diff --git a/Calorimeter/CaloDigiAlgs/CMakeLists.txt b/Calorimeter/CaloDigiAlgs/CMakeLists.txt index 42991aa03cc03af6e51ab161d36d1d61df1a7956..89d20eae8e67a52daa6a23b60825e06f43610ec3 100644 --- a/Calorimeter/CaloDigiAlgs/CMakeLists.txt +++ b/Calorimeter/CaloDigiAlgs/CMakeLists.txt @@ -9,7 +9,9 @@ atlas_subdir( CaloDigiAlgs ) atlas_add_component( CaloDigiAlgs src/*.cxx src/*.h src/components/*.cxx - LINK_LIBRARIES AthenaBaseComps Identifier StoreGateLib WaveRawEvent FaserCaloSimEvent WaveDigiToolsLib) + LINK_LIBRARIES AthenaBaseComps Identifier FaserCaloIdentifier + WaveformConditionsToolsLib StoreGateLib WaveRawEvent + FaserCaloSimEvent WaveDigiToolsLib) atlas_install_python_modules( python/*.py ) diff --git a/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py b/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py index ce45e6257885956f5edb6284780ff9756b51b9fc..793f73401b54c91724bdb6283fa4c6099811628c 100644 --- a/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py +++ b/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py @@ -6,6 +6,7 @@ from AthenaConfiguration.ComponentFactory import CompFactory from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from WaveformConditionsTools.WaveformCableMappingConfig import WaveformCableMappingCfg # One stop shopping for normal FASER data def CaloWaveformDigitizationCfg(flags): @@ -17,6 +18,8 @@ def CaloWaveformDigitizationCfg(flags): acc.merge(CaloWaveformDigiCfg(flags, "CaloWaveformDigiAlg")) acc.merge(CaloWaveformDigitizationOutputCfg(flags)) + acc.merge(WaveformCableMappingCfg(flags)) + return acc # Return configured digitization algorithm from SIM hits @@ -54,6 +57,8 @@ def CaloWaveformDigitizationOutputCfg(flags, **kwargs): ] acc.merge(OutputStreamCfg(flags, "RDO")) ostream = acc.getEventAlgo("OutputStreamRDO") - ostream.TakeItemsFromInput = True # Copies all data from input file to output + # ostream.TakeItemsFromInput = True # Copies all data from input file to output + # ostream.TakeItemsFromInput = False + # Try turning this off ostream.ItemList += ItemList return acc diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx index 1abfcf9f11ecf71c135723f51d799828205ea2be..3e10288eaa2e68f82f1c72be38fde04cb73c66fd 100644 --- a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx +++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx @@ -2,13 +2,15 @@ #include "Identifier/Identifier.h" -#include <vector> +#include "FaserCaloSimEvent/CaloHitIdHelper.h" + #include <map> #include <utility> CaloWaveformDigiAlg::CaloWaveformDigiAlg(const std::string& name, ISvcLocator* pSvcLocator) - : AthReentrantAlgorithm(name, pSvcLocator) { + : AthReentrantAlgorithm(name, pSvcLocator) +{ } @@ -18,7 +20,7 @@ CaloWaveformDigiAlg::initialize() { // Initalize tools ATH_CHECK( m_digiTool.retrieve() ); - + ATH_CHECK( m_mappingTool.retrieve() ); // Set key to read waveform from ATH_CHECK( m_caloHitContainerKey.initialize() ); @@ -26,19 +28,19 @@ CaloWaveformDigiAlg::initialize() { // Set key to write container ATH_CHECK( m_waveformContainerKey.initialize() ); - // Will eventually depend on the type of detector - // TODO: Vary time at which centre it? - // TODO: Change params compared to scint - // m_kernel = new TF1("PDF", " ROOT::Math::crystalball_pdf(x, -0.9, 10, 4, 900)", 0, 1200); - + // Set up helper + ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID")); + + // Create CB time kernel and pre-evaluate for number of samples m_kernel = new TF1("PDF", "[4] * ROOT::Math::crystalball_pdf(x, [0],[1],[2],[3])", 0, 1200); - //m_kernel->SetParameters(-0.25,10,4,900); m_kernel->SetParameter(0, m_CB_alpha); m_kernel->SetParameter(1, m_CB_n); m_kernel->SetParameter(2, m_CB_sigma); m_kernel->SetParameter(3, m_CB_mean); m_kernel->SetParameter(4, m_CB_norm); + // Pre-evaluate time kernel for each bin + m_timekernel = m_digiTool->evaluate_timekernel(m_kernel); return StatusCode::SUCCESS; } @@ -55,12 +57,10 @@ CaloWaveformDigiAlg::finalize() { StatusCode CaloWaveformDigiAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("Executing"); - - ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() - << " Event: " << ctx.eventID().event_number()); + ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() << " Event: " << ctx.eventID().event_number()); // Find the input HIT collection - SG::ReadHandle<CaloHitCollection> caloHitHandle(m_caloHitContainerKey, ctx); + SG::ReadHandle<CaloHitCollection> caloHitHandle(m_caloHitContainerKey, ctx); ATH_CHECK( caloHitHandle.isValid() ); ATH_MSG_DEBUG("Found ReadHandle for CaloHitCollection " << m_caloHitContainerKey); @@ -75,11 +75,67 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("CaloHitCollection found with zero length!"); return StatusCode::SUCCESS; } - - // Digitise the hits - CHECK( m_digiTool->digitise<CaloHitCollection>(caloHitHandle.ptr(), - waveformContainerHandle.ptr(), m_kernel, - std::pair<float, float>(m_base_mean, m_base_rms)) ); + + // Create structure to store pulse for each channel + std::map<Identifier, std::vector<uint16_t>> waveforms = m_digiTool->create_waveform_map(m_ecalID); + + for (const auto& tk : m_timekernel) { + std::map<unsigned int, float> counts; + + // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel) + for (const auto& hit : *caloHitHandle) { + counts[hit.identify()] += tk * hit.energyLoss(); + } + + // Subtract count from basleine and add result to correct waveform vector + for (const auto& c : counts) { + + unsigned int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms); + int value = baseline - c.second; + + if (value < 0) { + ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first); + value = 0; // Protect against scaling signal above baseline + } + + // Convert hit id to Identifier and store + Identifier id = CaloHitIdHelper::GetHelper()->getIdentifier(c.first); + waveforms[id].push_back(value); + } + } + + + // This is a bit of a hack to make sure all waveforms have + // at least baseline entries. Should really add this to the + // logic above + for (const auto& w : waveforms) { + if (w.second.size() > 0) continue; + + // Waveform was empty, fill with baseline + int channel = m_mappingTool->getChannelMapping(w.first); + ATH_MSG_DEBUG("Writing baseline into empty waveform in channel "<< channel); + int i = m_digiTool->nsamples(); + while(i--) { // Use while to avoid unused variable warning with for + int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms); + waveforms[w.first].push_back(baseline); + } + } + + //m_chrono->chronoStop("Digit"); + //m_chrono->chronoStart("Write"); + + // Loop over wavefrom vectors to make and store waveform + unsigned int nsamples = m_digiTool->nsamples(); + for (const auto& w : waveforms) { + RawWaveform* wfm = new RawWaveform(); + wfm->setWaveform(0, w.second); + wfm->setIdentifier(w.first); + wfm->setChannel(m_mappingTool->getChannelMapping(w.first)); + wfm->setSamples(nsamples); + waveformContainerHandle->push_back(wfm); + } + + //m_chrono->chronoStop("Write"); ATH_MSG_DEBUG("WaveformsHitContainer " << waveformContainerHandle.name() << "' filled with "<< waveformContainerHandle->size() <<" items"); diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h index f99d13b5565712045bcef7507fd04bca6bf0d07a..25111bc9655ae99d97e7ea56a98524102ce151f3 100644 --- a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h +++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h @@ -10,6 +10,7 @@ // Tool classes #include "WaveDigiTools/IWaveformDigitisationTool.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" // Handles #include "StoreGate/ReadHandleKey.h" @@ -19,11 +20,15 @@ #include "GaudiKernel/ServiceHandle.h" #include "GaudiKernel/ToolHandle.h" +// Helpers +#include "FaserCaloIdentifier/EcalID.h" + // ROOT #include "TF1.h" // STL #include <string> +#include <vector> class CaloWaveformDigiAlg : public AthReentrantAlgorithm { @@ -48,6 +53,8 @@ class CaloWaveformDigiAlg : public AthReentrantAlgorithm { CaloWaveformDigiAlg &operator=(const CaloWaveformDigiAlg&) = delete; //@} + /** @name Steerable pameters for crystal ball and baseline **/ + //@{ Gaudi::Property<double> m_CB_alpha {this, "CB_alpha", 0, "Alpha of the crystal ball function"}; Gaudi::Property<double> m_CB_n {this, "CB_n", 0, "n of the crystal ball function"}; Gaudi::Property<double> m_CB_mean {this, "CB_mean", 0, "Mean of the crystal ball function"}; @@ -56,10 +63,16 @@ class CaloWaveformDigiAlg : public AthReentrantAlgorithm { Gaudi::Property<double> m_base_mean {this, "base_mean", 0, "Mean of the baseline"}; Gaudi::Property<double> m_base_rms {this, "base_rms", 0, "RMS of the baseline"}; + //@} - /// Kernel PDF - TF1* m_kernel; + /** Kernel PDF and evaluated values **/ + //@{ + TF1* m_kernel; + std::vector<float> m_timekernel; + //@} + /// Detector ID helper + const EcalID* m_ecalID{nullptr}; /** * @name Digitisation tool @@ -67,6 +80,11 @@ class CaloWaveformDigiAlg : public AthReentrantAlgorithm { ToolHandle<IWaveformDigitisationTool> m_digiTool {this, "WaveformDigitisationTool", "WaveformDigitisationTool"}; + /** + * @name Mapping tool + */ + ToolHandle<IWaveformCableMappingTool> m_mappingTool + {this, "WaveformCableMappingTool", "WaveformCableMappingTool"}; /** * @name Input HITS using SG::ReadHandleKey @@ -89,4 +107,6 @@ class CaloWaveformDigiAlg : public AthReentrantAlgorithm { }; + + #endif // CALODIGIALGS_CALODIGIALG_H diff --git a/Calorimeter/FaserCaloSimEvent/CMakeLists.txt b/Calorimeter/FaserCaloSimEvent/CMakeLists.txt index 9777d4178e6e465f0f57de0c82173b0620fbe46a..2b034a3189207f186984b163c0c5a034bee7f956 100644 --- a/Calorimeter/FaserCaloSimEvent/CMakeLists.txt +++ b/Calorimeter/FaserCaloSimEvent/CMakeLists.txt @@ -18,11 +18,11 @@ atlas_add_library( FaserCaloSimEvent PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS} DEFINITIONS ${CLHEP_DEFINITIONS} LINK_LIBRARIES ${CLHEP_LIBRARIES} AthAllocators AthenaKernel CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests - PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} FaserCaloIdentifier ) + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} FaserCaloIdentifier Identifier) atlas_add_dictionary( FaserCaloSimEventDict FaserCaloSimEvent/CaloSimEventDict.h FaserCaloSimEvent/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthAllocators CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests FaserCaloIdentifier FaserCaloSimEvent ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthAllocators CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests FaserCaloIdentifier FaserCaloSimEvent Identifier) diff --git a/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHit.h b/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHit.h index b1e955f845d8f82ea8dcff82a6bbd5883f96b4b1..0b6fbe42ad0dd24cb4adbcb8072a65055d6ad2be 100644 --- a/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHit.h +++ b/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHit.h @@ -16,6 +16,8 @@ #include "CLHEP/Geometry/Point3D.h" #include "GeneratorObjects/HepMcParticleLink.h" +class Identifier; + class CaloHit { /////////////////////////////////////////////////////////////////// @@ -80,8 +82,13 @@ public: // Const methods: /////////////////////////////////////////////////////////////////// + // This returns the HitId, used in Geant. This is not the detector Identifier unsigned int identify() const; + // This is the detector readout Identifier (pmt Identifier) + // provided by ScintHitIdHelper::getIdentifier + Identifier getIdentifier() const; + // local start position of the energy deposit: HepGeom::Point3D<double> localStartPosition() const; diff --git a/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHitIdHelper.h b/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHitIdHelper.h index 5500649bc0c789aa5119503ee357839ee7e11b9e..e94581470c0fa76dddbec99c44aa93ba61484cdb 100644 --- a/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHitIdHelper.h +++ b/Calorimeter/FaserCaloSimEvent/FaserCaloSimEvent/CaloHitIdHelper.h @@ -23,6 +23,11 @@ // This class is singleton and static method and variable are used. #include "CxxUtils/checker_macros.h" + +#include "Identifier/Identifier.h" + +#include "FaserCaloIdentifier/EcalID.h" + ATLAS_NO_CHECK_FILE_THREAD_SAFETY; class CaloHitIdHelper : HitIdHelper { @@ -43,6 +48,8 @@ class CaloHitIdHelper : HitIdHelper { // Left or Right int getModule(const int& hid) const; + Identifier getIdentifier(const int& hid) const; + // // Info packing: int buildHitId(const int, const int) const; @@ -54,6 +61,9 @@ class CaloHitIdHelper : HitIdHelper { // // Initialize the helper, only called by the constructor void Initialize(); + + /// Detector ID helper + const EcalID* m_ecalID{nullptr}; }; #endif // CALOSIMEVENT_CALOHITIDHELPER diff --git a/Calorimeter/FaserCaloSimEvent/src/CaloHit.cxx b/Calorimeter/FaserCaloSimEvent/src/CaloHit.cxx index c8e18d7fc737268e388bf469be037ea43655a6d3..86e895117d03eb537127c68d74efef7b08bf8788 100644 --- a/Calorimeter/FaserCaloSimEvent/src/CaloHit.cxx +++ b/Calorimeter/FaserCaloSimEvent/src/CaloHit.cxx @@ -142,6 +142,10 @@ int CaloHit::getModule() const { return CaloHitIdHelper::GetHelper()->getModule(m_ID); } +Identifier CaloHit::getIdentifier() const { + return CaloHitIdHelper::GetHelper()->getIdentifier(m_ID); +} + void CaloHit::print() const { std::cout << "*** Calorimeter Hit" << std::endl; std::cout << " Station Number " << getRow() << std::endl; diff --git a/Calorimeter/FaserCaloSimEvent/src/CaloHitIdHelper.cxx b/Calorimeter/FaserCaloSimEvent/src/CaloHitIdHelper.cxx index eec88553dae53bc6e415b385494b32a7f83645ad..0e98fbd6aa3c1be718b049ab91e74ae92b682ed4 100644 --- a/Calorimeter/FaserCaloSimEvent/src/CaloHitIdHelper.cxx +++ b/Calorimeter/FaserCaloSimEvent/src/CaloHitIdHelper.cxx @@ -6,8 +6,6 @@ #include "FaserCaloSimEvent/CaloHitIdHelper.h" #include "StoreGate/StoreGateSvc.h" -#include "StoreGate/StoreGateSvc.h" -#include "FaserCaloIdentifier/EcalID.h" #include "G4Types.hh" #ifdef G4MULTITHREADED @@ -42,10 +40,9 @@ void CaloHitIdHelper::Initialize() { // determine whether hits were created with an SLHC dictionary // in which case eta module field is expanded. // Need to lock this thread-unsafe retrieval - const EcalID* pix; ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "CaloHitIdHelper"); if (detStore.retrieve().isSuccess()) { - if (detStore->retrieve(pix, "EcalID").isFailure()) { pix = 0; } + if (detStore->retrieve(m_ecalID, "EcalID").isFailure()) { m_ecalID = 0; } } InitializeField("Row", 0, 2); @@ -64,6 +61,14 @@ int CaloHitIdHelper::getModule(const int& hid) const return this->GetFieldValue("Module", hid); } +// identifier +Identifier CaloHitIdHelper::getIdentifier(const int& hid) const +{ + return m_ecalID->pmt_id(getRow(hid), getModule(hid), 0); + +} + + // // Info packing: int CaloHitIdHelper::buildHitId( const int row, diff --git a/Control/CalypsoConfiguration/python/DetectorConfigFlags.py b/Control/CalypsoConfiguration/python/DetectorConfigFlags.py index 763f1176951ecef9e3ecb3a57d7b8a607d449bbb..b2588ba84ef16b18af9084a029cdccbcbe8fae8f 100644 --- a/Control/CalypsoConfiguration/python/DetectorConfigFlags.py +++ b/Control/CalypsoConfiguration/python/DetectorConfigFlags.py @@ -7,15 +7,16 @@ from CalypsoConfiguration.AutoConfigFlags import DetDescrInfo, getDefaultDetecto allDetectors = [ - 'Emulsion', 'Veto', 'Trigger', 'Preshower', 'FaserSCT', 'Ecal', 'Dipole', + 'Emulsion', 'Veto', 'Trigger', 'Preshower', 'VetoNu', 'FaserSCT', 'Ecal', 'Dipole', 'Trench' ] allGroups = { 'Neutrino' : [ 'Emulsion' ], 'Tracker' : ['SCT'], - 'Scintillator' : ['Veto', 'Trigger', 'Preshower'], + 'Scintillator' : ['Veto', 'Trigger', 'Preshower', 'VetoNu'], 'FaserCalo' : ['Ecal'], - 'Magnet' : ['Dipole'] + 'Magnet' : ['Dipole'], + 'Cavern' : ['Trench'] } def createDetectorConfigFlags(): @@ -32,17 +33,20 @@ def createDetectorConfigFlags(): dcf.addFlag('Detector.GeometryVeto', False) dcf.addFlag('Detector.GeometryTrigger', False) dcf.addFlag('Detector.GeometryPreshower', False) + dcf.addFlag('Detector.GeometryVetoNu', False) dcf.addFlag('Detector.GeometryScintillator', lambda prevFlags : (prevFlags.Detector.GeometryVeto or prevFlags.Detector.GeometryTrigger or - prevFlags.Detector.GeometryPreshower)) + prevFlags.Detector.GeometryPreshower or + prevFlags.Detector.GeometryVetoNu)) dcf.addFlag('Detector.GeometryFaserSCT', False) dcf.addFlag('Detector.GeometryTracker', lambda prevFlags : prevFlags.Detector.GeometryFaserSCT ) dcf.addFlag('Detector.GeometryEcal', False) dcf.addFlag('Detector.GeometryFaserCalo', lambda prevFlags : prevFlags.Detector.GeometryEcal) - # Cavern (disabled by default) - # dcf.addFlag('Detector.GeometryCavern',False) + # Trench (disabled by default) + dcf.addFlag('Detector.GeometryTrench',False) + dcf.addFlag('Detector.GeometryFaserCavern', lambda prevFlags : (prevFlags.Detector.GeometryTrench )) # dcf.addFlag('Detector.GeometryFaser', lambda prevFlags : (prevFlags.Detector.GeometryDecayVolume or # prevFlags.Detector.GeometryScintillator or @@ -66,9 +70,11 @@ def createDetectorConfigFlags(): dcf.addFlag('Detector.EnableVeto', lambda prevFlags : 'Veto' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) dcf.addFlag('Detector.EnableTrigger', lambda prevFlags : 'Trigger' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) dcf.addFlag('Detector.EnablePreshower', lambda prevFlags : 'Preshower' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) + dcf.addFlag('Detector.EnableVetoNu', lambda prevFlags : 'VetoNu' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) dcf.addFlag('Detector.EnableScintillator',lambda prevFlags : (prevFlags.Detector.EnableVeto or prevFlags.Detector.EnableTrigger or - prevFlags.Detector.EnablePreshower)) + prevFlags.Detector.EnablePreshower or + prevFlags.Detector.EnableVetoNu)) dcf.addFlag('Detector.EnableFaserSCT', lambda prevFlags : 'FaserSCT' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) dcf.addFlag('Detector.EnableTracker', lambda prevFlags : prevFlags.Detector.EnableFaserSCT ) dcf.addFlag('Detector.EnableEcal', lambda prevFlags : 'Ecal' in getDefaultDetectors(prevFlags.GeoModel.FaserVersion)) @@ -86,8 +92,9 @@ def createDetectorConfigFlags(): dcf.addFlag('Detector.RecoTrigger', False) dcf.addFlag('Detector.RecoPreshower', False) dcf.addFlag('Detector.RecoEcal', False) + dcf.addFlag('Detector.RecoVetoNu', False) dcf.addFlag('Detector.RecoWaveform', lambda prevFlags : (prevFlags.Detector.RecoVeto or prevFlags.Detector.RecoTrigger or - prevFlags.Detector.RecoPreshower or prevFlags.Detector.RecoEcal)) + prevFlags.Detector.RecoPreshower or prevFlags.Detector.RecoVetoNu or prevFlags.Detector.RecoEcal)) dcf.addFlag('Detector.RecoFaserSCT', False) dcf.addFlag('Detector.RecoTracker', lambda prevFlags : (prevFlags.Detector.RecoFaserSCT)) diff --git a/Control/CalypsoConfiguration/python/testDetectorFlags.py b/Control/CalypsoConfiguration/python/testDetectorFlags.py index 9a555b4c637e5699aefd8516874286f1e127b51c..ab8c1e99cf6373e09dc02b94fd72d2560df187d2 100644 --- a/Control/CalypsoConfiguration/python/testDetectorFlags.py +++ b/Control/CalypsoConfiguration/python/testDetectorFlags.py @@ -54,11 +54,13 @@ assert flags.Detector.GeometryDipole assert not flags.Detector.EnableFaserSCT assert not flags.Detector.EnableEcal assert not flags.Detector.EnableVeto +assert not flags.Detector.EnableVetoNu assert not flags.Detector.EnableTrigger assert not flags.Detector.EnablePreshower assert not flags.Detector.GeometryFaserSCT assert not flags.Detector.GeometryEcal assert not flags.Detector.GeometryVeto +assert not flags.Detector.GeometryVetoNu assert not flags.Detector.GeometryTrigger assert not flags.Detector.GeometryPreshower print() diff --git a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py new file mode 100755 index 0000000000000000000000000000000000000000..0d94cf0c344b4010627ad63826c4d7aa4732a580 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Run with: +# ./faser_digi.py filepath runtype +# +# filepath - fully qualified path, including url if needed, to the input HITS file +# example: "root://eospublic.cern.ch//eos/experiment/faser/sim/GeniePilot/HITS/1/faser.150fbInv.1.001.HITS.pool.root" +# +# For MDC, we assume this is TI12 geometry +# +import sys +import time +import argparse + +a = time.time() + +parser = argparse.ArgumentParser(description="Run FASER reconstruction") + +parser.add_argument("file_path", + help="Fully qualified path of the raw input file") +parser.add_argument("run_type", nargs="?", default="", + help="Specify run type (if it can't be parsed from path)") +parser.add_argument("-t", "--tag", default="", + help="Specify digi tag (to append to output filename)") +parser.add_argument("-n", "--nevts", type=int, default=-1, + help="Specify number of events to process (default: all)") +parser.add_argument("-v", "--verbose", action='store_true', + help="Turn on DEBUG output") + +args = parser.parse_args() + +from pathlib import Path + +filepath=Path(args.file_path) + +# runtype has been provided +if len(args.run_type) > 0: + runtype=args.run_type + +else: + runtype = "TI12MC" + print(f"Assuming {runtype} geometry for MDC") + +print(f"Starting digitization of {filepath.name} with type {runtype}") +if args.nevts > 0: + print(f"Reconstructing {args.nevts} events by command-line option") + +# Start digitization + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from AthenaCommon.Constants import VERBOSE, INFO + +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags + +Configurable.configurableRun3Behavior = True + +# Flags for this job +ConfigFlags.Input.isMC = True # Needed to bypass autoconfig +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + +ConfigFlags.Input.ProjectName = "mc20" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Digitization.TruthOutput = True + +# TI12 old geometry +if runtype == "TI12OldMC": + ConfigFlags.GeoModel.FaserVersion = "FASER-01" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" + +# Testbeam setup +elif runtype == "TestBeamMC" : + ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00" + +# New TI12 geometry (ugh) +elif runtype == "TI12MC": + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" + +else: + print("Invalid run type found:", runtype) + print("Specify correct type or update list") + sys.exit(-1) + + +# Must use original input string here, as pathlib mangles double // in path names +ConfigFlags.Input.Files = [ args.file_path ] + +filestem = filepath.stem +# Remove any filetype modifier +if filestem[-5:] == "-HITS": + filestem = filestem[:-5] + +if len(args.tag) > 0: + print(f"{args.tag} in {filestem}?") + if args.tag in filestem: + print(f"Not adding tag {args.tag} to file {filestem}") + else: + filestem += f"-{args.tag}" + +ConfigFlags.Output.RDOFileName = f"{filestem}-RDO.root" + +# +# Play around with this? +# ConfigFlags.Concurrency.NumThreads = 2 +# ConfigFlags.Concurrency.NumConcurrentEvents = 2 +ConfigFlags.lock() + +# +# Configure components +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) + +# +# Needed, or move to MainServicesCfg? +from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +acc.merge(FaserGeometryCfg(ConfigFlags)) + +# Set up algorithms +from FaserSCT_Digitization.FaserSCT_DigitizationConfigNew import FaserSCT_DigitizationCfg +acc.merge(FaserSCT_DigitizationCfg(ConfigFlags)) + +from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +# ConfigFlags.dump() +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + +else: + acc.foreach_component("*").OutputLevel = INFO + +acc.foreach_component("*ClassID*").OutputLevel = INFO + +acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M" + +# Execute and finish +sc = acc.run(maxEvents=args.nevts) + +b = time.time() +from AthenaCommon.Logging import log +log.info(f"Finish execution in {b-a} seconds") + +sys.exit(not sc.isSuccess()) diff --git a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py new file mode 100755 index 0000000000000000000000000000000000000000..9c656de660dc7957aa222b691e50af457a870bf0 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Run with: +# ./faser_digi.py filepath runtype +# +# filepath - fully qualified path, including url if needed, to the input HITS file +# example: "root://eospublic.cern.ch//eos/experiment/faser/sim/GeniePilot/HITS/1/faser.150fbInv.1.001.HITS.pool.root" +# +# For MDC, we assume this is TI12 geometry +# +import sys +import time +import argparse + +a = time.time() + +parser = argparse.ArgumentParser(description="Run FASER reconstruction") + +parser.add_argument("dir_path", + help="Fully qualified path of the input file directory") +parser.add_argument("run_type", nargs="?", default="", + help="Specify run type (if it can't be parsed from path)") +parser.add_argument("-s", "--slice", type=int, default=0, + help="Specify file slice to produce") +parser.add_argument("-f", "--files", type=int, default=5, + help="Specify number of input files to run in one batch") +parser.add_argument("-t", "--tag", default="", + help="Specify digi tag (to append to output filename)") +parser.add_argument("-n", "--nevts", type=int, default=-1, + help="Specify number of events to process (default: all)") +parser.add_argument("-v", "--verbose", action='store_true', + help="Turn on DEBUG output") + +args = parser.parse_args() + +from pathlib import Path + +dirpath = Path(args.dir_path) + +# runtype has been provided +if len(args.run_type) > 0: + runtype=args.run_type + +else: + runtype = "TI12MC" + print(f"Assuming {runtype} geometry for MDC") + +# Does the directory exist? +if not (dirpath.exists() and dirpath.is_dir()): + print(f"Problem with directory {args.dir_path}") + sys.exit(1) + +# Create segment list +seglist = list(range(args.slice*args.files, (args.slice+1)*args.files)) + +# Now build file list +filelist = [] +dirlist = list(dirpath.glob('FaserMC-*-HITS.root')) +if len(dirlist) == 0: + print(f"No HITS file found in directory {args.dir_path}") + sys.exit(1) + +for seg in seglist: + # Assume these are in numerical order from 0 + if seg >= len(dirlist): + print(f"Requested file segment {seg} but only {len(dirlist)} files found") + break + filelist.append(dirlist[seg]) + +if len(filelist) == 0: + # Asked for range that doesn't exist + print(f"No files found for slice {args.slice} with Nfiles={args.files}") + sys.exit(1) + +# Figure out the file pattern for the output +stem = filelist[0].stem +spl = stem.split('-') +short = spl[1] +run = spl[2] +seglo = int(spl[3]) +# Can be multiple tags +tagstr = '' +for tag in spl[4:]: + if tag == "HITS": break + if len(tagstr) > 0: + tagstr += "-" + tagstr += tag + +# Also find the largest file number +stem = filelist[-1].stem +spl = stem.split('-') +seghi = int(spl[3]) + +# Build output filename +if seglo == 0 and (seghi+1) == len(dirlist): # Full run + outfile = f"FaserMC-{short}-{run}" +elif seglo == seghi: # Single segment + outfile = f"FaserMC-{short}-{run}-{seglo:05}" +else: + outfile = f"FaserMC-{short}-{run}-{seglo:05}-{seghi:05}" + +# Add existing tag +if len(tagstr) > 0: + outfile += f"-{tagstr}" + +# Was a tag requested? +if len(args.tag) > 0: + if args.tag in tagstr: + print(f"Not adding tag {args.tag} to file {filelist[0]}") + else: + outfile += f"-{args.tag}" + +# Finish output file +outfile += "-RDO.root" + +print(f"Found files from {seglo} to {seghi}") +print(f"Starting digitization of outfile {outfile} with type {runtype}") +if args.nevts > 0: + print(f"Reconstructing {args.nevts} events by command-line option") + +# Start digitization + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from AthenaCommon.Constants import VERBOSE, INFO + +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags + +Configurable.configurableRun3Behavior = True + +# Flags for this job +ConfigFlags.Input.isMC = True # Needed to bypass autoconfig +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + +ConfigFlags.Input.ProjectName = "mc20" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Digitization.TruthOutput = True + +# TI12 old geometry +if runtype == "TI12OldMC": + ConfigFlags.GeoModel.FaserVersion = "FASER-01" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" + +# Testbeam setup +elif runtype == "TestBeamMC" : + ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00" + +# New TI12 geometry (ugh) +elif runtype == "TI12MC": + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" + +else: + print("Invalid run type found:", runtype) + print("Specify correct type or update list") + sys.exit(-1) + + +# Try just passing the filelist +ConfigFlags.Input.Files = [str(file) for file in filelist] +ConfigFlags.Output.RDOFileName = outfile + +# +# Play around with this? +# ConfigFlags.Concurrency.NumThreads = 2 +# ConfigFlags.Concurrency.NumConcurrentEvents = 2 +ConfigFlags.lock() + +# +# Configure components +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) + +# +# Needed, or move to MainServicesCfg? +from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +acc.merge(FaserGeometryCfg(ConfigFlags)) + +# Set up algorithms +from FaserSCT_Digitization.FaserSCT_DigitizationConfigNew import FaserSCT_DigitizationCfg +acc.merge(FaserSCT_DigitizationCfg(ConfigFlags)) + +from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +# ConfigFlags.dump() +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + +else: + acc.foreach_component("*").OutputLevel = INFO + +acc.foreach_component("*ClassID*").OutputLevel = INFO + +acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M" + +# Execute and finish +sc = acc.run(maxEvents=args.nevts) + +b = time.time() +from AthenaCommon.Logging import log +log.info(f"Finish execution in {b-a} seconds") + +sys.exit(not sc.isSuccess()) diff --git a/Control/CalypsoExample/Digitization/scripts/faser_digi.py b/Control/CalypsoExample/Digitization/scripts/faser_digi.py index 5ef818999634d592b21142b88ad2cee5c1a324f1..91de9cad754ec1bb739a3f689f27911139e48882 100755 --- a/Control/CalypsoExample/Digitization/scripts/faser_digi.py +++ b/Control/CalypsoExample/Digitization/scripts/faser_digi.py @@ -82,7 +82,7 @@ elif runtype == "TestBeamMC" : # New TI12 geometry (ugh) elif runtype == "TI12MC": - ConfigFlags.GeoModel.FaserVersion = "FASERNU-02" + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" else: diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh new file mode 100755 index 0000000000000000000000000000000000000000..a8e1b9059aa32d4e91bafe923797d262aa2b84ca --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_digi.sh filepath [release_directory] [working_directory] +# +# filepath - full file name (with path) +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches gen/g???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +file_path=${1} +release_directory=${2} +working_directory=${3} +# +# Set defaults if arguments aren't provided +if [ -z "$file_path" ] +then + echo "No file specified!" + echo "Usage: submit_faserMDC_digi.sh file [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +starting_directory=`pwd` +# +# Now extract the run number and file stem +# +# First, get the filename +file_name=$(basename "$file_path") +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read file_stem ext <<< "$file_name" +# +# Finally extract the run number +IFS='-' +# Read the split words into an array based on delimiter +read faser short run_number segment <<< "$file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Make output directory if needed +output_directory="$working_directory/$run_number" +mkdir -p "$output_directory" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/$file_stem.log" +echo `date` - $HOSTNAME +echo "File: $file_name" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +# asetup +# source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# +# Try to find a release tag +cd calypso +recotag=`git describe` +if [[ "$recotag" == "reco/r"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" +fi +if [[ "$recotag" == "digi/d"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found digi tag: $tag" +fi +if [[ "$recotag" == "sim/s"???? ]]; then + tag=`echo "$recotag" | cut -c 5-10` + echo "Found sim tag: $tag" +fi +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "$file_stem" ]]; then + echo "Directory $file_stem already exists" +else + mkdir "$file_stem" +fi +cd "$file_stem" +# +# Run job +if [[ -z "$tag" ]]; then + faserMDC_digi.py "$file_path" +else + faserMDC_digi.py "--tag=$tag" "$file_path" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi_merge.sh b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi_merge.sh new file mode 100755 index 0000000000000000000000000000000000000000..3c500905965fc48e7242838f284226516c03b8f2 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi_merge.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_digi_merge.sh dirpath slice nfiles [release_directory] [working_directory] +# +# dirpath - full directory path to HITS files +# slice - ordinal output file number +# nfiles - number of HITS files to process per slice +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches sim/s???? or digi/d???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +dir_path=${1} +slice=${2} +nfiles=${3} +release_directory=${4} +working_directory=${5} +# +# Set defaults if arguments aren't provided +if [ -z "$dir_path" ] +then + echo "No directory specified!" + echo "Usage: submit_faserMDC_digi_merge.sh directory slice nfiles [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$slice" ] +then + echo "Slice number not specified!" + echo "Usage: submit_faserMDC_digi_merge.sh directory slice nfiles [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$nfiles" ] +then + echo "Files per slice not specified!" + echo "Usage: submit_faserMDC_digi_merge.sh directory slice nfiles [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +starting_directory=`pwd` +# +# Now extract the run number and file stem +# +# First, get an example filename +file_name=`ls -1 $dir_path | head -1` +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read file_stem ext <<< "$file_name" +# +# Finally extract the run number +IFS='-' +# Read the split words into an array based on delimiter +read faser short run_number segment <<< "$file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Make output directory if needed +output_directory="$working_directory/$run_number" +mkdir -p "$output_directory" +# +# Need to make up an output name +file_stem="$faser-$short-$run_number-RDO-merge-$slice" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/$file_stem.log" +echo `date` - $HOSTNAME +echo "Directory: $dir_path" +echo "Slice: $slice" +echo "NFiles: $nfiles" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +echo "job: $file_stem" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +# asetup +# source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# +# Try to find a release tag +cd calypso +recotag=`git describe` +if [[ "$recotag" == "reco/r"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" +fi +if [[ "$recotag" == "digi/d"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found digi tag: $tag" +fi +if [[ "$recotag" == "sim/s"???? ]]; then + tag=`echo "$recotag" | cut -c 5-10` + echo "Found sim tag: $tag" +fi +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "$file_stem" ]]; then + echo "Directory $file_stem already exists" +else + mkdir "$file_stem" +fi +cd "$file_stem" +# +# Run job +if [[ -z "$tag" ]]; then + faserMDC_digi_merge.py --slice $slice --files $nfiles $dir_path +else + faserMDC_digi_merge.py --slice $slice --files $nfiles --tag $tag $dir_path +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" diff --git a/Control/CalypsoExample/Generation/CMakeLists.txt b/Control/CalypsoExample/Generation/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ffb523fe90a093c43dc84e121ae7792078e8047 --- /dev/null +++ b/Control/CalypsoExample/Generation/CMakeLists.txt @@ -0,0 +1,12 @@ +################################################################################ +# Package: Generation +################################################################################ + +# Declare the package name: +atlas_subdir( Generation ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( scripts/*.sh scripts/*.py ) + + diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_100MeV_1Em5-110001.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_100MeV_1Em5-110001.json new file mode 100644 index 0000000000000000000000000000000000000000..782dda26b0ebb02c6553cfeed61daf0bfd59c563 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_100MeV_1Em5-110001.json @@ -0,0 +1,14 @@ +{ + "run": 110001, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/DarkPhoton/npy/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy", + "short": "MDC_FS_Aee_100MeV_1Em5", + "tag": null, + "pid": [ + -11, + 11 + ], + "mass": 100.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em4-110003.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em4-110003.json new file mode 100644 index 0000000000000000000000000000000000000000..41326579b17bf5befc48f03423749770b12e8a68 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em4-110003.json @@ -0,0 +1,14 @@ +{ + "run": 110003, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/DarkPhoton/npy/events_14TeV_m0.01GeV_c0.0001to_11_-11.npy", + "short": "MDC_FS_Aee_10MeV_1Em4", + "tag": null, + "pid": [ + -11, + 11 + ], + "mass": 10.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em5-110002.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em5-110002.json new file mode 100644 index 0000000000000000000000000000000000000000..112a4e79f625481e9524b6ac04d939d618a3171f --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Aee_10MeV_1Em5-110002.json @@ -0,0 +1,14 @@ +{ + "run": 110002, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/DarkPhoton/npy/events_14TeV_m0.01GeV_c1e-05to_11_-11.npy", + "short": "MDC_FS_Aee_10MeV_1Em5", + "tag": null, + "pid": [ + -11, + 11 + ], + "mass": 10.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_100MeV_1Em4-110007.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_100MeV_1Em4-110007.json new file mode 100644 index 0000000000000000000000000000000000000000..044d1840123099f44b7f208f0a0d95e52717ff2e --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_100MeV_1Em4-110007.json @@ -0,0 +1,14 @@ +{ + "run": 110007, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/ALP-W/npy/events_14TeV_m0.1GeV_c0.0001to_22_22.npy", + "short": "MDC_FS_Alp_100MeV_1Em4", + "tag": null, + "pid": [ + 22, + 22 + ], + "mass": 100.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em2-110006.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em2-110006.json new file mode 100644 index 0000000000000000000000000000000000000000..7d4d8496ec2270679c8e41f082083057723dfaa9 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em2-110006.json @@ -0,0 +1,14 @@ +{ + "run": 110006, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/ALP-W/npy/events_14TeV_m0.01GeV_c0.01to_22_22.npy", + "short": "MDC_FS_Alp_10MeV_1Em2", + "tag": null, + "pid": [ + 22, + 22 + ], + "mass": 10.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em4-110005.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em4-110005.json new file mode 100644 index 0000000000000000000000000000000000000000..6bdc7701c5c18ea683f4311d90ada6440a94c693 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Alp_10MeV_1Em4-110005.json @@ -0,0 +1,14 @@ +{ + "run": 110005, + "segment": 0, + "file_length": 100, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/ALP-W/npy/events_14TeV_m0.01GeV_c0.0001to_22_22.npy", + "short": "MDC_FS_Alp_10MeV_1Em4", + "tag": null, + "pid": [ + 22, + 22 + ], + "mass": 10.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json new file mode 100644 index 0000000000000000000000000000000000000000..998137d88277e5a4dd579e8dac02382ca525e9bf --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004.json @@ -0,0 +1,14 @@ +{ + "run": 110004, + "segment": 0, + "file_length": 1000, + "model": "DarkPhoton", + "model_path": "/eos/experiment/faser/gen/ForeseeMDC/DarkPhoton/npy/events_14TeV_m0.3162GeV_c2e-06to_13_-13.npy", + "short": "MDC_FS_Amm_316MeV_2Em6", + "tag": null, + "pid": [ + -13, + 13 + ], + "mass": 316.2 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_100GeV-101103.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_100GeV-101103.json new file mode 100644 index 0000000000000000000000000000000000000000..5d894348c01aabba890fadcc2e5ab29b21feb166 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_100GeV-101103.json @@ -0,0 +1,13 @@ +{ + "file_length": 1000, + "mass": 0.511, + "maxE": 100.0, + "minE": 100.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 101103, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_elec_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json new file mode 100644 index 0000000000000000000000000000000000000000..4ced9578a31bc74d2b04056600a5f4d988ceeb5a --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_logE-101101.json @@ -0,0 +1,13 @@ +{ + "file_length": 500, + "mass": 0.511, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 101101, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_elec_logE", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json new file mode 100644 index 0000000000000000000000000000000000000000..9fd3bac93171aacaaa85380e825cc0a75e2da340 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json @@ -0,0 +1,13 @@ +{ + "file_length": 1000, + "mass": 0.0, + "maxE": 100.0, + "minE": 100.0, + "pid": 22, + "radius": -100.0, + "run": 102201, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_gam_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_100GeV-101303.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_100GeV-101303.json new file mode 100644 index 0000000000000000000000000000000000000000..f2bb15dbf45d165c53fced996db34c028b91c60b --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_100GeV-101303.json @@ -0,0 +1,13 @@ +{ + "file_length": 2000, + "mass": 105.66, + "maxE": 100.0, + "minE": 100.0, + "pid": [-13, 13], + "radius": -100.0, + "run": 101303, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_muon_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101302.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101302.json new file mode 100644 index 0000000000000000000000000000000000000000..76ba19e1146b9107c3365cc5c5dd867ff26e6c94 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101302.json @@ -0,0 +1,13 @@ +{ + "file_length": 2000, + "mass": 105.66, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-13, 13], + "radius": -100.0, + "run": 101302, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_muon_fasernu_logE", + "zpos": -4000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_logE-101301.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_logE-101301.json new file mode 100644 index 0000000000000000000000000000000000000000..c462453d04dfef9a93b310c8d782574efb687d9b --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_logE-101301.json @@ -0,0 +1,13 @@ +{ + "file_length": 2000, + "mass": 105.66, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-13, 13], + "radius": -100.0, + "run": 101301, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_muon_logE", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json new file mode 100644 index 0000000000000000000000000000000000000000..d6fa243102ae6edd11144bf3297992a014f23cbc --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_pion_100GeV-121101.json @@ -0,0 +1,13 @@ +{ + "file_length": 1000, + "mass": 139.6, + "maxE": 100.0, + "minE": 100.0, + "pid": [211, -211], + "radius": -100.0, + "run": 121101, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_pion_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/python/__init__.py b/Control/CalypsoExample/Generation/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f078213647f851a7dfbd2d5ca63157209ff91b22 --- /dev/null +++ b/Control/CalypsoExample/Generation/python/__init__.py @@ -0,0 +1,2 @@ +# Generation + diff --git a/Control/CalypsoExample/Generation/python/faserMDC_parser.py b/Control/CalypsoExample/Generation/python/faserMDC_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..583b04199c9d7799215a6cd79539865141a4347a --- /dev/null +++ b/Control/CalypsoExample/Generation/python/faserMDC_parser.py @@ -0,0 +1,172 @@ +# +# Copyright (C) 2022 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2022 CERN for the benefit of the FASER collaboration +# +# Parser function for MDC particle gun samples +# +def faserMDC_pgparser(): + + import sys + import json + import argparse + + parser = argparse.ArgumentParser(description="Run FASER ParticleGun Simulation") + + parser.add_argument("--conf", action='append', + help="Specify configuration file with default values") + parser.add_argument("--run", default=123456, type=int, + help="Run number to generate") + parser.add_argument("--segment", default=00000, type=int, + help="Segment number to generate") + parser.add_argument("--file_length", default=1000, type=int, + help="Total events per file segement") + + parser.add_argument("--short", default="MDCPG_logE", + help="Short description for filename") + parser.add_argument("--tag", default=None, + help="Generator tag (g0000)") + + parser.add_argument("--pid", default=[-13, 13], type=int, nargs='*', + help="Specify PDG ID of particle (note plus/minus different) or list (e.g.: --pid -13 13)") + parser.add_argument("--mass", default=105.66, type=float, + help="Specify particle mass (in MeV)") + parser.add_argument("--radius", default=100., type=float, + help="Specify radius (in mm)") + parser.add_argument("--angle", default=0.015, type=float, + help="Specify angular width (in Rad)") + parser.add_argument("--zpos", default=None, type=float, + help="Specify z position of particles (in mm) (helpful to avoid FASERnu)") + + parser.add_argument("--sampler", default="log", + help="Specify energy sampling (log, lin, const)") + parser.add_argument("--minE", default=10., type=float, + help="Minimum energy in GeV (for log or lin sampler)") + parser.add_argument("--maxE", default=1000., type=float, + help="Maximum energy (or constant) in GeV") + + parser.add_argument("--nevts", default=-1, type=int, + help="Number of events to generate (for debugging)") + parser.add_argument("--dump", action='store_true', + help="Write out full configuration") + parser.add_argument("--noexec", action='store_true', + help="Exit after parsing configuration (no execution)") + + pg_args = parser.parse_args() + + # Get defaults + if pg_args.conf is not None: + for conf_fname in pg_args.conf: + with open(conf_fname, 'r') as f: + parser.set_defaults(**json.load(f)) + + # Reload arguments to override config file with command line + pg_args = parser.parse_args() + + # Print out configuration if requested + if pg_args.dump: + tmp_args = vars(pg_args).copy() + del tmp_args['dump'] # Don't dump the dump value + del tmp_args['conf'] # Don't dump the conf file name either + del tmp_args['nevts'] # Debugging, not part of configuration + del tmp_args['noexec'] # Debugging, not part of configuration + print("Configuration:") + print(json.dumps(tmp_args, indent=4, sort_keys=False)) + + if pg_args.noexec: + sys.exit(0) + + # + # Add some derived quantities + # + + # Create the file name also (could add gentag here) + pg_args.outfile = f"FaserMC-{pg_args.short}-{pg_args.run:06}-{pg_args.segment:05}" + + if pg_args.tag: + pg_args.outfile += f"-{pg_args.tag}" + + pg_args.outfile += "-HITS.root" + + return pg_args + +# All done + +# +# Parser function for MDC Foresee samples +# +def faserMDC_fsparser(): + + import sys + import json + import argparse + + parser = argparse.ArgumentParser(description="Run FASER ParticleGun Simulation") + + parser.add_argument("--conf", action='append', + help="Specify configuration file with default values") + parser.add_argument("--run", default=123456, type=int, + help="Run number to generate") + parser.add_argument("--segment", default=00000, type=int, + help="Segment number to generate") + parser.add_argument("--file_length", default=1000, type=int, + help="Total events per file segement") + + parser.add_argument("--model", help="Model name") + parser.add_argument("--model_path", help="Path to model phase space file") + + parser.add_argument("--short", default="MDCPG_logE", + help="Short description for filename") + parser.add_argument("--tag", default=None, + help="Generator tag (g0000)") + + parser.add_argument("--pid", default=[-13, 13], type=int, nargs=2, + help="Specify PDG ID of daughter particles") + parser.add_argument("--mass", default=105.66, type=float, + help="Specify particle mass (in MeV)") + + parser.add_argument("--nevts", default=-1, type=int, + help="Number of events to generate (for debugging)") + parser.add_argument("--dump", action='store_true', + help="Write out full configuration") + parser.add_argument("--noexec", action='store_true', + help="Exit after parsing configuration (no execution)") + + fs_args = parser.parse_args() + + # Get defaults + if fs_args.conf is not None: + for conf_fname in fs_args.conf: + with open(conf_fname, 'r') as f: + parser.set_defaults(**json.load(f)) + + # Reload arguments to override config file with command line + fs_args = parser.parse_args() + + # Print out configuration if requested + if fs_args.dump: + tmp_args = vars(fs_args).copy() + del tmp_args['dump'] # Don't dump the dump value + del tmp_args['conf'] # Don't dump the conf file name either + del tmp_args['nevts'] # Debugging, not part of configuration + del tmp_args['noexec'] # Debugging, not part of configuration + print("Configuration:") + print(json.dumps(tmp_args, indent=4, sort_keys=False)) + + if fs_args.noexec: + sys.exit(0) + + # + # Add some derived quantities + # + + # Create the file name also (could add gentag here) + fs_args.outfile = f"FaserMC-{fs_args.short}-{fs_args.run:06}-{fs_args.segment:05}" + + if fs_args.tag: + fs_args.outfile += f"-{fs_args.tag}" + + fs_args.outfile += "-HITS.root" + + return fs_args + +# All done diff --git a/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py b/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py new file mode 100755 index 0000000000000000000000000000000000000000..b48bbf861ed4bbac6e0a6fb6cc9fd95da5049138 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/faserMDC_foresee.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +""" +Produce particle gun samples +Derived from G4FaserAlgConfigNew + +Usage: +faserMDC_particlegun.py --conf=<config_file> + +Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +""" + +if __name__ == '__main__': + + import sys + import time + a = time.time() +# +# Parse command-line options +# + from Generation.faserMDC_parser import faserMDC_fsparser + args = faserMDC_fsparser() +# +# Figure out events to run and skip +# + nskipped = args.segment*args.file_length + if args.nevts > 0: + nevents = args.nevts + else: + nevents = args.file_length +# +# Print out what we are doing +# + print(f"Generating {nevents} in file {args.outfile}") +# +# Set up logging and config behaviour +# + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, VERBOSE + from AthenaCommon.Configurable import Configurable + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = 1 +# +# Import and set config flags +# + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Exec.MaxEvents = nevents + ConfigFlags.Exec.SkipEvents = nskipped + from AthenaConfiguration.Enums import ProductionStep + ConfigFlags.Common.ProductionStep = ProductionStep.Simulation +# +# All these must be specified to avoid auto-configuration +# + ConfigFlags.Input.RunNumber = [args.run] #Isn't updating - todo: investigate + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [(args.segment+1)] + ConfigFlags.Input.isMC = True +# +# Output file name +# + ConfigFlags.Output.HITSFileName = args.outfile +# +# Sim ConfigFlags +# + ConfigFlags.Sim.Layout = "FASER" + ConfigFlags.Sim.PhysicsList = "FTFP_BERT" + ConfigFlags.Sim.ReleaseGeoModel = False + ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file + + # Property bag for particle gun keyword:argument pairs + # Apply +12mm vertical shift (to get to FASER CL) + # And 150 uRad crossing angle (Jamie claims this is half-angle) + ConfigFlags.addFlag("Sim.Gun",{"Generator" : "Foresee"}) + ConfigFlags.addFlag("Sim.Beam.xangle", 0) # Potential beam crossing angles + ConfigFlags.addFlag("Sim.Beam.yangle", -0.000150) + ConfigFlags.addFlag("Sim.Beam.xshift", 0) # Potential beam shift + ConfigFlags.addFlag("Sim.Beam.yshift", 12.) + + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up + ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # To avoid autoconfig + ConfigFlags.GeoModel.Align.Dynamic = False + +# +# Preset particle gun parameters +# + from math import atan + from AthenaCommon.SystemOfUnits import GeV, TeV, cm, m + from AthenaCommon.PhysicalConstants import pi + + print(f"Using pid: {args.pid}") + if len(args.pid) != 2: + print(f"Need 2 particles defined for Foresee generator!") + sys.exit(1) + + # String seeding doesn't work for numpy, make integer by hashing instead + import hashlib + + # Note the mother mass here is in GeV for some reason + import ParticleGun as PG + ConfigFlags.Sim.Gun = { + "Generator" : "Foresee", + "model_path" : args.model_path, + "model_name" : args.model, + "daughter1_pid" : args.pid[0], + "daughter2_pid" : args.pid[1], + "mother_mass" : args.mass/1000., + "randomSeed" : int(hashlib.sha512(args.outfile.encode()).hexdigest(), 16) } + + # Note the nominal z position is -3.75m, which is a bit upstream of vetoNu + # The decay volume is approximately -1.5 - 0 m, so -1m is safely inside + # To get all the material currently defined in front, specify -5m. + # Note zpos is in mm! + #if args.zpos: + # ConfigFlags.Sim.Gun["z"] = args.zpos + + doShiftLOS = (ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle or + ConfigFlags.Sim.Beam.xshift or ConfigFlags.Sim.Beam.yshift) + + if doShiftLOS: + pgConfig = ConfigFlags.Sim.Gun + pgConfig["McEventKey"] = "BeamTruthEvent_ATLASCoord" + ConfigFlags.Sim.Gun = pgConfig + +# +# MDC geometry configuration +# + detectors = ['Veto', 'VetoNu', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion'] +# +# Setup detector flags +# + from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList + setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True) +# +# Finalize flags +# + ConfigFlags.lock() +# +# Initialize a new component accumulator +# + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) +# +# Configure the particle gun as requested, or using defaults +# + +# +# Particle gun generators - the generator, energy, angle, particle type, position, etc can be modified by passing keyword arguments +# + from FaserParticleGun.FaserParticleGunConfig import FaserParticleGunCfg + cfg.merge(FaserParticleGunCfg(ConfigFlags)) + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) + +# +# Output file +# + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + cfg.merge(PoolWriteCfg(ConfigFlags)) + +# +# Shift LOS +# + + if doShiftLOS: + import McParticleEvent.Pythonizations + from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg + + cfg.merge(ShiftLOSCfg(ConfigFlags, + xcross = ConfigFlags.Sim.Beam.xangle, + ycross = ConfigFlags.Sim.Beam.yangle, + xshift = ConfigFlags.Sim.Beam.xshift, + yshift = ConfigFlags.Sim.Beam.yshift)) + + +# +# Add the G4FaserAlg +# + from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg + cfg.merge(G4FaserAlgCfg(ConfigFlags)) +# +# Dump config +# + from AthenaConfiguration.ComponentFactory import CompFactory + cfg.addEventAlgo(CompFactory.JobOptsDumperAlg(FileName="G4FaserTestConfig.txt")) + cfg.getService("StoreGateSvc").Dump = True + cfg.getService("ConditionStore").Dump = True + cfg.printConfig(withDetails=True, summariseProps = False) # gags on ParticleGun if summariseProps = True? + + ConfigFlags.dump() + #f = open("test.pkl","wb") + #cfg.store(f) + #f.close() +# +# Execute and finish +# + + #cfg.foreach_component("*").OutputLevel = "INFO" # Use warning for production + + sc = cfg.run() + + b = time.time() + log.info("Run G4FaserAlg in " + str(b-a) + " seconds") +# +# Success should be 0 +# + sys.exit(not sc.isSuccess()) + diff --git a/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py b/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py new file mode 100755 index 0000000000000000000000000000000000000000..20970fdf37f5fb28f102949e5ef35cd1372f193c --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/faserMDC_particlegun.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python +""" +Produce particle gun samples +Derived from G4FaserAlgConfigNew + +Usage: +faserMDC_particlegun.py --conf=<config_file> + +Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +""" + +if __name__ == '__main__': + + import sys + import time + a = time.time() +# +# Parse command-line options +# + from Generation.faserMDC_parser import faserMDC_pgparser + args = faserMDC_pgparser() +# +# Figure out events to run and skip +# + nskipped = args.segment*args.file_length + if args.nevts > 0: + nevents = args.nevts + else: + nevents = args.file_length +# +# Print out what we are doing +# + print(f"Generating {nevents} in file {args.outfile}") +# +# Set up logging and config behaviour +# + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, VERBOSE + from AthenaCommon.Configurable import Configurable + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = 1 +# +# Import and set config flags +# + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Exec.MaxEvents = nevents + ConfigFlags.Exec.SkipEvents = nskipped + from AthenaConfiguration.Enums import ProductionStep + ConfigFlags.Common.ProductionStep = ProductionStep.Simulation +# +# All these must be specified to avoid auto-configuration +# + ConfigFlags.Input.RunNumber = [args.run] #Isn't updating - todo: investigate + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [(args.segment+1)] + ConfigFlags.Input.isMC = True +# +# Output file name +# + ConfigFlags.Output.HITSFileName = args.outfile +# +# Sim ConfigFlags +# + ConfigFlags.Sim.Layout = "FASER" + ConfigFlags.Sim.PhysicsList = "FTFP_BERT" + ConfigFlags.Sim.ReleaseGeoModel = False + ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file + ConfigFlags.addFlag("Sim.Gun",{"Generator" : "SingleParticle"}) # Property bag for particle gun keyword:argument pairs + ConfigFlags.addFlag("Sim.Beam.xangle", 0) # Potential beam crossing angles + ConfigFlags.addFlag("Sim.Beam.yangle", 0) + ConfigFlags.addFlag("Sim.Beam.xshift", 0) # Potential beam shift + ConfigFlags.addFlag("Sim.Beam.yshift", 0) + + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up + ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # To avoid autoconfig + ConfigFlags.GeoModel.Align.Dynamic = False + +# +# Preset particle gun parameters +# + import ParticleGun as PG + from AthenaCommon.SystemOfUnits import GeV, TeV, cm, m + from AthenaCommon.PhysicalConstants import pi + + if isinstance(args.pid, list): + # Note args.pid is a list, must make this a set for ParticleGun + pidarg = set(args.pid) + else: + # Just pass a single value + pidarg = args.pid + + print(f"Using pid: {args.pid} => {pidarg}") + + # Create the simgun dictionary + # Negative radius gives uniform sampling + # Positive radius gives Gaussian sampling + sg_dict = { + "Generator" : "SingleParticle", + "pid" : pidarg, "mass" : args.mass, + "theta" : PG.GaussianSampler(0, args.angle, oneside = True), + "phi" : [0, 2*pi], "radius" : args.radius, + "randomSeed" : args.outfile + } + + # Note the nominal z position is -3.75m, which is a bit upstream of vetoNu + # The decay volume is approximately -1.5 - 0 m, so -1m is safely inside + # To get all the material currently defined in front, specify -5m. + # Note zpos is in mm! + if args.zpos: + sg_dict["z"] = args.zpos + + # Determine energy sampling + if args.sampler == "lin": + sg_dict["energy"] = PG.UniformSampler(args.minE*GeV, args.maxE*GeV) + elif args.sampler == "log": + sg_dict["energy"] = PG.LogSampler(args.minE*GeV, args.maxE*GeV) + elif args.sampler == "const": + sg_dict["energy"] = PG.ConstSampler(args.maxE*GeV) + else: + print(f"Sampler {args.sampler} not known!") + sys.exit(1) + + # Pass this in one go to ConfigFlags + ConfigFlags.Sim.Gun = sg_dict + + doShiftLOS = (ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle or + ConfigFlags.Sim.Beam.xshift or ConfigFlags.Sim.Beam.yshift) + + if doShiftLOS: + pgConfig = ConfigFlags.Sim.Gun + pgConfig["McEventKey"] = "BeamTruthEvent_ATLASCoord" + ConfigFlags.Sim.Gun = pgConfig + +# +# MDC geometry configuration +# + detectors = ['Veto', 'VetoNu', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion'] +# +# Setup detector flags +# + from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList + setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True) +# +# Finalize flags +# + ConfigFlags.lock() +# +# Initialize a new component accumulator +# + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) +# +# Configure the particle gun as requested, or using defaults +# + +# +# Particle gun generators - the generator, energy, angle, particle type, position, etc can be modified by passing keyword arguments +# + from FaserParticleGun.FaserParticleGunConfig import FaserParticleGunCfg + cfg.merge(FaserParticleGunCfg(ConfigFlags)) + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) + +# +# Output file +# + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + cfg.merge(PoolWriteCfg(ConfigFlags)) + +# +# Shift LOS +# + + if doShiftLOS: + import McParticleEvent.Pythonizations + from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg + + cfg.merge(ShiftLOSCfg(ConfigFlags, + xcross = ConfigFlags.Sim.Beam.xangle, + ycross = ConfigFlags.Sim.Beam.yangle, + xshift = ConfigFlags.Sim.Beam.xshift, + yshift = ConfigFlags.Sim.Beam.yshift)) + + +# +# Add the G4FaserAlg +# + from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg + cfg.merge(G4FaserAlgCfg(ConfigFlags)) +# +# Dump config +# + from AthenaConfiguration.ComponentFactory import CompFactory + cfg.addEventAlgo(CompFactory.JobOptsDumperAlg(FileName="G4FaserTestConfig.txt")) + cfg.getService("StoreGateSvc").Dump = True + cfg.getService("ConditionStore").Dump = True + cfg.printConfig(withDetails=True, summariseProps = False) # gags on ParticleGun if summariseProps = True? + + ConfigFlags.dump() + #f = open("test.pkl","wb") + #cfg.store(f) + #f.close() +# +# Execute and finish +# + + #cfg.foreach_component("*").OutputLevel = "INFO" # Use warning for production + + sc = cfg.run() + + b = time.time() + log.info("Run G4FaserAlg in " + str(b-a) + " seconds") +# +# Success should be 0 +# + sys.exit(not sc.isSuccess()) + diff --git a/Control/CalypsoExample/Generation/scripts/faser_particlegun.py b/Control/CalypsoExample/Generation/scripts/faser_particlegun.py new file mode 100755 index 0000000000000000000000000000000000000000..ee38005df79c3f6aab97b5c800f3949521110a02 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/faser_particlegun.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python +""" +Produce particle gun samples +Derived from G4FaserAlgConfigNew +This is a general low-level script, +although this could be useful for testing. + +Usage: +faser_particlegun.py <options> + +Control using command-line options: +--evtMax=1000 +--skipEvt=1000 + +Output.HITSFileName=<name> +Sim.Gun='{"pid" : 11, "z": -1500.}' + +Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +""" + +if __name__ == '__main__': + + import time + a = time.time() +# +# Set up logging and config behaviour +# + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, VERBOSE + from AthenaCommon.Configurable import Configurable + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = 1 +# +# Import and set config flags +# + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Exec.MaxEvents = 10 # can be overridden from command line with --evtMax=<number> + ConfigFlags.Exec.SkipEvents = 0 # can be overridden from command line with --skipEvt=<number> + from AthenaConfiguration.Enums import ProductionStep + ConfigFlags.Common.ProductionStep = ProductionStep.Simulation +# +# All these must be specified to avoid auto-configuration +# + ConfigFlags.Input.RunNumber = [12345] #Isn't updating - todo: investigate + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [1] + ConfigFlags.Input.isMC = True +# +# Output file name +# + ConfigFlags.Output.HITSFileName = "my.HITS.pool.root" # can be overridden from command line with Output.HITSFileName=<name> +# +# Sim ConfigFlags +# + ConfigFlags.Sim.Layout = "FASER" + ConfigFlags.Sim.PhysicsList = "FTFP_BERT" + ConfigFlags.Sim.ReleaseGeoModel = False + ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file + ConfigFlags.addFlag("Sim.Gun",{"Generator" : "SingleParticle"}) # Property bag for particle gun keyword:argument pairs + ConfigFlags.addFlag("Sim.Beam.xangle", 0) # Potential beam crossing angles + ConfigFlags.addFlag("Sim.Beam.yangle", 0) + + ConfigFlags.GeoModel.FaserVersion = "FASERNU-02" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up + ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # To avoid autoconfig + ConfigFlags.GeoModel.Align.Dynamic = False + +# +# Preset particle gun parameters +# + from math import atan + from AthenaCommon.SystemOfUnits import GeV, TeV, cm, m + from AthenaCommon.PhysicalConstants import pi + + # 11 - electron, 13 - muon, 22 - photon + import ParticleGun as PG + ConfigFlags.Sim.Gun = { + "Generator" : "SingleParticle", "pid" : 13, + "energy" : PG.LogSampler(10*GeV, 1*TeV), + "theta" : PG.GaussianSampler(0, atan((10*cm)/(7*m)), oneside = True), + "phi" : [0, 2*pi], "mass" : 0.511, "radius" : -10*cm, #"z": -2.0*m, + "randomSeed" : 12345} + +# +# Command-line overrides +# +# These have the format: Sim.Gun='{"pid" : 11}' +# Filename: Output.HITSFileName="test.muon.001.root" +# Also number of events: --evtMax 100 +# Starting at z = -1.5m (-1500.) will miss the veto (for electrons) + + import sys + ConfigFlags.fillFromArgs(sys.argv[1:]) + +# +# By being a little clever, we can steer the geometry setup from the command line using GeoModel.FaserVersion +# +# MDC configuration +# + detectors = ['Veto', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion'] +# +# Setup detector flags +# + from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList + setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True) +# +# Finalize flags +# + ConfigFlags.lock() +# +# Initialize a new component accumulator +# + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) +# +# Configure the particle gun as requested, or using defaults +# + +# +# Particle gun generators - the generator, energy, angle, particle type, position, etc can be modified by passing keyword arguments +# + from FaserParticleGun.FaserParticleGunConfig import FaserParticleGunCfg + cfg.merge(FaserParticleGunCfg(ConfigFlags)) + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) + +# +# Output file +# + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + cfg.merge(PoolWriteCfg(ConfigFlags)) + +# +# Shift LOS +# + + if ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle: + MCEventKey = "BeamTruthEventShifted" + import McParticleEvent.Pythonizations + from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg + cfg.merge(ShiftLOSCfg(ConfigFlags, OutputMCEventKey = MCEventKey, + xcross = ConfigFlags.Sim.Beam.xangle, ycross = ConfigFlags.Sim.Beam.yangle)) + else: + MCEventKey = "BeamTruthEvent" + +# +# Add the G4FaserAlg +# + from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg + cfg.merge(G4FaserAlgCfg(ConfigFlags, InputTruthCollection = MCEventKey)) +# +# Dump config +# + from AthenaConfiguration.ComponentFactory import CompFactory + cfg.addEventAlgo(CompFactory.JobOptsDumperAlg(FileName="G4FaserTestConfig.txt")) + cfg.getService("StoreGateSvc").Dump = True + cfg.getService("ConditionStore").Dump = True + cfg.printConfig(withDetails=True, summariseProps = False) # gags on ParticleGun if summariseProps = True? + + ConfigFlags.dump() + #f = open("test.pkl","wb") + #cfg.store(f) + #f.close() +# +# Execute and finish +# + + #cfg.foreach_component("*").OutputLevel = "INFO" # Use warning for production + + sc = cfg.run() + + b = time.time() + log.info("Run G4FaserAlg in " + str(b-a) + " seconds") +# +# Success should be 0 +# + sys.exit(not sc.isSuccess()) + diff --git a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh new file mode 100755 index 0000000000000000000000000000000000000000..6278fddba9c504ae360c0947c445553b455cdccc --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh @@ -0,0 +1,150 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_foresee.sh config_file segment [release_directory] [working_directory] +# +# config_file - full file name (with path) +# segment - segment number (file segment) +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches gen/g???? or sim/s???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +config_path=${1} +segment=${2} +release_directory=${3} +working_directory=${4} +# +# Set defaults if arguments aren't provided +if [ -z "$config_path" ] +then + echo "No config_path specified!" + echo "Usage: submit_faserMDC_foresee.sh config_file segment [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$segment" ] +then + segment=0 +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +# Apply padding to segment number +printf -v seg_str "%05d" $segment +# +starting_directory=`pwd` +# +# Now extract the file stem +# +# First, get the filename +config_file=$(basename "$config_path") +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read config_file_stem ext <<< "$config_file" +# +# Try to find the run number +IFS='-' +# Read the split words into an array based on delimeter +read faser short run_number <<< "$config_file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Check if we found a number, use full config name if not +output_directory="$working_directory/${run_number}" +re='^[0-9]+$' +if ! [[ $run_number =~ $re ]] ; then + # Not a number... + output_directory="$working_directory/${config_file_stem}" +fi +# +# Make output directory if needed +mkdir -p "$output_directory" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/${config_file_stem}-${seg_str}.log" +echo `date` - $HOSTNAME +echo "File: $config_file" +echo "Segment: $seg_str" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +# This doesn't seem to work, as we need the --input argument +#asetup +#source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# +# Try to find a release tag +cd calypso +gentag=`git describe` +if [[ "$gentag" == "gen/g"???? ]]; then + tag=`echo "$gentag" | cut -c 5-10` + echo "Found gen tag: $tag" +fi +if [[ "$gentag" == "sim/s"???? ]]; then + tag=`echo "$gentag" | cut -c 5-10` + echo "Found sim tag: $tag" +fi +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "${config_file_stem}-${seg_str}" ]]; then + echo "Directory ${config_file_stem}-${seg_str} already exists" +else + mkdir "${config_file_stem}-${seg_str}" +fi +cd "${config_file_stem}-${seg_str}" +# +# Run job +if [[ -z "$tag" ]]; then + faserMDC_foresee.py "--conf=$config_path" "--segment=$seg_str" +else + faserMDC_foresee.py "--conf=$config_path" "--segment=$seg_str" "--tag=$tag" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" diff --git a/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh new file mode 100755 index 0000000000000000000000000000000000000000..c85fa4803a7fe9d2acfd0d3e29beaf26e515afe6 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_particlegun.sh config_file segment [release_directory] [working_directory] +# +# config_file - full file name (with path) +# segment - segment number (file segment) +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches gen/g???? or sim/s???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +config_path=${1} +segment=${2} +release_directory=${3} +working_directory=${4} +# +# Set defaults if arguments aren't provided +if [ -z "$config_path" ] +then + echo "No config_path specified!" + echo "Usage: submit_faserMDC_particlegun.sh config_file segment [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$segment" ] +then + segment=0 +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +# Apply padding to segment number +printf -v seg_str "%05d" $segment +# +starting_directory=`pwd` +# +# Now extract the file stem +# +# First, get the filename +config_file=$(basename "$config_path") +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read config_file_stem ext <<< "$config_file" +# +# Try to find the run number +IFS='-' +# Read the split words into an array based on delimeter +read faser short run_number <<< "$config_file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Check if we found a number, use full config name if not +output_directory="$working_directory/${run_number}" +re='^[0-9]+$' +if ! [[ $run_number =~ $re ]] ; then + # Not a number... + output_directory="$working_directory/${config_file_stem}" +fi +# +# Make output directory if needed +mkdir -p "$output_directory" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/${config_file_stem}-${seg_str}.log" +echo `date` - $HOSTNAME +echo "File: $config_file" +echo "Segment: $seg_str" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +# This doesn't seem to work, as we need the --input argument +#asetup +#source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# +# Try to find a release tag +cd calypso +gentag=`git describe` +if [[ "$gentag" == "gen/g"???? ]]; then + tag=`echo "$gentag" | cut -c 5-10` + echo "Found gen tag: $tag" +fi +if [[ "$gentag" == "sim/s"???? ]]; then + tag=`echo "$gentag" | cut -c 5-10` + echo "Found sim tag: $tag" +fi +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "${config_file_stem}-${seg_str}" ]]; then + echo "Directory ${config_file_stem}-${seg_str} already exists" +else + mkdir "${config_file_stem}-${seg_str}" +fi +cd "${config_file_stem}-${seg_str}" +# +# Run job +if [[ -z "$tag" ]]; then + faserMDC_particlegun.py "--conf=$config_path" "--segment=$seg_str" +else + faserMDC_particlegun.py "--conf=$config_path" "--segment=$seg_str" "--tag=$tag" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# + diff --git a/Control/CalypsoExample/GeoModelTest/CMakeLists.txt b/Control/CalypsoExample/GeoModelTest/CMakeLists.txt index 9db978f852f7d3ae840297d164670b9c6ba9aa00..772543c3ad28c4f31b5d42e382cff2cc79215192 100644 --- a/Control/CalypsoExample/GeoModelTest/CMakeLists.txt +++ b/Control/CalypsoExample/GeoModelTest/CMakeLists.txt @@ -25,6 +25,11 @@ atlas_add_test( Faser02GeoCheck PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR} PROPERTIES TIMEOUT 300 ) +atlas_add_test( Faser03GeoCheck + SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/python/Faser03TestConfig.py + PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + PROPERTIES TIMEOUT 300 ) + atlas_add_test( TestBeamGeoCheck SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/python/TestBeamTestConfig.py diff --git a/Control/CalypsoExample/GeoModelTest/python/Faser01TestConfig.py b/Control/CalypsoExample/GeoModelTest/python/Faser01TestConfig.py index 69a57833523e460b1ab5465312f410ae9e2509d6..e85fd9e4b3f2529de19b5d4d6e323275dbc5b5e6 100644 --- a/Control/CalypsoExample/GeoModelTest/python/Faser01TestConfig.py +++ b/Control/CalypsoExample/GeoModelTest/python/Faser01TestConfig.py @@ -19,6 +19,7 @@ def GeoModelTestCfg(flags, name="GeoModelTestAlg", **kwargs): GeoModelTestAlg = CompFactory.GeoModelTestAlg a.addEventAlgo(GeoModelTestAlg(name, FirstSCTStation=1, LastSCTStation=3, + NumVetoNuStations=0, **kwargs)) return a diff --git a/Control/CalypsoExample/GeoModelTest/python/Faser02TestConfig.py b/Control/CalypsoExample/GeoModelTest/python/Faser02TestConfig.py index 03913db74587b020b24c290fc6a2928eb965e22d..ba3f91b75be389c3c4053b6f694ee1bdbde0fa99 100644 --- a/Control/CalypsoExample/GeoModelTest/python/Faser02TestConfig.py +++ b/Control/CalypsoExample/GeoModelTest/python/Faser02TestConfig.py @@ -19,6 +19,7 @@ def GeoModelTestCfg(flags, name="GeoModelTestAlg", **kwargs): GeoModelTestAlg = CompFactory.GeoModelTestAlg a.addEventAlgo(GeoModelTestAlg(name, FirstSCTStation=0, LastSCTStation=3, + NumVetoNuStations=0, PrintSctIDs=True, **kwargs)) @@ -35,7 +36,7 @@ if __name__ == "__main__": ConfigFlags.Input.isMC = True # Needed to bypass autoconfig ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion ConfigFlags.GeoModel.FaserVersion = "FASERNU-02" # Default FASER geometry - # ConfigFlags.GeoModel.GeoExportFile = "faserGeoNu02.db" # Writes out a GeoModel file with the full geometry tree (optional, comment out to skip) + ConfigFlags.GeoModel.GeoExportFile = "FaserNu02.db" # Writes out a GeoModel file with the full geometry tree (optional, comment out to skip) # ConfigFlags.Detector.EnableVeto = True # ConfigFlags.Detector.EnableTrigger = True # ConfigFlags.Detector.EnablePreshower= True diff --git a/Control/CalypsoExample/GeoModelTest/python/Faser03TestConfig.py b/Control/CalypsoExample/GeoModelTest/python/Faser03TestConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..70322eb150975256868a84bf7bd2174697d0a0da --- /dev/null +++ b/Control/CalypsoExample/GeoModelTest/python/Faser03TestConfig.py @@ -0,0 +1,68 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +#!/usr/bin/env python +import sys +from AthenaCommon.Constants import VERBOSE, INFO +from AthenaConfiguration.ComponentFactory import CompFactory + +def GeoModelTestCfg(flags, name="GeoModelTestAlg", **kwargs): + + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + a = FaserGeometryCfg(flags) + + # Initialize field service + from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + a.merge(MagneticFieldSvcCfg(flags)) + + # Configure the algorithm itself + GeoModelTestAlg = CompFactory.GeoModelTestAlg + a.addEventAlgo(GeoModelTestAlg(name, FirstSCTStation=0, + LastSCTStation=3, + PrintSctIDs=True, + **kwargs)) + + return a + +if __name__ == "__main__": + from AthenaCommon.Logging import log#, logging + from AthenaCommon.Configurable import Configurable + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + + Configurable.configurableRun3Behavior = True + +# Flags for this job + ConfigFlags.Input.isMC = True # Needed to bypass autoconfig + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Default FASER geometry + ConfigFlags.GeoModel.GeoExportFile = "FaserNu03.db" # Writes out a GeoModel file with the full geometry tree (optional, comment out to skip) + ConfigFlags.Detector.GeometryEmulsion = True + ConfigFlags.Detector.GeometryTrench = True + # ConfigFlags.Detector.EnableVeto = True + # ConfigFlags.Detector.EnableTrigger = True + # ConfigFlags.Detector.EnablePreshower= True + # ConfigFlags.Detector.EnableFaserSCT = True + # ConfigFlags.Detector.EnableUpstreamDipole = True + # ConfigFlags.Detector.EnableCentralDipole = True + # ConfigFlags.Detector.EnableDownstreamDipole = True + # ConfigFlags.Detector.EnableEcal = True + ConfigFlags.lock() + +# Configure components + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + acc = MainServicesCfg(ConfigFlags) + +# Set up algorithm + acc.merge(GeoModelTestCfg(ConfigFlags)) + +# Configure verbosity + msgSvc = acc.getService("MessageSvc") + msgSvc.Format = "% F%30W%S%7W%R%T %0W%M" + # ConfigFlags.dump() + # logging.getLogger('forcomps').setLevel(VERBOSE) + acc.foreach_component("*").OutputLevel = VERBOSE + acc.foreach_component("*ClassID*").OutputLevel = INFO + log.setLevel(VERBOSE) + +# Execute and finish + sys.exit(int(acc.run(maxEvents=1).isFailure())) diff --git a/Control/CalypsoExample/GeoModelTest/python/TestBeamTestConfig.py b/Control/CalypsoExample/GeoModelTest/python/TestBeamTestConfig.py index d590b125b0570e1628481ecbcaad312c357aa021..5dd299336c754e97a9de0fe8ec7b798c79a30f75 100644 --- a/Control/CalypsoExample/GeoModelTest/python/TestBeamTestConfig.py +++ b/Control/CalypsoExample/GeoModelTest/python/TestBeamTestConfig.py @@ -25,6 +25,7 @@ def GeoModelTestCfg(flags, name="GeoModelTestAlg", **kwargs): LastSCTStation=0, NumVetoStations=1, NumVetoPlatesPerStation=2, + NumVetoNuStations=0, NumTriggerStations=0, PrintSctIDs=True, **kwargs)) diff --git a/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.cxx b/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.cxx index 0865640503cfd4d2862f643acb6cbe38a7828dc4..0db09483da97480f304421db1ff6a1e464e0b0c5 100644 --- a/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.cxx +++ b/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.cxx @@ -4,6 +4,7 @@ #include "GeoModelFaserUtilities/GeoModelExperiment.h" #include "ScintReadoutGeometry/VetoDetectorManager.h" +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" #include "ScintReadoutGeometry/TriggerDetectorManager.h" #include "ScintReadoutGeometry/PreshowerDetectorManager.h" #include "TrackerReadoutGeometry/SCT_DetectorManager.h" @@ -12,6 +13,7 @@ #include "TrackerReadoutGeometry/SiDetectorElement.h" #include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/PreshowerID.h" #include "TrackerIdentifier/FaserSCT_ID.h" @@ -68,6 +70,8 @@ StatusCode GeoModelTestAlg::execute(const EventContext& ctx) const ATH_CHECK(testVeto()); + if (m_numVetoNuStations > 0) ATH_CHECK(testVetoNu()); + ATH_CHECK(testTrigger()); ATH_CHECK(testPreshower()); @@ -469,6 +473,160 @@ StatusCode GeoModelTestAlg::testSCT() const return StatusCode::SUCCESS; } +StatusCode GeoModelTestAlg::testVetoNu() const +{ + // Test retrieval of helper object directly from store + const VetoNuID* helper = nullptr; + ATH_CHECK(detStore()->retrieve(helper, "VetoNuID")); + if (helper != nullptr) + { + // Test neighbors with helper function + const IdContext& context = helper->plate_context(); + ATH_MSG_ALWAYS("Retrieved VetoNuID helper from DetStore."); + for (int iStation = 0; iStation < m_numVetoNuStations; iStation++) + { + for (int iPlate = 0; iPlate < m_numVetoNuPlatesPerStation; iPlate++) + { + Identifier thisId = helper->plate_id(iStation, iPlate, true); + IdentifierHash thisHash = helper->plate_hash(thisId); + IdentifierHash prevHash; + IdentifierHash nextHash; + Identifier prevId; + Identifier nextId; + int prevStation {-1}; + int prevPlate {-1}; + int nextStation {-1}; + int nextPlate {-1}; + int prevStat = helper->get_prev_in_z(thisHash, prevHash); + if (prevStat == 0) + { + IdentifierHash testHash; + int nextStat = helper->get_next_in_z(prevHash, testHash); + if (nextStat != 0 || testHash != thisHash) + { + ATH_MSG_FATAL("Next VetoNu plate (" << testHash << ") of previous (" << prevHash << ") is not the original (" << thisHash <<")" ); + return StatusCode::FAILURE; + } + prevStat = helper->get_id(prevHash, prevId, &context); + if (prevStat == 0) + { + prevStation = helper->station(prevId); + prevPlate = helper->plate(prevId); + } + } + int nextStat = helper->get_next_in_z(thisHash, nextHash); + if (nextStat == 0) + { + IdentifierHash testHash; + prevStat = helper->get_prev_in_z(nextHash, testHash); + if (prevStat != 0 || testHash != thisHash) + { + ATH_MSG_FATAL("Previous veto plate (" << testHash << ") of next (" << nextHash << ") is not the original (" << thisHash <<")" ); + return StatusCode::FAILURE; + } + nextStat = helper->get_id(nextHash, nextId, &context); + if (nextStat == 0) + { + nextStation = helper->station(nextId); + nextPlate = helper->plate(nextId); + } + } + ATH_MSG_ALWAYS("Station/Plate " << iStation << "/" << iPlate << + " (" << thisHash << ") " << + " : prev = " << prevStation << "/" << prevPlate << + " , next = " << nextStation << "/" << nextPlate ); + } + } + } + else + { + ATH_MSG_FATAL("Failed to retrieve VetoNuID helper from DetStore."); + return StatusCode::FAILURE; + } + + // Test direct retrieval of typed managers from DetStore + const ScintDD::VetoNuDetectorManager* vetoMgr = nullptr; + ATH_CHECK(detStore()->retrieve(vetoMgr, "VetoNu")); + if (vetoMgr != nullptr) + { + ATH_MSG_ALWAYS("Retrieved (typed) VetoNu detector manager with " << vetoMgr->getNumTreeTops() << " treetops directly from DetStore."); + // Compare numerology with the "right" answers from our properties + if (vetoMgr->numerology().numStations() != m_numVetoNuStations) + { + ATH_MSG_FATAL("Disagreement in number of veto stations."); + return StatusCode::FAILURE; + } + if (m_numVetoNuStations > 0 && vetoMgr->numerology().numPlatesPerStation() != m_numVetoNuPlatesPerStation) + { + ATH_MSG_FATAL("Disagreement in number of plates per veto station."); + return StatusCode::FAILURE; + } + if (m_numVetoNuStations > 0 && m_numVetoNuPlatesPerStation > 0 && vetoMgr->numerology().numPmtsPerPlate() != m_numVetoNuPmtsPerPlate) + { + ATH_MSG_FATAL("Disagreement in number of pmts per veto plate."); + return StatusCode::FAILURE; + } + // Test detector elements + const ScintDD::ScintDetectorElementCollection* elements = vetoMgr->getDetectorElementCollection(); + for (int station = 0; station < m_numVetoNuStations; station++) + { + for (int plate = 0; plate < m_numVetoNuPlatesPerStation; plate++) + { + Identifier id = helper->plate_id(station, plate, true); + if (!vetoMgr->identifierBelongs(id)) + { + ATH_MSG_FATAL("Valid VetoNu identifier does not pass identifierBelongs."); + return StatusCode::FAILURE; + } + IdentifierHash hash = helper->plate_hash(id); + ScintDD::ScintDetectorElement* elementByLevels = vetoMgr->getDetectorElement(station, plate); + ScintDD::ScintDetectorElement* elementById = vetoMgr->getDetectorElement(id); + ScintDD::ScintDetectorElement* elementByHash = vetoMgr->getDetectorElement(hash); + ScintDD::ScintDetectorElement* element = (*elements)[hash]; + if (elementByLevels != element || elementById != element || elementByHash != element) + { + ATH_MSG_FATAL("Inconsistent retrieval of VetoNu detector elements"); + return StatusCode::FAILURE; + } + ATH_MSG_ALWAYS("Found VetoNu plate (" << station << ", " << plate << ") with global center at (" << + element->center().x() << ", " << + element->center().y() << ", " << + element->center().z() << ")." + ); + const ScintDD::ScintDetectorElement* next = element->nextInZ(); + if (next != nullptr) + { + if (next->prevInZ() != element) + { + ATH_MSG_FATAL("Previous neighbor of next VetoNu element is not this element."); + return StatusCode::FAILURE; + } + } + const ScintDD::ScintDetectorElement* prev = element->prevInZ(); + if (prev != nullptr) + { + if (prev->nextInZ() != element) + { + ATH_MSG_FATAL("Next neighbor of previous VetoNu element is not this element."); + return StatusCode::FAILURE; + } + } + if (next == nullptr && prev == nullptr && m_numVetoPlatesPerStation > 1) + { + ATH_MSG_FATAL("Veto element " << hash << " has no previous OR next neighbor."); + return StatusCode::FAILURE; + } + } + } + } + else + { + ATH_MSG_FATAL("Failed to retrieve (typed) Veto detector manager directly from DetStore."); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; +} + StatusCode GeoModelTestAlg::testVeto() const { // Test retrieval of helper object directly from store @@ -623,6 +781,10 @@ StatusCode GeoModelTestAlg::testVeto() const return StatusCode::SUCCESS; } + + + + StatusCode GeoModelTestAlg::testTrigger() const { // Test retrieval of helper object directly from store diff --git a/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.h b/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.h index 010be38c93980f6bb9db5f3f4779b5bc6144b559..9fe9ab00f3ca5fc31ca2208b2f5ae72024829636 100644 --- a/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.h +++ b/Control/CalypsoExample/GeoModelTest/src/GeoModelTestAlg.h @@ -26,6 +26,7 @@ class GeoModelTestAlg : public AthReentrantAlgorithm private: StatusCode testVeto() const; + StatusCode testVetoNu() const; StatusCode testTrigger() const; StatusCode testPreshower() const; StatusCode testSCT() const; @@ -45,6 +46,10 @@ class GeoModelTestAlg : public AthReentrantAlgorithm Gaudi::Property<int> m_numPreshowerPlatesPerStation {this, "NumPreshowerPlatesPerStation", 2, "Number of plates per station in the Preshower detector"}; Gaudi::Property<int> m_numPreshowerPmtsPerPlate {this, "NumPreshowerPmtsPerPlate", 1, "Number of pmts per plate in the Preshower detector"}; + Gaudi::Property<int> m_numVetoNuStations {this, "NumVetoNuStations", 1, "Number of stations in the VetoNu detector"}; + Gaudi::Property<int> m_numVetoNuPlatesPerStation {this, "NumVetoNuPlatesPerStation", 2, "Number of plates per station in the VetoNu detector"}; + Gaudi::Property<int> m_numVetoNuPmtsPerPlate {this, "NumVetoNuPmtsPerPlate", 1, "Number of pmts per plate in the VetoNu detector"}; + Gaudi::Property<int> m_firstSctStation {this, "FirstSCTStation", 1, "Identifier of the first SCT station (0 w/FaserNu, 1 otherwise)"}; Gaudi::Property<int> m_lastSctStation {this, "LastSCTStation", 3, "Identifier of the last SCT station (normally 3)"}; Gaudi::Property<int> m_numSctPlanesPerStation {this, "NumSCTPlanesPerStation", 3, "Number of planes per station in the SCT detector"}; diff --git a/Control/CalypsoExample/Reconstruction/CMakeLists.txt b/Control/CalypsoExample/Reconstruction/CMakeLists.txt index dddd2f621013501750a82d0569e2714bbb20c9db..f821257234e5758a0c92a1d13e1b0d5df44f2843 100644 --- a/Control/CalypsoExample/Reconstruction/CMakeLists.txt +++ b/Control/CalypsoExample/Reconstruction/CMakeLists.txt @@ -20,7 +20,17 @@ atlas_install_scripts( scripts/*.sh scripts/*.py ) atlas_add_test( ProdRecoTI12 SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../rawdata/Faser-Physics-001920-filtered.raw TI12Data PROPERTIES TIMEOUT 300 ) + +# Turn this off until we figure out the CKF behavior on testbeam data atlas_add_test( ProdRecoTestBeam SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-003613-filtered.raw TestBeamData PROPERTIES TIMEOUT 300 ) +atlas_add_test( ProdRecoPilotTracks + SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-pilot_tracks-filtered.raw TI12Data + PROPERTIES TIMEOUT 300 ) + +atlas_add_test( ProdRecoTI12-2022 + SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../rawdata/Faser-Physics-006525-filtered.raw TI12Data02 + PROPERTIES TIMEOUT 300 ) + diff --git a/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py new file mode 100755 index 0000000000000000000000000000000000000000..942340f12c97db7e80850e0ede3be55d44bda54d --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Run with: +# ./faser_reco.py filepath [runtype] +# +# filepath - fully qualified path, including url if needed, to the input raw data file +# example: "root://hepatl30//atlas/local/torrence/faser/commissioning/TestBeamData/Run-004150/Faser-Physics-004150-00000.raw" +# +# runtype - optionally specify the data type (TI12Data, TI12Data02, TI12Data03 or TestBeamData). +# In a normal file system location, this will be extracted from the directory name, +# but runtype will override this assignment. +# > TI12Data02 is needed for the IFT geometry. +# MDC will assume TI12Data03 geometry. +# +import sys +import time +import argparse + +a = time.time() + +parser = argparse.ArgumentParser(description="Run FASER reconstruction") + +parser.add_argument("file_path", + help="Fully qualified path of the raw input file") +parser.add_argument("run_type", nargs="?", default="", + help="Specify run type (if it can't be parsed from path)") +parser.add_argument("-r", "--reco", default="", + help="Specify reco tag (to append to output filename)") +parser.add_argument("-n", "--nevents", type=int, default=-1, + help="Specify number of events to process (default: all)") +parser.add_argument("-v", "--verbose", action='store_true', + help="Turn on DEBUG output") + + +args = parser.parse_args() + +from pathlib import Path + +filepath=Path(args.file_path) + +# runtype has been provided +if len(args.run_type) > 0: + runtype=args.run_type + +# Assume based on MDC reco +else: + runtype = "TI12Data03" + +# Assume this is MC +args.isMC = True + +print(f"Starting reconstruction of {filepath.name} with type {runtype}") +if args.nevents > 0: + print(f"Reconstructing {args.nevents} events by command-line option") + +# Start reconstruction + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from AthenaCommon.Constants import VERBOSE, INFO + +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags + +Configurable.configurableRun3Behavior = True + +# Flags for this job +ConfigFlags.Input.isMC = args.isMC # Needed to bypass autoconfig +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + +ConfigFlags.Input.ProjectName = "data20" +ConfigFlags.GeoModel.Align.Dynamic = False + +# For tracking +ConfigFlags.TrackingGeometry.MaterialSource = "/cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/acts/material-maps.json" + +# TI12 Cosmics geometry +if runtype == "TI12Data": + ConfigFlags.GeoModel.FaserVersion = "FASER-01" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" + +# Testbeam setup +elif runtype == "TestBeamData" or runtype == "TestBeam2021": + ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00" + +# New TI12 geometry (ugh) +elif runtype == "TI12Data02": + ConfigFlags.GeoModel.FaserVersion = "FASER-02" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" + +# Final 2022 TI12 geometry +elif runtype == "TI12Data03": + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" + +else: + print("Invalid run type found:", runtype) + print("Specify correct type or update list") + sys.exit(-1) + + +# Must use original input string here, as pathlib mangles double // in path names +ConfigFlags.Input.Files = [ args.file_path ] + +filestem = filepath.stem +if len(args.reco) > 0: + filestem += f"-{args.reco}" + +ConfigFlags.addFlag("Output.xAODFileName", f"{filestem}-xAOD.root") +ConfigFlags.Output.ESDFileName = f"{filestem}-ESD.root" +ConfigFlags.Output.doWriteESD = False + +# +# Play around with this? +# ConfigFlags.Concurrency.NumThreads = 2 +# ConfigFlags.Concurrency.NumConcurrentEvents = 2 +ConfigFlags.lock() + +# +# Configure components +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolWriteCfg(ConfigFlags)) + +# +# Set up RAW data access + +if args.isMC: + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + acc.merge(PoolReadCfg(ConfigFlags)) +else: + from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg + acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) + +# +# Needed, or move to MainServicesCfg? +from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +acc.merge(FaserGeometryCfg(ConfigFlags)) + +# Set up algorithms +from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg +acc.merge(WaveformReconstructionCfg(ConfigFlags)) + +# Not ready for primetime +# from CaloRecAlgs.CaloRecAlgsConfig import CalorimeterReconstructionCfg +# acc.merge(CalorimeterReconstructionCfg(ConfigFlags)) + +# Tracker clusters +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_RDOs")) + +# +# SpacePoints +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) + +# Try Dave's new fitter +print("Configuring TrackerSegmentFit (new)") +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +acc.merge(SegmentFitAlgCfg(ConfigFlags, + SharedHitFraction=0.61, + MinClustersPerFit=5, + TanThetaXZCut=0.083)) +# +# Ghost removal +from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg +acc.merge(GhostBustersCfg(ConfigFlags)) + +# +# Kalman Filter for tracking +from FaserActsKalmanFilter.CKF2Config import CKF2Cfg +acc.merge(CKF2Cfg(ConfigFlags, noDiagnostics=True)) + +# +# Configure output +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +itemList = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + , "FaserSiHitCollection#*" # Strip hits, do we want this? + , "FaserSCT_RDO_Container#*" + , "FaserSCT_SpacePointContainer#*" + , "Tracker::FaserSCT_ClusterContainer#*" + , "TrackCollection#*" +] +# +if args.isMC: + # Add truth records here? + itemList.extend( ["McEventCollection#*", "TrackerSimDataCollection#*"] ) + +acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) + +# Waveform reconstruction output +from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionOutputCfg +acc.merge(WaveformReconstructionOutputCfg(ConfigFlags)) + +# Calorimeter reconstruction output +# from CaloRecAlgs.CaloRecAlgsConfig import CalorimeterReconstructionOutputCfg +# acc.merge(CalorimeterReconstructionOutputCfg(ConfigFlags)) + +# Check what we have +print( "Writing out xAOD objects:" ) +print( acc.getEventAlgo("OutputStreamxAOD").ItemList ) + +# Hack to avoid problem with our use of MC databases when isMC = False +if not args.isMC: + replicaSvc = acc.getService("DBReplicaSvc") + replicaSvc.COOLSQLiteVetoPattern = "" + replicaSvc.UseCOOLSQLite = True + replicaSvc.UseCOOLFrontier = False + replicaSvc.UseGeomSQLite = True + +# Configure verbosity +ConfigFlags.dump() +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE +else: + acc.foreach_component("*").OutputLevel = INFO + +acc.foreach_component("*ClassID*").OutputLevel = INFO + +acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M" + +# Execute and finish +sc = acc.run(maxEvents=args.nevents) + +b = time.time() +from AthenaCommon.Logging import log +log.info(f"Finish execution in {b-a} seconds") + +sys.exit(int(sc.isFailure())) + diff --git a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py index 1579f4c1b19b83a3bf7b024060122ba7ce69746b..2063b729cb1c5a09ac4a2e90c914fc7096a85412 100755 --- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py +++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py @@ -7,15 +7,18 @@ # filepath - fully qualified path, including url if needed, to the input raw data file # example: "root://hepatl30//atlas/local/torrence/faser/commissioning/TestBeamData/Run-004150/Faser-Physics-004150-00000.raw" # -# runtype - optionally specify the data type (TI12Data, TI12Data02, or TestBeamData). +# runtype - optionally specify the data type (TI12Data, TI12Data02, TI12Data03 or TestBeamData). # In a normal file system location, this will be extracted from the directory name, # but runtype will override this assignment. # TI12Data02 is needed for the IFT geometry. Script will auto-detect this if read # from normal file system location. # import sys +import time import argparse +a = time.time() + parser = argparse.ArgumentParser(description="Run FASER reconstruction") parser.add_argument("file_path", @@ -28,8 +31,6 @@ parser.add_argument("-n", "--nevents", type=int, default=-1, help="Specify number of events to process (default: all)") parser.add_argument("-v", "--verbose", action='store_true', help="Turn on DEBUG output") -parser.add_argument("--clusterFit", action='store_true', - help="Use ClusterFit (old) track finder - default: SegmentFit(new)") parser.add_argument("--isMC", action='store_true', help="Running on digitised MC rather than data") @@ -95,6 +96,10 @@ ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now ConfigFlags.Input.ProjectName = "data20" ConfigFlags.GeoModel.Align.Dynamic = False +useCKF = True +# Enable ACTS material corrections, this crashes testbeam geometries +ConfigFlags.TrackingGeometry.MaterialSource = "/cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/acts/material-maps.json" + # TI12 Cosmics geometry if runtype == "TI12Data": ConfigFlags.GeoModel.FaserVersion = "FASER-01" @@ -104,12 +109,18 @@ if runtype == "TI12Data": elif runtype == "TestBeamData" or runtype == "TestBeam2021": ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00" + useCKF = False # New TI12 geometry (ugh) elif runtype == "TI12Data02": ConfigFlags.GeoModel.FaserVersion = "FASER-02" ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +# Final 2022 TI12 geometry +elif runtype == "TI12Data03": + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" + else: print("Invalid run type found:", runtype) print("Specify correct type or update list") @@ -125,6 +136,7 @@ if len(args.reco) > 0: ConfigFlags.addFlag("Output.xAODFileName", f"{filestem}-xAOD.root") ConfigFlags.Output.ESDFileName = f"{filestem}-ESD.root" +ConfigFlags.Output.doWriteESD = False # # Play around with this? @@ -165,24 +177,32 @@ acc.merge(WaveformReconstructionCfg(ConfigFlags)) # Tracker clusters from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg -acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_RDOs")) +# # SpacePoints from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) -# Can't use both in the same job, as they write to the same output histograms -if args.clusterFit: - print("Configuring TrackerClusterFit (old)") - # Try Dave's fitter - from TrackerClusterFit.TrackerClusterFitConfig import ClusterFitAlgCfg - acc.merge(ClusterFitAlgCfg(ConfigFlags)) - -else: - print("Configuring TrackerSegmentFit (new)") - # Try Dave's new fitter - from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg - acc.merge(SegmentFitAlgCfg(ConfigFlags)) +# Try Dave's new fitter +print("Configuring TrackerSegmentFit (new)") +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +acc.merge(SegmentFitAlgCfg(ConfigFlags, + SharedHitFraction=0.61, + MinClustersPerFit=5, + TanThetaXZCut=0.083)) + +# Turn on CKF track finding +if useCKF: + # + # Ghost removal + from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg + acc.merge(GhostBustersCfg(ConfigFlags)) + + # + # Kalman Filter for tracking + from FaserActsKalmanFilter.CKF2Config import CKF2Cfg + acc.merge(CKF2Cfg(ConfigFlags, noDiagnostics=True)) # # Configure output @@ -191,12 +211,17 @@ itemList = [ "xAOD::EventInfo#*" , "xAOD::EventAuxInfo#*" , "xAOD::FaserTriggerData#*" , "xAOD::FaserTriggerDataAux#*" - , "FaserSCT_RDO_Container#*" - , "Tracker::FaserSCT_ClusterContainer#*" + , "FaserSiHitCollection#*" # Strip hits, do we want this? + , "FaserSCT_RDO_Container#*" , "FaserSCT_SpacePointContainer#*" - #, "FaserSCT_SpacePointOverlapCollection#*" + , "Tracker::FaserSCT_ClusterContainer#*" , "TrackCollection#*" ] +# +if args.isMC: + # Add truth records here? + itemList.extend( ["McEventCollection#*"] ) + acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) # Waveform reconstruction output @@ -223,13 +248,6 @@ if not args.isMC: # ConfigFlags.dump() if args.verbose: acc.foreach_component("*").OutputLevel = VERBOSE - - #acc.getService("FaserByteStreamInputSvc").DumpFlag = True - #acc.getService("FaserEventSelector").OutputLevel = VERBOSE - #acc.getService("FaserByteStreamInputSvc").OutputLevel = VERBOSE - #acc.getService("FaserByteStreamCnvSvc").OutputLevel = VERBOSE - #acc.getService("FaserByteStreamAddressProviderSvc").OutputLevel = VERBOSE - else: acc.foreach_component("*").OutputLevel = INFO @@ -238,4 +256,11 @@ acc.foreach_component("*ClassID*").OutputLevel = INFO acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M" # Execute and finish -sys.exit(int(acc.run(maxEvents=args.nevents).isFailure())) +sc = acc.run(maxEvents=args.nevents) + +b = time.time() +from AthenaCommon.Logging import log +log.info(f"Finish execution in {b-a} seconds") + +sys.exit(int(sc.isFailure())) + diff --git a/Control/CalypsoExample/Reconstruction/scripts/submit_faserMDC_reco.sh b/Control/CalypsoExample/Reconstruction/scripts/submit_faserMDC_reco.sh new file mode 100755 index 0000000000000000000000000000000000000000..b04d56aa9d13f3bac39f02213e0f47625714c689 --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/scripts/submit_faserMDC_reco.sh @@ -0,0 +1,134 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faser_reco.sh file_path [release_directory] [working_directory] [nevents] +# +# file_path - full file name (with path) +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# nevents - optional number of events to process (default: -1 - all) +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches reco/r???? it will be passed to the reco job +# +#---------------------------------------- +# +# Parse command-line options +file_path=${1} +release_directory=${2} +working_directory=${3} +nevents=${4} +# +# Set defaults if arguments aren't provided +if [ -z "$file_path" ] +then + echo "No file_path specified!" + exit 1 +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +if [ -z "$nevents" ] +then + nevents="-1" +fi +# +starting_directory=`pwd` +# +# Now extract the run number and file stem +# +# First, get the filename +file_name=$(basename "$file_path") +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read file_stem ext <<< "$file_name" +# +# Finally extract the run number +IFS='-' +# Read the split words into an array based on delimiter +read faser desc run_number segment <<< "$file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Make output directory if needed +output_directory="$working_directory/${run_number}" +mkdir -p "$output_directory" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/$file_stem.log" +echo `date` - $HOSTNAME +echo "File: $file_name" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +#asetup +#source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# +# Try to find a release tag +cd calypso +recotag=`git describe` +if [[ "$recotag" == "reco/r"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" +fi +if [[ "$recotag" == "reco/p"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" +fi +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "$file_stem" ]]; then + echo "Directory $file_stem already exists" +else + mkdir "$file_stem" +fi +cd "$file_stem" +# +# Run job +if [[ -z "$tag" ]]; then + faserMDC_reco.py "--nevents=$nevents" "$file_path" +else + faserMDC_reco.py "--nevents=$nevents" "--reco=$tag" "$file_path" +fi +# +# Print out ending time +date diff --git a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh index 64cca5567690c0680a4966b7e64f1d8ea869b1ca..277d6eaa79a3bc510cb413aa742b292837e28403 100755 --- a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh +++ b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh @@ -97,8 +97,12 @@ source build/x8*/setup.sh cd calypso recotag=`git describe` if [[ "$recotag" == "reco/r"???? ]]; then - rtag=`echo "$recotag" | cut -c 6-11` - echo "Found reco tag: $rtag" + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" +fi +if [[ "$recotag" == "reco/p"???? ]]; then + tag=`echo "$recotag" | cut -c 6-11` + echo "Found reco tag: $tag" fi # # Move to the run directory @@ -123,7 +127,7 @@ cd "$file_stem" if [[ -z "$rtag" ]]; then faser_reco.py "--nevents=$nevents" "$file_path" else - faser_reco.py "--nevents=$nevents" "--reco=$rtag" "$file_path" + faser_reco.py "--nevents=$nevents" "--reco=$tag" "$file_path" fi # # Print out ending time diff --git a/Control/CalypsoExample/Simulation/CMakeLists.txt b/Control/CalypsoExample/Simulation/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..440e12c8c1df89217ed1e7df9b3c7314ff4303d4 --- /dev/null +++ b/Control/CalypsoExample/Simulation/CMakeLists.txt @@ -0,0 +1,12 @@ +################################################################################ +# Package: Simulation +################################################################################ + +# Declare the package name: +atlas_subdir( Simulation ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( scripts/*.sh scripts/*.py ) + + diff --git a/Control/CalypsoExample/Simulation/python/__init__.py b/Control/CalypsoExample/Simulation/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1019c31f8428bc651bbfdb56065098ecc35f870c --- /dev/null +++ b/Control/CalypsoExample/Simulation/python/__init__.py @@ -0,0 +1 @@ +# Simulation.py diff --git a/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py b/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py new file mode 100755 index 0000000000000000000000000000000000000000..12de492f4070237b59dda273673b994bbc275d37 --- /dev/null +++ b/Control/CalypsoExample/Simulation/scripts/faserMDC_simulate.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +""" +Produce simulated hits from input 4-vectors +Derived from G4FaserAlgConfigNew + +Usage: +faserMDC_simulate.py filepath outfile + +filepath - full path, including url if needed, to the input 4-vector file +outfile - output filename, parameters will be inferred from this name + +Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +""" + +if __name__ == '__main__': + + import sys + import time + a = time.time() +# +# Parse command-line options +# + import sys + import argparse + + parser = argparse.ArgumentParser(description="Run FASER simulation") + + parser.add_argument("file_path", + help="Fully qualified path of the raw input file") + + parser.add_argument("output", + help="Output file name") + + #parser.add_argument("--run", type=int, default=123456, + # help="Specify run number to use in simulated data") + + parser.add_argument("--xangle", type=float, default=0.0, + help="Specify H crossing angle (in Radians)") + parser.add_argument("--yangle", type=float, default=0.0, + help="Specify V crossing angle (in Radians)") + parser.add_argument("--xshift", type=float, default=0.0, + help="Specify H shift of events wrt FASER (in mm)") + parser.add_argument("--yshift", type=float, default=0.0, + help="Specify V shift of events wrt FASER (in mm)") + + parser.add_argument("-t", "--tag", default="", + help="Specify sim tag (to append to output filename)") + parser.add_argument("-s", "--skip", type=int, default=0, + help="Specify number of events to skip (default: none)") + parser.add_argument("-n", "--nevents", type=int, default=-1, + help="Specify number of events to process (default: all)") + parser.add_argument("-v", "--verbose", action='store_true', + help="Turn on DEBUG output") + + args = parser.parse_args() + + from pathlib import Path + + filepath = Path(args.file_path) + +# +# Parse input file +# + print(f"Starting digitization of {filepath.name}") + + filestem = filepath.stem + if len(args.tag) > 0: + if args.tag in filestem: + print(f"Not adding tag {args.tag} to {filestem}") + else: + filestem += f"-{args.tag}" + + if args.output: + # Just directly specify the output filename + outfile = args.output + + spl = outfile.split('-') + if len(spl) < 4: + print(f"Can't get run number from {outfile}!") + sys.exit(1) + + runnum = int(spl[2]) + segnum = int(spl[3]) + + else: + outfile = f"{filestem}-HITS.root" + print(f"Output file name not specified") + sys.exit(1) + + print(f"Outfile: {outfile}") + +# +# Figure out events to run +# + if args.skip > 0: + print(f"Skipping {args.skip} events by command-line option") + + if args.nevents > 0: + print(f"Reconstructing {args.nevents} events by command-line option") +# +# Set up logging and config behaviour +# + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, VERBOSE + from AthenaCommon.Configurable import Configurable + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = 1 +# +# Import and set config flags +# + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + from AthenaConfiguration.Enums import ProductionStep + ConfigFlags.Common.ProductionStep = ProductionStep.Simulation +# +# All these must be specified to avoid auto-configuration +# + ConfigFlags.Input.RunNumber = [ runnum ] + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [ (segnum+1) ] + ConfigFlags.Input.isMC = True +# +# Input file name +# + # Path mangles // in url, so use direct file_path here + ConfigFlags.Input.Files = [ args.file_path ] +# +# Skip events +# + ConfigFlags.Exec.SkipEvents = args.skip + ConfigFlags.Exec.MaxEvents = args.nevents +# +# Output file name +# + ConfigFlags.Output.HITSFileName = outfile +# +# Sim ConfigFlags +# + ConfigFlags.Sim.Layout = "FASER" + ConfigFlags.Sim.PhysicsList = "FTFP_BERT" + ConfigFlags.Sim.ReleaseGeoModel = False + ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file + + # Units are radians and mm + ConfigFlags.addFlag("Sim.Beam.xangle", args.xangle) # Potential beam crossing angles + ConfigFlags.addFlag("Sim.Beam.yangle", args.yangle) + ConfigFlags.addFlag("Sim.Beam.xshift", args.xshift) # Potential beam shift + ConfigFlags.addFlag("Sim.Beam.yshift", args.yshift) + + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up + ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # To avoid autoconfig + ConfigFlags.GeoModel.Align.Dynamic = False + + # import sys + # ConfigFlags.fillFromArgs(sys.argv[1:]) + + doShiftLOS = (ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle or + ConfigFlags.Sim.Beam.xshift or ConfigFlags.Sim.Beam.yshift) + +# +# MDC geometry configuration +# + detectors = ['Veto', 'VetoNu', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', 'Dipole', 'Emulsion'] +# +# Setup detector flags +# + from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList + setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True) +# +# Finalize flags +# + ConfigFlags.lock() +# +# Initialize a new component accumulator +# + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) + +# +# Check whether a known input file was specified +# + if ConfigFlags.Input.Files[0].endswith(".events") or ConfigFlags.Input.Files[0].endswith(".hepmc"): + + from HEPMCReader.HepMCReaderConfig import HepMCReaderCfg + + if doShiftLOS: + cfg.merge(HepMCReaderCfg(ConfigFlags, McEventKey = "BeamTruthEvent_ATLASCoord")) + else: + cfg.merge(HepMCReaderCfg(ConfigFlags)) + + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) +# +# Else, set up to read it as a pool.root file +# + else: + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + cfg.merge(PoolReadCfg(ConfigFlags)) + + if doShiftLOS: + from SGComps.AddressRemappingConfig import InputOverwriteCfg + # Rename old truth collection to add ATLAS coord to can still use BeamTruthEvent for the one in FASER Coords + cfg.merge(InputOverwriteCfg("McEventCollection", "BeamTruthEvent", "McEventCollection", "BeamTruthEvent_ATLASCoord")) + +# +# Output file +# + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + cfg.merge(PoolWriteCfg(ConfigFlags)) + +# +# Shift LOS +# + if doShiftLOS: + + import McParticleEvent.Pythonizations + from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg + cfg.merge(ShiftLOSCfg(ConfigFlags, + xcross = ConfigFlags.Sim.Beam.xangle, + ycross = ConfigFlags.Sim.Beam.yangle, + xshift = ConfigFlags.Sim.Beam.xshift, + yshift = ConfigFlags.Sim.Beam.yshift)) + + +# +# Add the G4FaserAlg +# + from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg + cfg.merge(G4FaserAlgCfg(ConfigFlags)) +# +# Dump config +# + from AthenaConfiguration.ComponentFactory import CompFactory + cfg.addEventAlgo(CompFactory.JobOptsDumperAlg(FileName="G4FaserTestConfig.txt")) + cfg.getService("StoreGateSvc").Dump = True + cfg.getService("ConditionStore").Dump = True + cfg.printConfig(withDetails=True, summariseProps = False) # gags on ParticleGun if summariseProps = True? + + ConfigFlags.dump() + #f = open("test.pkl","wb") + #cfg.store(f) + #f.close() +# +# Execute and finish +# + + # This fails with ShiftLOSCfg... + #if args.verbose: + # cfg.foreach_component("*").OutputLevel = "DEBUG" + #else: + # cfg.foreach_component("*").OutputLevel = "INFO" + + sc = cfg.run(maxEvents=args.nevents) + + b = time.time() + log.info("Finish execution in " + str(b-a) + " seconds") +# +# Success should be 0 +# + sys.exit(int(sc.isFailure())) + diff --git a/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh b/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh new file mode 100755 index 0000000000000000000000000000000000000000..3c175d72519eda6d9f973c84ea3c2b1af00b7dba --- /dev/null +++ b/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh @@ -0,0 +1,177 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_simluate.sh [--shift] input_file output_file [release_directory] [working_directory] [skip] [nevts] +# +# Options: +# --shift - apply crossing angle (and FASER shift) +# +# input_file - full file name (with path) +# output_file - full output file name +# release_directory - optional path to release install directory (default pwd) +# working_directory - optional path to output directory location (default pwd) +# skip - events in input file to skip +# nevts = events in input file to process +# +# The release directory must already be set up +# (so an unqualified asetup can set up the release properly) +# +# Script will use git describe to find the release tag. +# If this matches gen/g???? or sim/s???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +while [ -n "$1" ] +do + case "$1" in + -s | --shift) + echo "Applying crossing-angle shift" + xangle=1 + shift;; # This 'eats' the argument + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done + +# +# Parse command-line arguments +infile=${1} +outfile=${2} +release_directory=${3} +working_directory=${4} +skip_events=${5} +nevts=${6} +# +# Set defaults if arguments aren't provided +if [ -z "$infile" ] +then + echo "No input file specified!" + echo "Usage: submit_faserMDC_simulate.sh input_file output_file [release dir] [output dir]" + exit 1 +fi +# +if [ -z "$outfile" ] +then + outfile="FaserMC-Test-123456-00000-HITS.root" + echo "No output file specified, using $outfile !" +fi +# +if [ -z "$release_directory" ] +then + release_directory=`pwd` +fi +# +if [ -z "$working_directory" ] +then + working_directory=`pwd` +fi +# +if [ -z "$skip_events" ] +then + skip_events=0 +fi +# +if [ -z "$nevts" ] +then + nevts=-1 +fi +# +starting_directory=`pwd` +# +# Now extract the file information +# Here we do this on the output file, as the input files can be non-standard +# +# First, get the filename +outfilename=$(basename "$outfile") +# +# Now split based on '.' to get stem +defaultIFS=$IFS +IFS='.' +read file_stem ext <<< "$outfilename" +# +# Try to find the run number +IFS='-' +# Read the split words into an array based on delimeter +read faser short run_number seg <<< "$file_stem" +# +# Set the IFS delimeter back or else echo doesn't work... +IFS=$defaultIFS +# +# Check if we found a number, use full input file name if not +output_directory="$working_directory/${run_number}" +re='^[0-9]+$' +if ! [[ $run_number =~ $re ]] ; then + # Not a number... + output_directory="$working_directory/${file_stem}" +fi +# +# Make output directory if needed +mkdir -p "$output_directory" +# +# This magic redirects everything in this script to our log file +exec >& "$output_directory/${file_stem}.log" +echo `date` - $HOSTNAME +echo "Input File: $infile" +echo "Output File: $outfilename" +echo "Release: $release_directory" +echo "Output: $output_directory" +echo "Starting: $starting_directory" +echo "Skip: $skip_events" +echo "Nevts: $nevts" +# +# Set up the release (do this automatically)? +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh +# +# Try automatic +# Always go back to the starting directory in case paths are relative +cd "$starting_directory" +cd "$release_directory" +# This doesn't seem to work, as we need the --input argument +#asetup +#source build/x8*/setup.sh +# +# Do this by hand +asetup --input=calypso/asetup.faser Athena,22.0.49 +source build/x86*/setup.sh +# +# Move to the run directory +cd "$starting_directory" +cd "$output_directory" +# +# Remove any previous directory if it exists +#if [[ -e "$file_stem" ]]; then +# echo "Remove previous directory $file_stem" +# rm -rf "$file_stem" +#fi +# +# Make run directory +if [[ -e "${file_stem}" ]]; then + echo "Directory ${file_stem} already exists" +else + mkdir "${file_stem}" +fi +cd "${file_stem}" +# +# Run job +#if [[ -z "$tag" ]]; then +#fi +if [[ -z "$xangle" ]]; then + faserMDC_simulate.py --skip "$skip_events" -n "$nevts" "$infile" "$outfile" +else + faserMDC_simulate.py --yangle -0.000150 --yshift 12.0 --skip "$skip_events" -n "$nevts" "$infile" "$outfile" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# + diff --git a/Control/CalypsoExample/rawdata/Faser-Physics-006525-filtered.raw b/Control/CalypsoExample/rawdata/Faser-Physics-006525-filtered.raw new file mode 100644 index 0000000000000000000000000000000000000000..e7e7da6e539a0f05a064c58c1b58d7c6a1081e7e Binary files /dev/null and b/Control/CalypsoExample/rawdata/Faser-Physics-006525-filtered.raw differ diff --git a/Control/CalypsoExample/rawdata/Faser-Physics-pilot_tracks-filtered.raw b/Control/CalypsoExample/rawdata/Faser-Physics-pilot_tracks-filtered.raw new file mode 100644 index 0000000000000000000000000000000000000000..3079490b5b1d0110887cb2a7de7591e0bf2b0cc2 Binary files /dev/null and b/Control/CalypsoExample/rawdata/Faser-Physics-pilot_tracks-filtered.raw differ diff --git a/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml index 52542a2837125d540824617b1085a5d710c3507f..9cebc2e82b233d6191d7671cf6d9d6997cad23f9 100644 --- a/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml +++ b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml @@ -26,4 +26,9 @@ <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/CABP200.db" accessMode="read" /> </logicalservice> +<logicalservice name="COOLOFL_TRIGGER"> + <service name="sqlite_file:data/sqlite200/waveform_reco.db" accessMode="read" /> + <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/waveform_reco.db" accessMode="read" /> +</logicalservice> + </servicelist> diff --git a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx index 50884e7221086392e645855bd885e6f19ee821e0..cc2fca779acd953d177963424389477baa30c856 100644 --- a/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx +++ b/DetectorDescription/DetDescrCnvSvc/src/DetDescrCnvSvc.cxx @@ -125,6 +125,8 @@ DetDescrCnvSvc::initialize() { if (status != StatusCode::SUCCESS) return status; status = addToDetStore(55179317, "PreshowerID"); if (status != StatusCode::SUCCESS) return status; + status = addToDetStore(247779284, "VetoNuID"); + if (status != StatusCode::SUCCESS) return status; status = addToDetStore(205618430, "FaserSCT_ID"); if (status != StatusCode::SUCCESS) return status; status = addToDetStore(113753346, "EcalID"); diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h index 6c0a2b2919f4ef4bc8f16b4519bdd82dbc45bade..0ee1ecc5d64e53a1d5cd0e04ad969421f8344c59 100644 --- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h +++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetTechnology.h @@ -35,20 +35,21 @@ namespace FaserDetDescr { fLastFaserNeutrinoTechnology = 1, // Scintillator fFirstFaserScintillatorTechnology = 2, - fFaserVeto = 2, - fFaserTrigger = 3, - fFaserPreshower = 4, - fLastFaserScintillatorTechnology = 4, + fFaserVetoNu = 2, + fFaserVeto = 3, + fFaserTrigger = 4, + fFaserPreshower = 5, + fLastFaserScintillatorTechnology = 5, // Tracker - fFirstFaserTrackerTechnology = 5, - fFaserSCT = 5, - fLastFaserTrackerTechnology = 5, + fFirstFaserTrackerTechnology = 6, + fFaserSCT = 6, + fLastFaserTrackerTechnology = 6, // Calorimeter - fFirstFaserCalorimeterTechnology = 6, - fFaserECAL = 6, - fLastFaserCalorimeterTechnology = 6, + fFirstFaserCalorimeterTechnology = 7, + fFaserECAL = 7, + fLastFaserCalorimeterTechnology = 7, // number of defined detector technologies - fNumFaserDetTechnologies = 7 + fNumFaserDetTechnologies = 8 }; } // end of namespace diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h index 3de4b6428fa65ae333a6bebe92aef8334f78a7b8..3ac1160a9e0c12935f522b0750b09a74fe4d4983 100644 --- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h +++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserDetectorID.h @@ -82,6 +82,7 @@ public: /// @name Scintillator subsystem ids //@{ Identifier veto (void) const; + Identifier vetonu (void) const; Identifier trigger (void) const; Identifier preshower (void) const; //@} @@ -157,6 +158,7 @@ public: bool is_calo (Identifier id) const; bool is_emulsion (Identifier id) const; bool is_veto (Identifier id) const; + bool is_vetonu (Identifier id) const; bool is_trigger (Identifier id) const; bool is_preshower (Identifier id) const; bool is_sct (Identifier id) const; @@ -172,6 +174,7 @@ public: bool is_calo (const ExpandedIdentifier& id) const; bool is_emulsion (const ExpandedIdentifier& id) const; bool is_veto (const ExpandedIdentifier& id) const; + bool is_vetonu (const ExpandedIdentifier& id) const; bool is_trigger (const ExpandedIdentifier& id) const; bool is_preshower (const ExpandedIdentifier& id) const; bool is_sct (const ExpandedIdentifier& id) const; @@ -230,6 +233,7 @@ protected: /// Scintillator: ExpandedIdentifier veto_exp (void) const; + ExpandedIdentifier vetonu_exp (void) const; ExpandedIdentifier trigger_exp (void) const; ExpandedIdentifier preshower_exp (void) const; @@ -247,6 +251,7 @@ protected: int calo_field_value () const; int emulsion_field_value () const; int veto_field_value () const; + int vetonu_field_value () const; int trigger_field_value () const; int preshower_field_value () const; int sct_field_value () const; @@ -306,6 +311,7 @@ private: int m_CALO_ID; int m_EMULSION_ID; int m_VETO_ID; + int m_VETONU_ID; int m_TRIGGER_ID; int m_PRESHOWER_ID; int m_SCT_ID; @@ -382,6 +388,13 @@ FaserDetectorID::veto_exp (void) const return (result << m_VETO_ID); } +inline ExpandedIdentifier +FaserDetectorID::vetonu_exp (void) const +{ + ExpandedIdentifier result(scint_exp()); + return (result << m_VETONU_ID); +} + inline ExpandedIdentifier FaserDetectorID::trigger_exp (void) const { @@ -428,6 +441,9 @@ FaserDetectorID::emulsion_field_value () const {return (m_EMULSION_ID);} inline int FaserDetectorID::veto_field_value () const {return (m_VETO_ID);} +inline int +FaserDetectorID::vetonu_field_value () const {return (m_VETONU_ID);} + inline int FaserDetectorID::trigger_field_value () const {return (m_TRIGGER_ID);} @@ -484,6 +500,16 @@ FaserDetectorID::is_veto (Identifier id) const return result; } +inline bool +FaserDetectorID::is_vetonu (Identifier id) const +{ + bool result = false; + if(is_scint(id)) { + result = (m_scint_part_impl.unpack(id) == m_VETONU_ID); + } + return result; +} + inline bool FaserDetectorID::is_trigger (Identifier id) const { diff --git a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserRegion.h b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserRegion.h index fdefad244797c043e1d6048dd0e4e416c60fba7f..86b9324d943ef75f1eea2d2c45eaf8521981be5e 100644 --- a/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserRegion.h +++ b/DetectorDescription/FaserDetDescr/FaserDetDescr/FaserRegion.h @@ -35,8 +35,9 @@ namespace FaserDetDescr { fFaserDipole = 4, // this means in the metal of the magnet, not the bore fFaserCalorimeter = 5, fFaserCavern = 6, + fFaserTrench = 7, // i.e. the concrete around the trench // number of defined GeoIDs - fNumFaserRegions = 7 + fNumFaserRegions = 8 }; } // end of namespace diff --git a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx index 9e8dfbb0dcf18ea616c4e35725b28cbb27e8151a..59d81a8d8006bdde022b1db76092a6f97567e85e 100644 --- a/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx +++ b/DetectorDescription/FaserDetDescr/src/FaserDetectorID.cxx @@ -42,6 +42,7 @@ FaserDetectorID::FaserDetectorID() m_CALO_ID(4), m_EMULSION_ID(1), m_VETO_ID(1), + m_VETONU_ID(4), m_TRIGGER_ID(2), m_PRESHOWER_ID(3), m_SCT_ID(1), @@ -77,6 +78,7 @@ FaserDetectorID::FaserDetectorID(const FaserDetectorID& other) m_CALO_ID (other.m_CALO_ID), m_EMULSION_ID (other.m_EMULSION_ID), m_VETO_ID (other.m_VETO_ID), + m_VETONU_ID (other.m_VETONU_ID), m_TRIGGER_ID (other.m_TRIGGER_ID), m_PRESHOWER_ID (other.m_PRESHOWER_ID), m_SCT_ID (other.m_SCT_ID), @@ -122,6 +124,7 @@ FaserDetectorID::operator= (const FaserDetectorID& other) m_VETO_ID = other.m_VETO_ID; m_TRIGGER_ID = other.m_TRIGGER_ID; m_PRESHOWER_ID = other.m_PRESHOWER_ID; + m_VETONU_ID = other.m_VETONU_ID; m_SCT_ID = other.m_SCT_ID; m_ECAL_ID = other.m_ECAL_ID; m_faser_dict = other.m_faser_dict; @@ -204,6 +207,16 @@ FaserDetectorID::veto (void) const return (result); } +Identifier +FaserDetectorID::vetonu (void) const +{ + Identifier result((Identifier::value_type)0); + // Pack field + m_det_impl.pack (scint_field_value(), result); + m_scint_part_impl.pack(m_VETONU_ID, result); + return (result); +} + Identifier FaserDetectorID::trigger (void) const { @@ -444,6 +457,16 @@ FaserDetectorID::is_veto (const ExpandedIdentifier& id) const return result; } +bool +FaserDetectorID::is_vetonu (const ExpandedIdentifier& id) const +{ + bool result = false; + if ( is_scint(id) && id.fields() > 1 ){ + if ( id[1] == m_VETONU_ID ) result = true; + } + return result; +} + bool FaserDetectorID::is_trigger (const ExpandedIdentifier& id) const { @@ -729,6 +752,7 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr) m_VETO_ID = -1; m_TRIGGER_ID = -1; m_PRESHOWER_ID = -1; + m_VETONU_ID = -1; m_SCT_ID = -1; m_ECAL_ID = -1; @@ -935,6 +959,38 @@ FaserDetectorID::initLevelsFromDict(const IdDictMgr& dict_mgr) return (1); } + label = field->find_label("VetoNu"); + if (label) { + if (label->m_valued) { + m_VETONU_ID = label->m_value; + } + else { + if(m_msgSvc) { + MsgStream log(m_msgSvc, "FaserDetectorID" ); + log << MSG::ERROR << "initLevelsFromDict - label VetoNu does NOT have a value " + << endmsg; + } + else { + std::cout << "FaserDetectorID::initLevelsFromDict - label VetoNu does NOT have a value " + << std::endl; + } + return (1); + } + } + else { + if(m_msgSvc) { + MsgStream log(m_msgSvc, "FaserDetectorID" ); + log << MSG::ERROR << "initLevelsFromDict - unable to find 'VetoNu' label " + << endmsg; + } + else { + std::cout << "FaserDetectorID::initLevelsFromDict - unable to find 'VetoNu' label " + << std::endl; + } + return (1); + } + + } // Initialize ids for Tracker diff --git a/DetectorDescription/FaserDetDescr/src/FaserRegionHelper.cxx b/DetectorDescription/FaserDetDescr/src/FaserRegionHelper.cxx index 35362e28494447026cb03495568f67bc8a1066ed..b2af1fbef778f1fc224dd09417eb90a350c6d60b 100644 --- a/DetectorDescription/FaserDetDescr/src/FaserRegionHelper.cxx +++ b/DetectorDescription/FaserDetDescr/src/FaserRegionHelper.cxx @@ -22,6 +22,7 @@ namespace FaserDetDescr { else if ( region == FaserDetDescr::fFaserCalorimeter ) return "FaserCalo"; else if ( region == FaserDetDescr::fFaserNeutrino ) return "FaserNeutrino"; else if ( region == FaserDetDescr::fFaserCavern ) return "FaserCavern"; + else if ( region == FaserDetDescr::fFaserTrench ) return "FaserTrench"; else return "UndefinedFaserRegion"; } diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.h b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.h index b64fe128eac2531f3a4c44b98dbb2e19f2f9d301..3b212bbd59e5503dd7a6f14b55cc805fb6f22bb1 100644 --- a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.h +++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.h @@ -20,10 +20,12 @@ class ScintHit; class VetoID; class TriggerID; class PreshowerID; +class VetoNuID; namespace ScintDD { class VetoDetectorManager; class TriggerDetectorManager; class PreshowerDetectorManager; + class VetoNuDetectorManager; } class GeoScintHit { @@ -41,7 +43,7 @@ class GeoScintHit { // Is this hit ok? - operator bool () const { return s_veto || s_trigger || s_preshower; } + operator bool () const { return s_veto || s_trigger || s_preshower || s_vetonu; } private: @@ -49,9 +51,11 @@ class GeoScintHit { const ScintHit *m_hit; static const ScintDD::VetoDetectorManager *s_veto; + static const ScintDD::VetoNuDetectorManager *s_vetonu; static const ScintDD::TriggerDetectorManager *s_trigger; static const ScintDD::PreshowerDetectorManager *s_preshower; static const VetoID *s_vID; + static const VetoNuID *s_vnID; static const TriggerID *s_tID; static const PreshowerID *s_pID; }; diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.icc b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.icc index 47610f91a19cded0a84bb7e6c3c955d3bf4faaa9..ad0534374be219ff4a41f944a7ebd3de52f5c090 100644 --- a/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.icc +++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/FaserGeoAdaptors/GeoScintHit.icc @@ -5,11 +5,13 @@ #include "ScintSimEvent/ScintHit.h" #include "ScintReadoutGeometry/ScintDetectorElement.h" #include "ScintReadoutGeometry/VetoDetectorManager.h" +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" #include "ScintReadoutGeometry/TriggerDetectorManager.h" #include "ScintReadoutGeometry/PreshowerDetectorManager.h" #include "StoreGate/StoreGateSvc.h" #include "StoreGate/StoreGateSvc.h" #include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/PreshowerID.h" #include "GeoPrimitives/CLHEPtoEigenConverter.h" @@ -20,12 +22,16 @@ inline void GeoScintHit::init() { if (detStore.retrieve().isSuccess()) { if(detStore->retrieve(s_veto,"Veto").isFailure()) s_veto = 0; + if(detStore->retrieve(s_vetonu,"VetoNu").isFailure()) + s_vetonu = 0; if(detStore->retrieve(s_trigger,"Trigger").isFailure()) s_trigger = 0; if(detStore->retrieve(s_preshower,"Preshower").isFailure()) s_preshower = 0; if(detStore->retrieve(s_vID,"VetoID").isFailure()) s_vID = 0; + if(detStore->retrieve(s_vnID,"VetoNuID").isFailure()) + s_vnID = 0; if(detStore->retrieve(s_tID,"TriggerID").isFailure()) s_tID = 0; if(detStore->retrieve(s_pID,"PreshowerID").isFailure()) @@ -35,7 +41,7 @@ inline void GeoScintHit::init() { inline GeoScintHit::GeoScintHit (const ScintHit & h) { m_hit = &h; - if (!s_veto || ! s_trigger || ! s_preshower ) init(); + if (!s_veto || ! s_trigger || ! s_preshower || ! s_vetonu) init(); } inline HepGeom::Point3D<double> GeoScintHit::getGlobalPosition() const { @@ -48,6 +54,11 @@ inline HepGeom::Point3D<double> GeoScintHit::getGlobalPosition() const { m_hit->getPlate()); geoelement = s_veto->getDetectorElement(id); } + else if (m_hit->isVetoNu()) { + id = s_vnID->plate_id(Station, + m_hit->getPlate()); + geoelement = s_vetonu->getDetectorElement(id); + } else if (m_hit->isTrigger()) { id = s_tID->plate_id(Station, m_hit->getPlate()); diff --git a/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx b/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx index ca6dd213cbe3a3782bbe5a45500b9a09e48eee09..ab41b1e48be0304a68b0a79e846096bbd60f2acd 100644 --- a/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx +++ b/DetectorDescription/GeoModel/FaserGeoAdaptors/src/statics.cxx @@ -9,12 +9,14 @@ const NeutrinoDD::EmulsionDetectorManager *GeoNeutrinoHit::s_emulsion = 0; const ScintDD::VetoDetectorManager *GeoScintHit::s_veto = 0; +const ScintDD::VetoNuDetectorManager *GeoScintHit::s_vetonu = 0; const ScintDD::TriggerDetectorManager *GeoScintHit::s_trigger = 0; const ScintDD::PreshowerDetectorManager *GeoScintHit::s_preshower = 0; const TrackerDD::SCT_DetectorManager *GeoFaserSiHit::s_sct; const CaloDD::EcalDetectorManager *GeoFaserCaloHit::s_ecal = 0; const EmulsionID *GeoNeutrinoHit::s_nID = 0; const VetoID *GeoScintHit::s_vID = 0; +const VetoNuID *GeoScintHit::s_vnID = 0; const TriggerID *GeoScintHit::s_tID = 0; const PreshowerID *GeoScintHit::s_pID = 0; const FaserSCT_ID *GeoFaserSiHit::s_sID = 0; diff --git a/DetectorDescription/GeoModel/FaserGeoModel/CMakeLists.txt b/DetectorDescription/GeoModel/FaserGeoModel/CMakeLists.txt index 2086d60b12f50e223aa3bf0f0230ca8717aee6c7..38a8976dafe047cce2da022e6e1cee2267ef2aad 100644 --- a/DetectorDescription/GeoModel/FaserGeoModel/CMakeLists.txt +++ b/DetectorDescription/GeoModel/FaserGeoModel/CMakeLists.txt @@ -8,17 +8,17 @@ atlas_subdir( FaserGeoModel ) if (INSTALL_GEOMDB) add_custom_command ( - OUTPUT ${CMAKE_BINARY_DIR}/data/geomDB_sqlite + OUTPUT ${CMAKE_BINARY_DIR}/data/geomDB/geomDB_sqlite DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/data/geomDB.sql - COMMAND mkdir -p ${CMAKE_BINARY_DIR}/data - COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/data/geomDB.sql | sqlite3 ${CMAKE_BINARY_DIR}/data/geomDB_sqlite + COMMAND mkdir -p ${CMAKE_BINARY_DIR}/data/geomDB + COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/data/geomDB.sql | sqlite3 ${CMAKE_BINARY_DIR}/data/geomDB/geomDB_sqlite ) - add_custom_target( geomDB ALL DEPENDS ${CMAKE_BINARY_DIR}/data/geomDB_sqlite ) + add_custom_target( geomDB ALL DEPENDS ${CMAKE_BINARY_DIR}/data/geomDB/geomDB_sqlite ) # Install the generated file: - install( FILES ${CMAKE_BINARY_DIR}/data/geomDB_sqlite - DESTINATION ${CMAKE_INSTALL_DATADIR} ) + install( FILES ${CMAKE_BINARY_DIR}/data/geomDB/geomDB_sqlite + DESTINATION ${CMAKE_INSTALL_DATADIR}/geomDB/ ) endif() # Install python files from the package: diff --git a/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql b/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql index 25673485d439d673d60366b80f62285228601f98..81a979c3cc714898a733bc15ffa8896047c0d5a9 100644 --- a/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql +++ b/DetectorDescription/GeoModel/FaserGeoModel/data/geomDB.sql @@ -144,6 +144,25 @@ CREATE TABLE IF NOT EXISTS "EMULSIONGENERAL_DATA2TAG" ( "EMULSIONGENERAL_DATA_ID" SLONGLONG ); -- +DROP TABLE IF EXISTS "EMULSIONSUPPORT_DATA"; +CREATE TABLE IF NOT EXISTS "EMULSIONSUPPORT_DATA" ( + "EMULSIONSUPPORT_DATA_ID" SLONGLONG UNIQUE, + "MATERIAL" TEXT, + "DX" DOUBLE, + "DY" DOUBLE, + "DZ" DOUBLE, + "X" DOUBLE, + "Y" DOUBLE, + "Z" DOUBLE, + "LABEL" TEXT +); +-- +DROP TABLE IF EXISTS "EMULSIONSUPPORT_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "EMULSIONSUPPORT_DATA2TAG" ( + "EMULSIONSUPPORT_TAG_ID" SLONGLONG, + "EMULSIONSUPPORT_DATA_ID" SLONGLONG +); +-- DROP TABLE IF EXISTS "EMULSIONFILM_DATA"; CREATE TABLE IF NOT EXISTS "EMULSIONFILM_DATA" ( "EMULSIONFILM_DATA_ID" SLONGLONG UNIQUE, @@ -250,6 +269,75 @@ CREATE TABLE IF NOT EXISTS "VETORADIATORGENERAL_DATA2TAG" ( "VETORADIATORGENERAL_DATA_ID" SLONGLONG ); -- +-- Tables for describing VetoNu scintillator plates (and passive radiators) +-- +DROP TABLE IF EXISTS "VETONUTOPLEVEL_DATA"; +CREATE TABLE IF NOT EXISTS "VETONUTOPLEVEL_DATA" ( + "VETONUTOPLEVEL_DATA_ID" SLONGLONG UNIQUE, + "POSX" DOUBLE, + "POSY" DOUBLE, + "POSZ" DOUBLE, + "ROTX" DOUBLE, + "ROTY" DOUBLE, + "ROTZ" DOUBLE, + "ROTORDER" INT, + "LABEL" TEXT +); +-- +-- The DATA2TAG tables associate specific rows of the corresponding +-- _DATA table with the referenced tag (from the HVS_TAG2NODE table). +-- This is a many-to-many relationship: each row may belong to +-- several tags, and each tag may apply to several rows. +DROP TABLE IF EXISTS "VETONUTOPLEVEL_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "VETONUTOPLEVEL_DATA2TAG" ( + "VETONUTOPLEVEL_TAG_ID" SLONGLONG, + "VETONUTOPLEVEL_DATA_ID" SLONGLONG +); +-- +DROP TABLE IF EXISTS "VETONUSTATIONGENERAL_DATA"; +CREATE TABLE IF NOT EXISTS "VETONUSTATIONGENERAL_DATA" ( + "VETONUSTATIONGENERAL_DATA_ID" SLONGLONG UNIQUE, + "NUMPLATES" INT, + "PLATEPITCH" DOUBLE +); +-- +DROP TABLE IF EXISTS "VETONUSTATIONGENERAL_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "VETONUSTATIONGENERAL_DATA2TAG" ( + "VETONUSTATIONGENERAL_TAG_ID" SLONGLONG, + "VETONUSTATIONGENERAL_DATA_ID" SLONGLONG +); +-- +DROP TABLE IF EXISTS "VETONUPLATEGENERAL_DATA"; +CREATE TABLE IF NOT EXISTS "VETONUPLATEGENERAL_DATA" ( + "VETONUPLATEGENERAL_DATA_ID" SLONGLONG UNIQUE, + "NUMPMTS" INT, + "WIDTH" DOUBLE, + "LENGTH" DOUBLE, + "THICKNESS" DOUBLE, + "MATERIAL" TEXT +); +-- +DROP TABLE IF EXISTS "VETONUPLATEGENERAL_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "VETONUPLATEGENERAL_DATA2TAG" ( + "VETONUPLATEGENERAL_TAG_ID" SLONGLONG, + "VETONUPLATEGENERAL_DATA_ID" SLONGLONG +); +-- +DROP TABLE IF EXISTS "VETONURADIATORGENERAL_DATA"; +CREATE TABLE IF NOT EXISTS "VETONURADIATORGENERAL_DATA" ( + "VETONURADIATORGENERAL_DATA_ID" SLONGLONG UNIQUE, + "WIDTH" DOUBLE, + "LENGTH" DOUBLE, + "THICKNESS" DOUBLE, + "MATERIAL" TEXT +); +-- +DROP TABLE IF EXISTS "VETONURADIATORGENERAL_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "VETONURADIATORGENERAL_DATA2TAG" ( + "VETONURADIATORGENERAL_TAG_ID" SLONGLONG, + "VETONURADIATORGENERAL_DATA_ID" SLONGLONG +); +-- -- Tables for describing Trigger scintillator plates (and passive radiators) -- DROP TABLE IF EXISTS "TRIGGERTOPLEVEL_DATA"; @@ -583,6 +671,22 @@ CREATE TABLE IF NOT EXISTS "VETOSWITCHES_DATA2TAG" ( "VETOSWITCHES_DATA_ID" SLONGLONG ); -- +DROP TABLE IF EXISTS "VETONUSWITCHES_DATA"; +CREATE TABLE IF NOT EXISTS "VETONUSWITCHES_DATA" ( + "VETONUSWITCHES_DATA_ID" SLONGLONG UNIQUE, + "DETECTORNAME" TEXT , + "USEMAGFIELDSVC" INT , + "COSMICLAYOUT" INT , + "VERSIONNAME" TEXT , + "LAYOUT" TEXT , + "DESCRIPTION" TEXT +); +DROP TABLE IF EXISTS "VETONUSWITCHES_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "VETONUSWITCHES_DATA2TAG" ( + "VETONUSWITCHES_TAG_ID" SLONGLONG, + "VETONUSWITCHES_DATA_ID" SLONGLONG +); +-- DROP TABLE IF EXISTS "TRIGGERSWITCHES_DATA"; CREATE TABLE IF NOT EXISTS "TRIGGERSWITCHES_DATA" ( "TRIGGERSWITCHES_DATA_ID" SLONGLONG UNIQUE, @@ -631,6 +735,24 @@ CREATE TABLE IF NOT EXISTS "ECALSWITCHES_DATA2TAG" ( "ECALSWITCHES_TAG_ID" SLONGLONG, "ECALSWITCHES_DATA_ID" SLONGLONG ); +-- +DROP TABLE IF EXISTS "TRENCHSWITCHES_DATA"; +CREATE TABLE IF NOT EXISTS "TRENCHSWITCHES_DATA" ( + "TRENCHSWITCHES_DATA_ID" SLONGLONG UNIQUE, + "DETECTORNAME" TEXT , + "USEMAGFIELDSVC" INT , + "COSMICLAYOUT" INT , + "VERSIONNAME" TEXT , + "LAYOUT" TEXT , + "DESCRIPTION" TEXT, + "GDMLFILE" TEXT +); +DROP TABLE IF EXISTS "TRENCHSWITCHES_DATA2TAG"; +CREATE TABLE IF NOT EXISTS "TRENCHSWITCHES_DATA2TAG" ( + "TRENCHSWITCHES_TAG_ID" SLONGLONG, + "TRENCHSWITCHES_DATA_ID" SLONGLONG +); + -- DROP TABLE IF EXISTS "NEUTRINOIDENTIFIER_DATA"; CREATE TABLE IF NOT EXISTS "NEUTRINOIDENTIFIER_DATA" ( @@ -689,6 +811,9 @@ CREATE TABLE IF NOT EXISTS "CALOIDENTIFIER_DATA2TAG" ( -- Data for the HVS_NODE table INSERT INTO "HVS_NODE" VALUES (0, "FASER", 0, 1, NULL); INSERT INTO "HVS_NODE" VALUES (90, "FaserCommon", 0, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (5, "Cavern", 0, 1, NULL); +INSERT INTO "HVS_NODE" VALUES (51, "Trench", 5, 1, NULL); +INSERT INTO "HVS_NODE" VALUES (514, "TrenchSwitches", 0, 0, NULL); INSERT INTO "HVS_NODE" VALUES (9000, "Materials", 0, 1, NULL); INSERT INTO "HVS_NODE" VALUES (9001, "StdMaterials", 9000, 0, NULL); INSERT INTO "HVS_NODE" VALUES (9002, "StdMatComponents", 9000, 0, NULL); @@ -703,6 +828,7 @@ INSERT INTO "HVS_NODE" VALUES (111, "EmulsionGeneral", 11, 0, NULL); INSERT INTO "HVS_NODE" VALUES (112, "EmulsionFilm", 11, 0, NULL); INSERT INTO "HVS_NODE" VALUES (113, "EmulsionPlates", 11, 0, NULL); INSERT INTO "HVS_NODE" VALUES (114, "EmulsionSwitches", 11, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (115, "EmulsionSupport", 11, 0, NULL); INSERT INTO "HVS_NODE" VALUES (2, "Scintillator", 0, 1, NULL); INSERT INTO "HVS_NODE" VALUES (2003, "ScintMaterials", 2, 0, NULL); INSERT INTO "HVS_NODE" VALUES (2004, "ScintMatComponents", 2, 0, NULL); @@ -725,6 +851,12 @@ INSERT INTO "HVS_NODE" VALUES (232, "PreshowerPlateGeneral", 23, 0, NULL); INSERT INTO "HVS_NODE" VALUES (234, "PreshowerSwitches", 23, 0, NULL ); INSERT INTO "HVS_NODE" VALUES (235, "PreshowerRadiatorGeneral", 23, 0, NULL); INSERT INTO "HVS_NODE" VALUES (236, "PreshowerAbsorberGeneral", 23, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (24, "VetoNu", 2, 1, NULL); +INSERT INTO "HVS_NODE" VALUES (240, "VetoNuTopLevel", 24, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (241, "VetoNuStationGeneral", 24, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (242, "VetoNuPlateGeneral", 24, 0, NULL); +INSERT INTO "HVS_NODE" VALUES (244, "VetoNuSwitches", 24, 0, NULL ); +INSERT INTO "HVS_NODE" VALUES (245, "VetoNuRadiatorGeneral", 24, 0, NULL); INSERT INTO "HVS_NODE" VALUES (3, "Tracker", 0, 1, NULL); INSERT INTO "HVS_NODE" VALUES (3003, "TrackerMaterials", 3, 0, NULL); INSERT INTO "HVS_NODE" VALUES (3004, "TrackerMatComponents", 3, 0, NULL); @@ -762,30 +894,40 @@ INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-CR", 107784, NULL, 0, 0, 1598400000 INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-02", 107788, NULL, 0, 0, 1619222400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASERNU-02", 107804, NULL, 0, 0, 1619308800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASER-TB00", 107834, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (0, "FASERNU-03", 107835, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (90, "FaserCommon-00", 100013, NULL, 0, 0, 1549324800000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (5, "Cavern-00", 107850, NULL, 0, 0, 1652313600000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (51, "Trench-00", 107851, NULL, 0, 0, 1652313600000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (514,"TrenchSwitches-00", 107852, NULL, 0, 0, 1652313600000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (9000, "Materials-00", 100005, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (9001, "StdMaterials-00", 100006, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (9002, "StdMatComponents-00", 100007, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (9003, "Elements-00", 100008, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (1, "Neutrino-00", 100031, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (1, "Neutrino-TB00", 107811, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (1, "Neutrino-01", 107839, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (11,"Emulsion-00", 100034, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (11,"Emulsion-TB00", 107812, NULL, 0, 0, 1582416000000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (11,"Emulsion-01", 107840, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (110, "EmulsionTopLevel-00", 100035, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (110, "EmulsionTopLevel-TB00", 107813, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (110, "EmulsionTopLevel-01", 107841, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (111, "EmulsionGeneral-00", 107805, NULL, 0, 0, 1619308800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (112, "EmulsionFilm-00", 107806, NULL, 0, 0, 1619308800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (113, "EmulsionPlates-00", 107807, NULL, 0, 0, 1619308800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (114, "EmulsionSwitches-00", 100036, NULL, 0, 0, 1582416000000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (115, "EmulsionSupport-00", 107842, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-00", 100001, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-01", 100042, NULL, 0, 0, 1590796800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-02", 107789, NULL, 0, 0, 1619222400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-TB00", 107814, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (2, "Scintillator-03", 107843, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-00", 100002, NULL, 0, 0, 1549238400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-01", 100038, NULL, 0, 0, 1590796800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-CR", 107783, NULL, 0, 0, 1598400000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-02", 107790, NULL, 0, 0, 1619222400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-TB00", 107815, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (3, "Tracker-03", 107836, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-00", 100026, NULL, 0, 0, 1567987200000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-01", 100037, NULL, 0, 0, 1159079680000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (31, "SCT-CR", 107781, NULL, 0, 0, 1598400000000000000, NULL, 22); @@ -795,6 +937,7 @@ INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-00", 100027, NULL, 0, 0, 15686784 INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-01", 100041, NULL, 0, 0, 1590796800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-02", 107792, NULL, 0, 0, 1619222400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-TB00", 107817, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (32, "Dipole-03", 107837, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-00", 106788, NULL, 0, 0, 1567987200000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-01", 106790, NULL, 0, 0, 1590796800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (310, "SctTopLevel-CR", 107786, NULL, 0, 0, 1598400000000000000, NULL, 22); @@ -816,6 +959,7 @@ INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-00", 100029, NULL, 0, 0, INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-01", 100040, NULL, 0, 0, 1590796800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-02", 107794, NULL, 0, 0, 1619222400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-TB00", 107819, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (320, "DipoleTopLevel-03", 107838, NULL, 0, 0, 1652054400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (321, "DipoleGeneral-00", 100004, NULL, 0, 0, 1568678400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (324, "DipoleSwitches-00", 100028, NULL, 0, 0, 1568678400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (4, "Calorimeter-00", 100003, NULL, 0, 0, 1549238400000000000, NULL, 22); @@ -856,6 +1000,12 @@ INSERT INTO "HVS_TAG2NODE" VALUES (231, "PreshowerStationGeneral-01", 100052, N INSERT INTO "HVS_TAG2NODE" VALUES (232, "PreshowerPlateGeneral-00", 120025, NULL, 0, 0, 1581292800000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (235, "PreshowerRadatorGeneral-00", 107808, NULL, 0, 0, 1627776000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (236, "PreshowerAbsorberGeneral-00", 107809, NULL, 0, 0, 1627776000000000000, NULL, 22); + +INSERT INTO "HVS_TAG2NODE" VALUES (240, "VetoNuTopLevel-00", 107845, NULL, 0, 0, 1652054400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (241, "VetoNuStationGeneral-00", 107846, NULL, 0, 0, 1652054400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (242, "VetoNuPlateGeneral-00", 107847, NULL, 0, 0, 1652054400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (245, "VetoNuRadiatorGeneral-00", 107849, NULL, 0, 0, 1652054400000000000, NULL, 22); + INSERT INTO "HVS_TAG2NODE" VALUES (1003, "NeutrinoMaterials-00", 100032, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (1004, "NeutrinoMatComponents-00", 100033, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2003, "ScintMaterials-00", 100011, NULL, 0, 0, 1549238400000000000, NULL, 22); @@ -867,6 +1017,7 @@ INSERT INTO "HVS_TAG2NODE" VALUES (4004, "CaloMatComponents-00", 100024, NULL, 0 INSERT INTO "HVS_TAG2NODE" VALUES (214, "VetoSwitches-00", 100014, NULL, 0, 0, 1550361600000000000 ,NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (224, "TriggerSwitches-00", 110014, NULL, 0, 0, 1581292800000000000 ,NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (234, "PreshowerSwitches-00", 120014, NULL, 0, 0, 1550361600000000000 ,NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (244, "VetoNuSwitches-00", 107848, NULL, 0, 0, 1550361600000000000 ,NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (21, "Veto-00", 100015, NULL, 0, 0, 1550448000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (22, "Trigger-00", 100019, NULL, 0, 0, 1550448000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-00", 100020, NULL, 0, 0, 1550448000000000000, NULL, 22); @@ -879,6 +1030,8 @@ INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-02", 107803, NULL, 0, 0, 16192 INSERT INTO "HVS_TAG2NODE" VALUES (21, "Veto-TB00", 107826, NULL, 0, 0, 1627862400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (22, "Trigger-TB00", 107827, NULL, 0, 0, 1627862400000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (23, "Preshower-TB00", 107828, NULL, 0, 0, 1627862400000000000, NULL, 22); +INSERT INTO "HVS_TAG2NODE" VALUES (24, "VetoNu-00", 107844, NULL, 0, 0, 1652054400000000000, NULL, 22); + INSERT INTO "HVS_TAG2NODE" VALUES (1005, "NeutrinoIdentifier-00", 100030, NULL, 0, 0, 1582416000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2005, "ScintIdentifier-00", 100016, NULL, 0, 0, 1550448000000000000, NULL, 22); INSERT INTO "HVS_TAG2NODE" VALUES (2005, "ScintIdentifier-TB00", 107832, NULL, 0, 0, 1627862400000000000, NULL, 22); @@ -890,36 +1043,51 @@ INSERT INTO "HVS_TAG2NODE" VALUES (4005, "CaloIdentifier-00", 100018, NULL, 0, 0 INSERT INTO "HVS_TAG2NODE" VALUES (4005, "CaloIdentifier-TB00", 107831, NULL, 0, 0, 1627862400000000000, NULL, 22); -- Data for the HVS_LTAG2LTAG table INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 1, 100031); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 1, 107839); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 1, 107811); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100000, 2, 100001); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100039, 2, 100042); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107784, 2, 100042); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107788, 2, 107789); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 2, 107789); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 2, 107814); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 2, 107843); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100000, 3, 100002); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100039, 3, 100038); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107784, 3, 107783); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107788, 3, 107790); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 3, 107790); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 3, 107815); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 3, 107836); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100000, 4, 100003); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100039, 4, 100003); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107784, 4, 100003); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107788, 4, 107795); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 4, 107795); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 4, 107820); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 4, 107795); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100000, 90, 100013); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100039, 90, 100013); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107788, 90, 100013); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 90, 100013); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 90, 100013); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 90, 100013); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 5, 107850); +INSERT INTO "HVS_LTAG2LTAG" VALUES (5, 107850, 51, 107851); +INSERT INTO "HVS_LTAG2LTAG" VALUES (51, 107835, 514, 107852); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100000, 9000, 100005); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 100039, 9000, 100005); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107784, 9000, 100005); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107788, 9000, 100005); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107804, 9000, 100005); INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107834, 9000, 100005); +INSERT INTO "HVS_LTAG2LTAG" VALUES (0, 107835, 9000, 100005); INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9001, 100006); INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9002, 100007); INSERT INTO "HVS_LTAG2LTAG" VALUES (9000, 100005, 9003, 100008); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 100031, 11, 100034); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107811, 11, 107812); +INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107839, 11, 107840); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 100034, 110, 100035); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 100034, 111, 107805); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 100034, 112, 107806); @@ -930,12 +1098,21 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107812, 111, 107805); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107812, 112, 107806); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107812, 113, 107807); INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107812, 114, 100036); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 110, 107841); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 111, 107805); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 112, 107806); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 113, 107807); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 114, 100036); +INSERT INTO "HVS_LTAG2LTAG" VALUES (11, 107840, 115, 107842); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 100031, 1003, 100032); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 100031, 1004, 100033); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 100031, 1005, 100030); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107811, 1003, 100032); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107811, 1004, 100033); INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107811, 1005, 100030); +INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107839, 1003, 100032); +INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107839, 1004, 100033); +INSERT INTO "HVS_LTAG2LTAG" VALUES (1, 107839, 1005, 100030); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 21, 100015); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 22, 100019); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 23, 100020); @@ -948,6 +1125,10 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107789, 23, 107803); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 21, 107826); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 22, 107827); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 23, 107828); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 21, 107801); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 22, 107802); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 23, 107803); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 24, 107844); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 2003, 100011); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 2004, 100012); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 100001, 2005, 100016); @@ -960,6 +1141,9 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107789, 2005, 100016); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 2003, 100011); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 2004, 100012); INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107814, 2005, 100016); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 2003, 100011); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 2004, 100012); +INSERT INTO "HVS_LTAG2LTAG" VALUES (2, 107843, 2005, 100016); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 100015, 210, 100009); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 100043, 210, 100046); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 107801, 210, 100046); @@ -976,6 +1160,7 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 100015, 214, 100014); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 100043, 214, 100014); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 107801, 214, 100014); INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 107826, 214, 100014); +INSERT INTO "HVS_LTAG2LTAG" VALUES (21, 107801, 215, 107810); INSERT INTO "HVS_LTAG2LTAG" VALUES (22, 100019, 220, 110009); INSERT INTO "HVS_LTAG2LTAG" VALUES (22, 100044, 220, 100047); INSERT INTO "HVS_LTAG2LTAG" VALUES (22, 107802, 220, 100047); @@ -1008,28 +1193,40 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 100020, 234, 120014); INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 100045, 234, 120014); INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 107803, 234, 120014); INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 107828, 234, 120014); +INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 107803, 235, 107808); +INSERT INTO "HVS_LTAG2LTAG" VALUES (23, 107803, 236, 107809); +INSERT INTO "HVS_LTAG2LTAG" VALUES (24, 107844, 240, 107845); +INSERT INTO "HVS_LTAG2LTAG" VALUES (24, 107844, 241, 107846); +INSERT INTO "HVS_LTAG2LTAG" VALUES (24, 107844, 242, 107847); +INSERT INTO "HVS_LTAG2LTAG" VALUES (24, 107844, 244, 107848); +INSERT INTO "HVS_LTAG2LTAG" VALUES (24, 107844, 245, 107849); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100002, 31, 100026); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100038, 31, 100037); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107783, 31, 107781); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107790, 31, 107791); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107815, 31, 107816); +INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107836, 31, 107791); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100002, 32, 100027); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100038, 32, 100041); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107790, 32, 107792); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107815, 32, 107817); +INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107836, 32, 107837); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100002, 3003, 100021); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100038, 3003, 100021); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107790, 3003, 100021); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107815, 3003, 100021); +INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107836, 3003, 100021); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100002, 3004, 100022); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100038, 3004, 100022); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107790, 3004, 100022); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107815, 3004, 100022); +INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107836, 3004, 100022); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100002, 3005, 100017); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 100038, 3005, 100017); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107781, 3005, 107785); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107790, 3005, 107787); INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107815, 3005, 107829); +INSERT INTO "HVS_LTAG2LTAG" VALUES (3, 107836, 3005, 107787); INSERT INTO "HVS_LTAG2LTAG" VALUES (31, 100026, 310, 106788); INSERT INTO "HVS_LTAG2LTAG" VALUES (31, 100037, 310, 106790); INSERT INTO "HVS_LTAG2LTAG" VALUES (31, 100081, 310, 107786); @@ -1074,14 +1271,17 @@ INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100027, 320, 100029); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100041, 320, 100040); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107792, 320, 107794); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107817, 320, 107819); +INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107837, 320, 107838); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100027, 321, 100004); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100041, 321, 100004); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107792, 321, 100004); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107817, 321, 100004); +INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107837, 321, 100004); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100027, 324, 100028); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 100041, 324, 100028); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107792, 324, 100028); INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107817, 324, 100028); +INSERT INTO "HVS_LTAG2LTAG" VALUES (32, 107837, 324, 100028); INSERT INTO "HVS_LTAG2LTAG" VALUES (4, 100003, 41, 100056); INSERT INTO "HVS_LTAG2LTAG" VALUES (4, 107795, 41, 107796); INSERT INTO "HVS_LTAG2LTAG" VALUES (4, 107820, 41, 107821); @@ -1489,6 +1689,83 @@ INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-TB00", "NeutrinoIdentifier", "Neutrino INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-TB00", "ScintIdentifier", "ScintIdentifier-TB00", 107832); INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-TB00", "TrackerIdentifier", "TrackerIdentifier-TB00", 107829); INSERT INTO "HVS_TAGCACHE" VALUES ("FASER-TB00", "CaloIdentifier", "CaloIdentifier-TB00", 107831); +-- +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "FASER", "FASERNU-03", 107835); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "FaserCommon", "FaserCommon-00", 100013); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Cavern", "Cavern-00", 107850); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Trench", "Trench-00", 107851); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TrenchSwitches", "TrenchSwitches-00", 107852); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Materials", "Materials-00", 100005); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "StdMaterials", "StdMaterials-00", 100006); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "StdMatComponents", "StdMatComponents-00", 100007); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Elements", "Elements-00", 100008); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Neutrino", "Neutrino-01", 107839); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Emulsion", "Emulsion-01", 107840); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionTopLevel", "EmulsionTopLevel-01", 107841); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionGeneral", "EmulsionGeneral-00", 107805); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionFilm", "EmulsionFilm-00", 107806); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionPlates", "EmulsionPlates-00", 107807); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionSwitches", "EmulsionSwitches-00", 100036); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EmulsionSupport", "EmulsionSupport-00", 107842); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Scintillator", "Scintillator-03", 107843); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Tracker", "Tracker-03", 107836); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SCT", "SCT-02", 107791); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctTopLevel", "SCTTopLevel-02", 107793); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctBrlModule", "SCTBrlModule-00", 107003); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctBrlSensor", "SCTBrlSensor-00", 106730); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctFaserGeneral", "SCTFaserGeneral-01", 106791); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctSwitches", "SCTSwitches-00", 107782); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SCTMaterials", "SCTMaterials-00", 107777); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SCTMatComponents", "SCTMatComponents-00", 107778); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctConditions", "SctConditions-00", 107779); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctFrame", "SctFrame-00", 100053); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctFrameGeneral", "SctFrameGeneral-00", 100054); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "SctFrameShape", "SctFrameShape-00", 100055); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Dipole", "Dipole-03", 107837); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "DipoleTopLevel", "DipoleTopLevel-03", 107838); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "DipoleGeneral", "DipoleGeneral-00", 100004); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "DipoleSwitches", "DipoleSwitches-00", 100028); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Calorimeter", "Calorimeter-02", 107795); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Ecal", "Ecal-02", 107796); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EcalTopLevel", "EcalTopLevel-02", 107797); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EcalRowGeneral", "EcalRowGeneral-00", 100059); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "EcalSwitches", "EcalSwitches-00", 100057); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoTopLevel", "VetoTopLevel-02", 107798); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoStationGeneral", "VetoStationGeneral-01", 100049); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoPlateGeneral", "VetoPlateGeneral-01", 100050); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoRadiatorGeneral", "VetoRadiatorGeneral-00", 107810); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNuTopLevel", "VetoNuTopLevel-00", 107845); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNuStationGeneral", "VetoNuStationGeneral-00", 107846); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNuPlateGeneral", "VetoNuPlateGeneral-00", 107847); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNuRadiatorGeneral","VetoNuRadiatorGeneral-00", 107849); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TriggerTopLevel", "TriggerTopLevel-02", 107799); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TriggerStationGeneral", "TriggerStationGeneral-01", 100051); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TriggerPlateGeneral", "TriggerPlateGeneral-00", 110025); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerTopLevel", "PreshowerTopLevel-02", 107800); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerStationGeneral", "PreshowerStationGeneral-01", 100052); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerPlateGeneral", "PreshowerPlateGeneral-00", 120025); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerRadiatorGeneral", "PreshowerRadiatorGeneral-00", 107808); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerAbsorberGeneral", "PreshowerAbsorberGeneral-00", 107809); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "NeutrinoMaterials", "NeutrinoMaterials-00", 100032); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "NeutrinoMatComponents", "NeutrinoMatComponents-00", 100033); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "ScintMaterials", "ScintMaterials-00", 100011); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "ScintMatComponents", "ScintMatComponents-00", 100012); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TrackerMaterials", "TrackerMaterials-00", 100021); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TrackerMatComponents", "TrackerMatComponents-00", 100022); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "CaloMaterials", "CaloMaterials-00", 100023); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "CaloMatComponents", "CaloMatComponents-00", 100024); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoSwitches", "VetoSwitches-00", 100014); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TriggerSwitches", "TriggerSwitches-00", 110014); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "PreshowerSwitches", "PreshowerSwitches-00", 120014); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNuSwitches", "VetoNuSwitches-00", 107848); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Veto", "Veto-02", 107801); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Trigger", "Trigger-02", 107802); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "Preshower", "Preshower-02", 107803); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "VetoNu", "VetoNu-00", 107844); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "NeutrinoIdentifier", "NeutrinoIdentifier-00", 100030); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "ScintIdentifier", "ScintIdentifier-00", 100016); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "TrackerIdentifier", "TrackerIdentifier-02", 107787); +INSERT INTO "HVS_TAGCACHE" VALUES ("FASERNU-03", "CaloIdentifier", "CaloIdentifier-00", 100018); -- -- -- Part 2b: Content (Leaf node) data @@ -2033,15 +2310,25 @@ INSERT INTO "ELEMENTS_DATA2TAG" VALUES (100008, 91); -- INSERT INTO "EMULSIONTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, -2475.72, 0.0, 0.0, 0.0, 321, "Emulsion"); INSERT INTO "EMULSIONTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 321, "StationA"); +INSERT INTO "EMULSIONTOPLEVEL_DATA" VALUES (2, 10.0, -21.0, -2510.27, 0.0, 0.0, 0.0, 321, "Emulsion"); INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (100035, 0); INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (100035, 1); -INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (107813, 0); +INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (107841, 2); +INSERT INTO "EMULSIONTOPLEVEL_DATA2TAG" VALUES (107841, 1); -- -- INSERT INTO "EMULSIONGENERAL_DATA" VALUES (0, 35, 22, -524.275, 525.275); INSERT INTO "EMULSIONGENERAL_DATA2TAG" VALUES (107805, 0); -- -- +INSERT INTO "EMULSIONSUPPORT_DATA" VALUES (0, "std::SSteel", 250.0, 300.0, 20.0, 0.0, 0.0, 535.45, "BoxBack"); +INSERT INTO "EMULSIONSUPPORT_DATA" VALUES (1, "std::SSteel", 250.0, 300.0, 30.0, 0.0, 0.0, -540.45, "Pusher"); +INSERT INTO "EMULSIONSUPPORT_DATA" VALUES (2, "std::SSteel", 250.0, 300.0, 20.0, 0.0, 0.0, -604.55, "BoxFront"); +INSERT INTO "EMULSIONSUPPORT_DATA2TAG" VALUES (107842, 0); +INSERT INTO "EMULSIONSUPPORT_DATA2TAG" VALUES (107842, 1); +INSERT INTO "EMULSIONSUPPORT_DATA2TAG" VALUES (107842, 2); +-- +-- INSERT INTO "EMULSIONFILM_DATA" VALUES (0, 250.0, 300.0, 0.210, "neutrino::Polystyrene", 250.0, 300.0, 0.070, "neutrino::Emulsion"); INSERT INTO "EMULSIONFILM_DATA2TAG" VALUES (107806, 0); -- @@ -2122,6 +2409,19 @@ INSERT INTO "VETORADIATORGENERAL_DATA" VALUES (0, 400.0, 350.0, 100.0, "std::Lea INSERT INTO "VETORADIATORGENERAL_DATA2TAG" VALUES (107810, 0); -- -- +INSERT INTO "VETONUTOPLEVEL_DATA" VALUES (0, 10.0, -21.0, -3112.0, 0.0, 0.0, 0.0, 321, "VetoNu"); +INSERT INTO "VETONUTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 321, "StationA"); +INSERT INTO "VETONUTOPLEVEL_DATA2TAG" VALUES (107845, 0); +INSERT INTO "VETONUTOPLEVEL_DATA2TAG" VALUES (107845, 1); +-- +INSERT INTO "VETONUSTATIONGENERAL_DATA" VALUES (0, 2, 21.0); +INSERT INTO "VETONUSTATIONGENERAL_DATA2TAG" VALUES (107846, 0); +-- +-- +INSERT INTO "VETONUPLATEGENERAL_DATA" VALUES (0, 1, 300.0, 350.0, 20.0, "scint::Scintillator"); +INSERT INTO "VETONUPLATEGENERAL_DATA2TAG" VALUES (107847, 0); +-- +-- INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (0, 0.0, 0.0, 187.0, 0.0, 0.0, 0.0, 321, "Trigger"); INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 321, "StationA"); INSERT INTO "TRIGGERTOPLEVEL_DATA" VALUES (2, 0.0, -5.0, -28.9, 0.0, 0.0, 0.0, 321, "Trigger"); @@ -2227,6 +2527,10 @@ INSERT INTO "VETOSWITCHES_DATA" VALUES (0, "Veto", 1, 0, "GEO", "Development", INSERT INTO "VETOSWITCHES_DATA2TAG" VALUES (100014, 0); -- -- +INSERT INTO "VETONUSWITCHES_DATA" VALUES (0, "VetoNu", 1, 0, "GEO", "Development", "Baseline geometry"); +INSERT INTO "VETONUSWITCHES_DATA2TAG" VALUES (107848, 0); +-- +-- INSERT INTO "TRIGGERSWITCHES_DATA" VALUES (0, "Trigger", 1, 0, "GEO", "Development", "Baseline geometry"); INSERT INTO "TRIGGERSWITCHES_DATA2TAG" VALUES (110014, 0); -- @@ -2239,6 +2543,10 @@ INSERT INTO "ECALSWITCHES_DATA" VALUES ( 0, "Ecal", 1, 0, "GEO", "Development", INSERT INTO "ECALSWITCHES_DATA2TAG" VALUES (100057, 0); -- -- +INSERT INTO "TRENCHSWITCHES_DATA" VALUES ( 0, "Trench", 1, 0, "GEO", "Development", "Baseline geometry", "TrenchGeoModel/Trench.gdml"); +INSERT INTO "TRENCHSWITCHES_DATA2TAG" VALUES (107852, 0); +-- +-- INSERT INTO "NEUTRINOIDENTIFIER_DATA" VALUES (0, "Neutrino", "NeutrinoIdDictFiles/IdDictNeutrino.xml", "Baseline layout"); INSERT INTO "NEUTRINOIDENTIFIER_DATA2TAG" VALUES (100030, 0); -- @@ -2443,6 +2751,7 @@ INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(7,0.0,0.0,-812.60,0.0,0.0,0.0,312,'Upst INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(8,0.0,0.0, 637.40,0.0,0.0,0.0,312,'CentralDipole'); INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(9,0.0,0.0,1837.40,0.0,0.0,0.0,312,'DownstreamDipole'); INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(10,0.0,0.0, 0.0,0.0,0.0,0.0,312,'Dipole'); +INSERT INTO "DIPOLETOPLEVEL_DATA" VALUES(11,0.0,0.0,-815.30,0.0,0.0,0.0,312,'UpstreamDipole'); -- shifted 2.7 mm upstream DROP TABLE IF EXISTS "DIPOLETOPLEVEL_DATA2TAG"; CREATE TABLE "DIPOLETOPLEVEL_DATA2TAG" ( "DIPOLETOPLEVEL_TAG_ID" SLONGLONG ,"DIPOLETOPLEVEL_DATA_ID" SLONGLONG ); @@ -2459,6 +2768,11 @@ INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,7); INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,8); INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107794,9); INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107819,10); +INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107838,11); +INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107838,3); +INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107838,8); +INSERT INTO "DIPOLETOPLEVEL_DATA2TAG" VALUES(107838,9); + -- -- DROP TABLE IF EXISTS "DIPOLEGENERAL_DATA"; diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py b/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py index 72e1d79a4266d82191dfef3141587dea7ac460d3..d1390bf949c6322de99495b12ba0ade905fce47e 100644 --- a/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py +++ b/DetectorDescription/GeoModel/FaserGeoModel/python/FaserGeoModelConfig.py @@ -23,4 +23,7 @@ def FaserGeometryCfg (flags): from EcalGeoModel.EcalGeoModelConfig import EcalGeometryCfg acc.merge(EcalGeometryCfg( flags )) + from FaserGeoModel.TrenchGMConfig import TrenchGeometryCfg + acc.merge(TrenchGeometryCfg( flags )) + return acc diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py b/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py index 0911c1db4ec3b16c8720abf755edf2c2568db721..af1ed16dcb630fd08948f6a648d9deb6d46756e2 100644 --- a/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py +++ b/DetectorDescription/GeoModel/FaserGeoModel/python/GeoModelInit.py @@ -47,6 +47,16 @@ def _setupGeoModel(): emulsionDetectorTool = EmulsionDetectorTool(DetectorName = "Emulsion", Alignable = True, RDBAccessSvc = "RDBAccessSvc", GeometryDBSvc = "NeutrinoGeometryDBSvc", GeoDbTagSvc = "GeoDbTagSvc") geoModelSvc.DetectorTools += [ emulsionDetectorTool ] + if "FASERNU-03" in DDversion: + from VetoNuGeoModel.VetoNuGeoModelConf import VetoNuDetectorTool + vetoNuDetectorTool = VetoNuDetectorTool( DetectorName = "VetoNu", + Alignable = True, + RDBAccessSvc = "RDBAccessSvc", + GeometryDBSvc = "ScintGeometryDBSvc", + GeoDbTagSvc = "GeoDbTagSvc") + + geoModelSvc.DetectorTools += [ vetoNuDetectorTool ] + from VetoGeoModel.VetoGeoModelConf import VetoDetectorTool vetoDetectorTool = VetoDetectorTool( DetectorName = "Veto", Alignable = True, @@ -112,6 +122,11 @@ def _setupGeoModel(): geoModelSvc.DetectorTools += [ ecalDetectorTool ] + if "FASERNU-03" in DDversion: + from TrenchGeoModel.TrenchGeoModelConf import TrenchDetectorTool + trenchDetectorTool = TrenchDetectorTool( ) + + geoModelSvc.DetectorTools += [ trenchDetectorTool ] pass diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py b/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py index 93c42c057852c8b24ac4760ea70a612941c04855..039b5155efd0d9b69278f79cd6a0cbc2fdf69ccc 100644 --- a/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py +++ b/DetectorDescription/GeoModel/FaserGeoModel/python/ScintGMConfig.py @@ -6,6 +6,10 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator def ScintGeometryCfg (flags): acc = ComponentAccumulator() + + from VetoNuGeoModel.VetoNuGeoModelConfig import VetoNuGeometryCfg + acc.merge(VetoNuGeometryCfg( flags )) + from VetoGeoModel.VetoGeoModelConfig import VetoGeometryCfg acc.merge(VetoGeometryCfg( flags )) diff --git a/DetectorDescription/GeoModel/FaserGeoModel/python/TrenchGMConfig.py b/DetectorDescription/GeoModel/FaserGeoModel/python/TrenchGMConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..b53147bcddab5129489d520f75cc01a0ae6e5f74 --- /dev/null +++ b/DetectorDescription/GeoModel/FaserGeoModel/python/TrenchGMConfig.py @@ -0,0 +1,13 @@ +# +# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +# +from AthenaConfiguration.ComponentFactory import CompFactory + +def TrenchGeometryCfg( flags ): + from FaserGeoModel.GeoModelConfig import GeoModelCfg + acc = GeoModelCfg( flags ) + + if flags.Detector.GeometryTrench: + TrenchDetectorTool=CompFactory.TrenchDetectorTool + acc.getPrimary().DetectorTools += [ TrenchDetectorTool() ] + return acc diff --git a/DetectorDescription/GeoModel/GeoModelFaserUtilities/src/DecodeFaserVersionKey.cxx b/DetectorDescription/GeoModel/GeoModelFaserUtilities/src/DecodeFaserVersionKey.cxx index a913211431b395745ecb18e14b537351ec81a7d9..010fa49563a9b8d1bd83d135d132911bb7b9f826 100644 --- a/DetectorDescription/GeoModel/GeoModelFaserUtilities/src/DecodeFaserVersionKey.cxx +++ b/DetectorDescription/GeoModel/GeoModelFaserUtilities/src/DecodeFaserVersionKey.cxx @@ -49,6 +49,9 @@ void DecodeFaserVersionKey::defineTag(const T* svc, const std::string & node) } else if (node == "Veto") { scintOverrideTag = svc->scintVersionOverride(); nodeOverrideTag = svc->vetoVersionOverride(); + } else if (node == "VetoNu") { + scintOverrideTag = svc->scintVersionOverride(); + nodeOverrideTag = svc->vetoNuVersionOverride(); } else if (node == "Trigger") { scintOverrideTag = svc->scintVersionOverride(); nodeOverrideTag = svc->triggerVersionOverride(); @@ -68,11 +71,12 @@ void DecodeFaserVersionKey::defineTag(const T* svc, const std::string & node) } else if (node == "Ecal") { caloOverrideTag = svc->caloVersionOverride(); nodeOverrideTag = svc->ecalVersionOverride(); + } else if (node == "Trench") { + nodeOverrideTag = svc->trenchVersionOverride(); } else { std::cout << "DecodeFaserVersionKey passed an unknown node:" << node << std::endl; nodeOverrideTag = ""; } - // Default to faser version m_tag = svc->faserVersion(); m_node = "FASER"; @@ -137,6 +141,7 @@ void DecodeFaserVersionKey::defineTag(const T* svc, const std::string & node) m_tag = outputTag; m_node = node; } + } const std::string & diff --git a/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoDbTagSvc.h b/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoDbTagSvc.h index ecb285ff291c3c6b7584d137f07de5d38f970c3d..9f8e103c63901d01d42283a648ca9b8e862e5396 100644 --- a/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoDbTagSvc.h +++ b/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoDbTagSvc.h @@ -32,6 +32,7 @@ class IGeoDbTagSvc : virtual public IInterface { virtual const std::string & emulsionVersion() const =0; virtual const std::string & scintVersion() const =0; virtual const std::string & vetoVersion() const =0; + virtual const std::string & vetoNuVersion() const =0; virtual const std::string & triggerVersion() const =0; virtual const std::string & preshowerVersion() const =0; virtual const std::string & trackerVersion() const =0; @@ -40,12 +41,13 @@ class IGeoDbTagSvc : virtual public IInterface { virtual const std::string & caloVersion() const =0; virtual const std::string & ecalVersion() const =0; // virtual const std::string & magFieldVersion() const =0; - // virtual const std::string & cavernInfraVersion() const =0; + virtual const std::string & trenchVersion() const =0; virtual const std::string & neutrinoVersionOverride() const =0; virtual const std::string & emulsionVersionOverride() const =0; virtual const std::string & scintVersionOverride() const =0; virtual const std::string & vetoVersionOverride() const =0; + virtual const std::string & vetoNuVersionOverride() const =0; virtual const std::string & triggerVersionOverride() const =0; virtual const std::string & preshowerVersionOverride() const =0; virtual const std::string & trackerVersionOverride() const =0; @@ -54,7 +56,7 @@ class IGeoDbTagSvc : virtual public IInterface { virtual const std::string & caloVersionOverride() const =0; virtual const std::string & ecalVersionOverride() const =0; // virtual const std::string & magFieldVersionOverride() const =0; - // virtual const std::string & cavernInfraVersionOverride() const =0; + virtual const std::string & trenchVersionOverride() const =0; virtual GeoModel::GeoConfig geoConfig() const = 0; }; diff --git a/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoModelSvc.h b/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoModelSvc.h index 2268f87fb1f490b135f04aa8ed6c9d7ccb114763..b5c7d10665f1928f2acb22dd43e4f1236dd9995e 100644 --- a/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoModelSvc.h +++ b/DetectorDescription/GeoModel/GeoModelInterfaces/GeoModelInterfaces/IGeoModelSvc.h @@ -30,6 +30,7 @@ public: virtual const std::string & emulsionVersion() const =0; virtual const std::string & scintVersion() const =0; virtual const std::string & vetoVersion() const =0; + virtual const std::string & vetoNuVersion() const =0; virtual const std::string & triggerVersion() const =0; virtual const std::string & preshowerVersion() const =0; virtual const std::string & trackerVersion() const =0; @@ -38,12 +39,13 @@ public: virtual const std::string & caloVersion() const =0; virtual const std::string & ecalVersion() const =0; // virtual const std::string & magFieldVersion() const =0; - // virtual const std::string & cavernInfraVersion() const =0; + virtual const std::string & trenchVersion() const =0; virtual const std::string & neutrinoVersionOverride() const =0; virtual const std::string & emulsionVersionOverride() const =0; virtual const std::string & scintVersionOverride() const =0; virtual const std::string & vetoVersionOverride() const =0; + virtual const std::string & vetoNuVersionOverride() const =0; virtual const std::string & triggerVersionOverride() const =0; virtual const std::string & preshowerVersionOverride() const =0; virtual const std::string & trackerVersionOverride() const =0; @@ -52,7 +54,7 @@ public: virtual const std::string & caloVersionOverride() const =0; virtual const std::string & ecalVersionOverride() const =0; // virtual const std::string & magFieldVersionOverride() const =0; - // virtual const std::string & cavernInfraVersionOverride() const =0; + virtual const std::string & trenchVersionOverride() const =0; virtual GeoModel::GeoConfig geoConfig() const = 0; diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.cxx b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.cxx index f329c0f6d3b599c5a1971cc53ad1f52331c7aba2..7c64133060caaa8bf9036f6fbacb3fff0d978a37 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.cxx +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.cxx @@ -84,6 +84,10 @@ StatusCode GeoDbTagSvc::setupTags() ? rdbAccessSvc->getChildTag("Veto", m_ScintVersion, "Scintillator", "FASERDD") : m_VetoVersionOverride); + m_VetoNuVersion = (m_VetoNuVersionOverride.empty() + ? rdbAccessSvc->getChildTag("VetoNu", m_ScintVersion, "Scintillator", "FASERDD") + : m_VetoNuVersionOverride); + m_TriggerVersion = (m_TriggerVersionOverride.empty() ? rdbAccessSvc->getChildTag("Trigger", m_ScintVersion, "Scintillator", "FASERDD") : m_TriggerVersionOverride); @@ -116,9 +120,9 @@ StatusCode GeoDbTagSvc::setupTags() // ? rdbAccessSvc->getChildTag("MagneticField",m_AtlasVersion,"ATLAS") // : m_MagFieldVersionOverride); - // m_CavernInfraVersion = (m_CavernInfraVersionOverride.empty() - // ? rdbAccessSvc->getChildTag("CavernInfra",m_AtlasVersion,"ATLAS") - // : m_CavernInfraVersionOverride); + m_TrenchVersion = (m_TrenchVersionOverride.empty() + ? rdbAccessSvc->getChildTag("Trench", m_FaserVersion,"FASERDD") + : m_TrenchVersionOverride); // Retrieve geometry config information (RUN1, RUN2, etc...) IRDBRecordset_ptr faserCommonRec = rdbAccessSvc->getRecordsetPtr("FaserCommon", m_FaserVersion, "FASER", "FASERDD"); diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.h b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.h index c7ed5637321b3e6a4124e39d40c72d8e3091a207..4fb1b0a29038b226a4955c9a9211c612defaa1bd 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.h +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoDbTagSvc.h @@ -32,6 +32,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc void setEmulsionVersionOverride(const std::string& tag) { m_EmulsionVersionOverride=tag; } void setScintVersionOverride(const std::string& tag) { m_ScintVersionOverride=tag; } void setVetoVersionOverride(const std::string& tag) { m_VetoVersionOverride=tag; } + void setVetoNuVersionOverride(const std::string& tag) { m_VetoNuVersionOverride=tag; } void setTriggerVersionOverride(const std::string& tag) { m_TriggerVersionOverride=tag; } void setPreshowerVersionOverride(const std::string& tag) { m_PreshowerVersionOverride=tag; } void setTrackerVersionOverride(const std::string& tag) { m_TrackerVersionOverride=tag; } @@ -40,7 +41,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc void setCaloVersionOverride(const std::string& tag) { m_CaloVersionOverride=tag; } void setEcalVersionOverride(const std::string& tag) { m_EcalVersionOverride=tag; } // void setMagFieldVersionOverride(const std::string& tag) { m_MagFieldVersionOverride=tag; } - // void setCavernInfraVersionOverride(const std::string& tag) { m_CavernInfraVersionOverride=tag; } + void setTrenchVersionOverride(const std::string& tag) { m_TrenchVersionOverride=tag; } StatusCode setupTags(); @@ -51,6 +52,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc const std::string & emulsionVersionOverride() const { return m_EmulsionVersionOverride; } const std::string & scintVersionOverride() const { return m_ScintVersionOverride; } const std::string & vetoVersionOverride() const { return m_VetoVersionOverride; } + const std::string & vetoNuVersionOverride() const { return m_VetoNuVersionOverride; } const std::string & triggerVersionOverride() const { return m_TriggerVersionOverride; } const std::string & preshowerVersionOverride() const { return m_PreshowerVersionOverride; } const std::string & trackerVersionOverride() const { return m_TrackerVersionOverride; } @@ -59,12 +61,13 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc const std::string & caloVersionOverride() const { return m_CaloVersionOverride; } const std::string & ecalVersionOverride() const { return m_EcalVersionOverride; } // const std::string & magFieldVersionOverride() const { return m_MagFieldVersionOverride; } - // const std::string & cavernInfraVersionOverride() const { return m_CavernInfraVersionOverride; } + const std::string & trenchVersionOverride() const { return m_TrenchVersionOverride; } const std::string & neutrinoVersion() const { return m_NeutrinoVersion; } const std::string & emulsionVersion() const { return m_EmulsionVersion; } const std::string & scintVersion() const { return m_ScintVersion; } const std::string & vetoVersion() const { return m_VetoVersion; } + const std::string & vetoNuVersion() const { return m_VetoNuVersion; } const std::string & triggerVersion() const { return m_TriggerVersion; } const std::string & preshowerVersion() const { return m_PreshowerVersion; } const std::string & trackerVersion() const { return m_TrackerVersion; } @@ -73,7 +76,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc const std::string & caloVersion() const { return m_CaloVersion; } const std::string & ecalVersion() const { return m_EcalVersion; } // const std::string & magFieldVersion() const { return m_MagFieldVersion; } - // const std::string & cavernInfraVersion() const { return m_CavernInfraVersion; } + const std::string & trenchVersion() const { return m_TrenchVersion; } GeoModel::GeoConfig geoConfig() const { return m_geoConfig; } @@ -84,6 +87,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc std::string m_EmulsionVersion; std::string m_ScintVersion; std::string m_VetoVersion; + std::string m_VetoNuVersion; std::string m_TriggerVersion; std::string m_PreshowerVersion; std::string m_TrackerVersion; @@ -92,12 +96,13 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc std::string m_CaloVersion; std::string m_EcalVersion; // std::string m_MagFieldVersion; - // std::string m_CavernInfraVersion; + std::string m_TrenchVersion; std::string m_NeutrinoVersionOverride; std::string m_EmulsionVersionOverride; std::string m_ScintVersionOverride; std::string m_VetoVersionOverride; + std::string m_VetoNuVersionOverride; std::string m_TriggerVersionOverride; std::string m_PreshowerVersionOverride; std::string m_TrackerVersionOverride; @@ -106,7 +111,7 @@ class GeoDbTagSvc : public AthService, virtual public IGeoDbTagSvc std::string m_CaloVersionOverride; std::string m_EcalVersionOverride; // std::string m_MagFieldVersionOverride; - // std::string m_CavernInfraVersionOverride; + std::string m_TrenchVersionOverride; GeoModel::GeoConfig m_geoConfig; }; diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.cxx b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.cxx index 4f728d36e0d6a1798d262c10cc4267b8f4d9089b..a1bf57b7f50e2ccf84714e96ae86b600c32ba46e 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.cxx +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.cxx @@ -56,6 +56,7 @@ GeoModelSvc::GeoModelSvc(const std::string& name,ISvcLocator* svc) declareProperty( "EmulsionVersionOverride", m_EmulsionVersionOverride); declareProperty( "ScintVersionOverride", m_ScintVersionOverride); declareProperty( "VetoVersionOverride", m_VetoVersionOverride); + declareProperty( "VetoNuVersionOverride", m_VetoNuVersionOverride); declareProperty( "TriggerVersionOverride", m_TriggerVersionOverride); declareProperty( "PreshowerVersionOverride", m_PreshowerVersionOverride); declareProperty( "TrackerVersionOverride", m_TrackerVersionOverride); @@ -64,7 +65,7 @@ GeoModelSvc::GeoModelSvc(const std::string& name,ISvcLocator* svc) declareProperty( "CaloVersionOverride", m_CaloVersionOverride); declareProperty( "EcalVersionOverride", m_EcalVersionOverride); // declareProperty( "MagFieldVersionOverride", m_MagFieldVersionOverride); - // declareProperty( "CavernInfraVersionOverride", m_CavernInfraVersionOverride); + declareProperty( "TrenchVersionOverride", m_TrenchVersionOverride); declareProperty( "AlignCallbacks", m_callBackON); declareProperty( "IgnoreTagDifference", m_ignoreTagDifference); declareProperty( "UseTagInfo", m_useTagInfo); @@ -189,6 +190,7 @@ StatusCode GeoModelSvc::geoInit() ATH_MSG_DEBUG("* Emulsion tag: " << m_EmulsionVersionOverride); ATH_MSG_DEBUG("* Scint tag: " << m_ScintVersionOverride); ATH_MSG_DEBUG("* Veto tag: " << m_VetoVersionOverride); + ATH_MSG_DEBUG("* VetoNu tag: " << m_VetoNuVersionOverride); ATH_MSG_DEBUG("* Trigger tag: " << m_TriggerVersionOverride); ATH_MSG_DEBUG("* Preshower tag: " << m_PreshowerVersionOverride); ATH_MSG_DEBUG("* Tracker tag: " << m_TrackerVersionOverride); @@ -197,7 +199,7 @@ StatusCode GeoModelSvc::geoInit() ATH_MSG_DEBUG("* Calo tag: " << m_CaloVersionOverride); ATH_MSG_DEBUG("* Ecal tag: " << m_EcalVersionOverride); // ATH_MSG_DEBUG("* MagField tag: " << m_MagFieldVersionOverride); - // ATH_MSG_DEBUG("* CavernInfra tag: " << m_CavernInfraVersionOverride); + ATH_MSG_DEBUG("* Trench tag: " << m_TrenchVersionOverride); // GetRDBAccessSvc and open connection to DB ServiceHandle<IRDBAccessSvc> rdbAccess("RDBAccessSvc",name()); @@ -261,6 +263,7 @@ StatusCode GeoModelSvc::geoInit() dbTagSvc->setEmulsionVersionOverride(m_EmulsionVersionOverride); dbTagSvc->setScintVersionOverride(m_ScintVersionOverride); dbTagSvc->setVetoVersionOverride(m_VetoVersionOverride); + dbTagSvc->setVetoNuVersionOverride(m_VetoNuVersionOverride); dbTagSvc->setTriggerVersionOverride(m_TriggerVersionOverride); dbTagSvc->setPreshowerVersionOverride(m_PreshowerVersionOverride); dbTagSvc->setTrackerVersionOverride(m_TrackerVersionOverride); @@ -269,7 +272,7 @@ StatusCode GeoModelSvc::geoInit() dbTagSvc->setCaloVersionOverride(m_CaloVersionOverride); dbTagSvc->setEcalVersionOverride(m_EcalVersionOverride); // dbTagSvc->setMagFieldVersionOverride(m_MagFieldVersionOverride); - // dbTagSvc->setCavernInfraVersionOverride(m_CavernInfraVersionOverride); + dbTagSvc->setTrenchVersionOverride(m_TrenchVersionOverride); if(dbTagSvc->setupTags().isFailure()) { ATH_MSG_FATAL("Failed to setup subsystem tags"); @@ -431,6 +434,8 @@ StatusCode GeoModelSvc::compareTags() tagsMatch = m_ScintVersionOverride == pair.second; else if(tagPairName=="GeoVeto") tagsMatch = m_VetoVersionOverride == pair.second; + else if(tagPairName=="GeoVetoNu") + tagsMatch = m_VetoNuVersionOverride == pair.second; else if(tagPairName=="GeoTrigger") tagsMatch = m_TriggerVersionOverride == pair.second; else if(tagPairName=="GeoPreshower") @@ -445,6 +450,8 @@ StatusCode GeoModelSvc::compareTags() tagsMatch = m_CaloVersionOverride == pair.second; else if(tagPairName=="GeoEcal") tagsMatch = m_EcalVersionOverride == pair.second; + else if(tagPairName=="GeoTrench") + tagsMatch = m_TrenchVersionOverride == pair.second; if(!tagsMatch) break; } @@ -458,6 +465,7 @@ StatusCode GeoModelSvc::compareTags() ATH_MSG_INFO("* Emulsion tag: " << m_EmulsionVersionOverride); ATH_MSG_INFO("* Scint tag: " << m_ScintVersionOverride); ATH_MSG_INFO("* Veto tag: " << m_VetoVersionOverride); + ATH_MSG_INFO("* VetoNu tag: " << m_VetoNuVersionOverride); ATH_MSG_INFO("* Trigger tag: " << m_TriggerVersionOverride); ATH_MSG_INFO("* Preshower tag: " << m_PreshowerVersionOverride); ATH_MSG_INFO("* Tracker tag: " << m_TrackerVersionOverride); @@ -466,7 +474,7 @@ StatusCode GeoModelSvc::compareTags() ATH_MSG_INFO("* Calo tag: " << m_CaloVersionOverride); ATH_MSG_INFO("* Ecal tag: " << m_EcalVersionOverride); // ATH_MSG_INFO("* MagField tag: " << m_MagFieldVersionOverride); - // ATH_MSG_INFO("* CavernInfra tag: " << m_CavernInfraVersionOverride); + ATH_MSG_INFO("* Trench tag: " << m_TrenchVersionOverride); ATH_MSG_INFO("** TAG INFO configuration: "); for (const auto& pair : pairs) { std::string tagPairName = pair.first; @@ -480,6 +488,8 @@ StatusCode GeoModelSvc::compareTags() ATH_MSG_INFO("*Scint tag: " << pair.second); else if(tagPairName=="GeoVeto") ATH_MSG_INFO("*Veto tag: " << pair.second); + else if(tagPairName=="GeoVetoNu") + ATH_MSG_INFO("*VetoNu tag: " << pair.second); else if(tagPairName=="GeoTrigger") ATH_MSG_INFO("*Trigger tag: " << pair.second); else if(tagPairName=="GeoPreshower") @@ -496,8 +506,8 @@ StatusCode GeoModelSvc::compareTags() ATH_MSG_INFO("*Ecal tag: " << pair.second); // else if(tagPairName=="GeoMagField") // ATH_MSG_INFO("*MagField tag: " << pair.second); - // else if(tagPairName=="GeoCavernInfra") - // ATH_MSG_INFO("*CavernInfra tag: " << pair.second); + else if(tagPairName=="GeoTrench") + ATH_MSG_INFO("*Trench tag: " << pair.second); } if(!m_ignoreTagDifference) { @@ -554,6 +564,13 @@ StatusCode GeoModelSvc::fillTagInfo() const } } + if(m_VetoNuVersionOverride != "") { + if(m_tagInfoMgr->addTag("GeoVetoNu",m_VetoNuVersionOverride).isFailure()) { + ATH_MSG_ERROR("GeoModelSvc VetoNu tag: " << m_VetoNuVersionOverride << " not added to TagInfo " ); + return StatusCode::FAILURE; + } + } + if(m_TriggerVersionOverride != "") { if(m_tagInfoMgr->addTag("GeoTrigger",m_TriggerVersionOverride).isFailure()) { ATH_MSG_ERROR("GeoModelSvc Trigger tag: " << m_TriggerVersionOverride << " not added to TagInfo " ); @@ -610,12 +627,12 @@ StatusCode GeoModelSvc::fillTagInfo() const // } // } - // if(m_CavernInfraVersionOverride != "") { - // if(m_tagInfoMgr->addTag("GeoCavernInfra",m_CavernInfraVersionOverride).isFailure()) { - // ATH_MSG_ERROR("GeoModelSvc CavernInfra tag: " << m_CavernInfraVersionOverride << " not added to TagInfo "); - // return StatusCode::FAILURE; - // } - // } + if(m_TrenchVersionOverride != "") { + if(m_tagInfoMgr->addTag("GeoTrench",m_TrenchVersionOverride).isFailure()) { + ATH_MSG_ERROR("GeoModelSvc Trench tag: " << m_TrenchVersionOverride << " not added to TagInfo "); + return StatusCode::FAILURE; + } + } return StatusCode::SUCCESS; } diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.h b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.h index e3880ced363400cb05ff949091346511d5c90c86..e40c06f9da7af23d6a20a14a95aab76f6faf5680 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.h +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/GeoModelSvc.h @@ -79,6 +79,7 @@ private: std::string m_EmulsionVersionOverride; std::string m_ScintVersionOverride; std::string m_VetoVersionOverride; + std::string m_VetoNuVersionOverride; std::string m_TriggerVersionOverride; std::string m_PreshowerVersionOverride; std::string m_TrackerVersionOverride; @@ -87,7 +88,7 @@ private: std::string m_CaloVersionOverride; std::string m_EcalVersionOverride; // std::string m_MagFieldVersionOverride; - // std::string m_CavernInfraVersionOverride; + std::string m_TrenchVersionOverride; bool m_printMaterials; // Print the contents of the Material Manager at the end of geoInit bool m_callBackON; // Register callback for Detector Tools @@ -105,6 +106,7 @@ private: const std::string & emulsionVersionOverride() const {return m_EmulsionVersionOverride; } const std::string & scintVersionOverride() const {return m_ScintVersionOverride; } const std::string & vetoVersionOverride() const {return m_VetoVersionOverride; } + const std::string & vetoNuVersionOverride() const {return m_VetoNuVersionOverride; } const std::string & triggerVersionOverride() const {return m_TriggerVersionOverride ;} const std::string & preshowerVersionOverride() const {return m_PreshowerVersionOverride ;} const std::string & trackerVersionOverride() const {return m_TrackerVersionOverride ;} @@ -113,12 +115,13 @@ private: const std::string & caloVersionOverride() const {return m_CaloVersionOverride ;} const std::string & ecalVersionOverride() const {return m_EcalVersionOverride ;} // const std::string & magFieldVersionOverride() const {return m_MagFieldVersionOverride ;} - // const std::string & cavernInfraVersionOverride() const {return m_CavernInfraVersionOverride ;} + const std::string & trenchVersionOverride() const {return m_TrenchVersionOverride ;} const std::string & neutrinoVersion() const {return m_geoDbTagSvc->neutrinoVersion(); } const std::string & emulsionVersion() const {return m_geoDbTagSvc->emulsionVersion(); } const std::string & scintVersion() const {return m_geoDbTagSvc->scintVersion(); } const std::string & vetoVersion() const {return m_geoDbTagSvc->vetoVersion(); } + const std::string & vetoNuVersion() const {return m_geoDbTagSvc->vetoNuVersion(); } const std::string & triggerVersion() const {return m_geoDbTagSvc->triggerVersion(); } const std::string & preshowerVersion() const {return m_geoDbTagSvc->preshowerVersion(); } const std::string & trackerVersion() const {return m_geoDbTagSvc->trackerVersion(); } @@ -127,7 +130,7 @@ private: const std::string & caloVersion() const {return m_geoDbTagSvc->caloVersion(); } const std::string & ecalVersion() const {return m_geoDbTagSvc->ecalVersion(); } // const std::string & magFieldVersion() const {return m_geoDbTagSvc->magFieldVersion(); } - // const std::string & cavernInfraVersion() const {return m_geoDbTagSvc->cavernInfraVersion(); } + const std::string & trenchVersion() const {return m_geoDbTagSvc->trenchVersion(); } GeoModel::GeoConfig geoConfig() const {return m_geoDbTagSvc->geoConfig();} diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx b/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx index dd440226fdff6abfc3e609d4f705e92884edd61e..988191de12501bf2105e9045baa3e468d234a0f5 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx @@ -215,35 +215,37 @@ StatusCode RDBMaterialManager::readMaterialsFromDB(ISvcLocator* pSvcLocator) log << MSG::WARNING << " Getting SCTMaterials with default tag" <<endmsg; m_trackermaterials = iAccessSvc->getRecordsetPtr("SCTMaterials","SCTMaterials-00", "", "FASERDD"); } + // TrackerMatComponents and TrackerMaterials tables in DB are empty // --- Tracker materials - DecodeFaserVersionKey keyTracker(iGeoModel, "Tracker"); - m_trackermatcomponents = iAccessSvc->getRecordsetPtr("TrackerMatComponents",keyTracker.tag(),keyTracker.node(),"FASERDD"); - if(m_trackermatcomponents->size()==0) { - if(log.level()<=MSG::WARNING) - log << MSG::WARNING << " Getting TrackerMatComponents with default tag" <<endmsg; - m_trackermatcomponents = iAccessSvc->getRecordsetPtr("TrackerMatComponents","TrackerMatComponents-00", "", "FASERDD"); - } - m_trackermaterials = iAccessSvc->getRecordsetPtr("TrackerMaterials",keyTracker.tag(),keyTracker.node(), "FASERDD"); - if(m_trackermaterials->size()==0) { - if(log.level()<=MSG::WARNING) - log << MSG::WARNING << " Getting TrackerMaterials with default tag" <<endmsg; - m_trackermaterials = iAccessSvc->getRecordsetPtr("TrackerMaterials","TrackerMaterials-00", "", "FASERDD"); - } - - // --- Tracker materials - DecodeFaserVersionKey keyCalorimeter(iGeoModel, "Calorimeter"); - m_calomatcomponents = iAccessSvc->getRecordsetPtr("CaloMatComponents",keyCalorimeter.tag(),keyCalorimeter.node(),"FASERDD"); - if(m_calomatcomponents->size()==0) { - if(log.level()<=MSG::WARNING) - log << MSG::WARNING << " Getting CaloMatComponents with default tag" <<endmsg; - m_calomatcomponents = iAccessSvc->getRecordsetPtr("CaloMatComponents","CaloMatComponents-00", "", "FASERDD"); - } - m_calomaterials = iAccessSvc->getRecordsetPtr("CaloMaterials",keyCalorimeter.tag(),keyCalorimeter.node(), "FASERDD"); - if(m_calomaterials->size()==0) { - if(log.level()<=MSG::WARNING) - log << MSG::WARNING << " Getting CaloMaterials with default tag" <<endmsg; - m_calomaterials = iAccessSvc->getRecordsetPtr("CaloMaterials","CaloMaterials-00", "", "FASERDD"); - } + // DecodeFaserVersionKey keyTracker(iGeoModel, "Tracker"); + // m_trackermatcomponents = iAccessSvc->getRecordsetPtr("TrackerMatComponents",keyTracker.tag(),keyTracker.node(),"FASERDD"); + // if(m_trackermatcomponents->size()==0) { + // if(log.level()<=MSG::WARNING) + // log << MSG::WARNING << " Getting TrackerMatComponents with default tag" <<endmsg; + // m_trackermatcomponents = iAccessSvc->getRecordsetPtr("TrackerMatComponents","TrackerMatComponents-00", "", "FASERDD"); + // } + // m_trackermaterials = iAccessSvc->getRecordsetPtr("TrackerMaterials",keyTracker.tag(),keyTracker.node(), "FASERDD"); + // if(m_trackermaterials->size()==0) { + // if(log.level()<=MSG::WARNING) + // log << MSG::WARNING << " Getting TrackerMaterials with default tag" <<endmsg; + // m_trackermaterials = iAccessSvc->getRecordsetPtr("TrackerMaterials","TrackerMaterials-00", "", "FASERDD"); + // } + + // CaloMatComponents and CaloMaterials tables are also empty + // // --- Calorimeter materials + // DecodeFaserVersionKey keyCalorimeter(iGeoModel, "Calorimeter"); + // m_calomatcomponents = iAccessSvc->getRecordsetPtr("CaloMatComponents",keyCalorimeter.tag(),keyCalorimeter.node(),"FASERDD"); + // if(m_calomatcomponents->size()==0) { + // if(log.level()<=MSG::WARNING) + // log << MSG::WARNING << " Getting CaloMatComponents with default tag" <<endmsg; + // m_calomatcomponents = iAccessSvc->getRecordsetPtr("CaloMatComponents","CaloMatComponents-00", "", "FASERDD"); + // } + // m_calomaterials = iAccessSvc->getRecordsetPtr("CaloMaterials",keyCalorimeter.tag(),keyCalorimeter.node(), "FASERDD"); + // if(m_calomaterials->size()==0) { + // if(log.level()<=MSG::WARNING) + // log << MSG::WARNING << " Getting CaloMaterials with default tag" <<endmsg; + // m_calomaterials = iAccessSvc->getRecordsetPtr("CaloMaterials","CaloMaterials-00", "", "FASERDD"); + // } return StatusCode::SUCCESS; } diff --git a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py index 3a50a75d55c0c2a1e06d6edfa6d900722d5a83c1..3a87cc4c75388ff53954f9a75be77b9c5d1dc9cd 100644 --- a/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py +++ b/Event/FaserByteStreamCnvSvcBase/python/FaserByteStreamCnvSvcBaseConfig.py @@ -15,6 +15,7 @@ def FaserByteStreamCnvSvcBaseCfg(flags, **kwargs): adxProvider.TypeNames += [ "RawWaveformContainer/CaloWaveforms", "RawWaveformContainer/VetoWaveforms", + "RawWaveformContainer/VetoNuWaveforms", "RawWaveformContainer/TriggerWaveforms", "RawWaveformContainer/PreshowerWaveforms", "RawWaveformContainer/ClockWaveforms", diff --git a/FaserGeometryCommon/TrenchGeoModel/CMakeLists.txt b/FaserGeometryCommon/TrenchGeoModel/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..041a00338e4f25ed8b0e27a1077571fbf23a342f --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/CMakeLists.txt @@ -0,0 +1,35 @@ +################################################################################ +# Package: TrenchGeoModel +################################################################################ + +# Declare the package name: +atlas_subdir( TrenchGeoModel ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( Eigen ) +find_package( GeoModel COMPONENTS GeoModelKernel GeoModelDBManager GDMLtoGM ) +find_package( XercesC ) + +# Component(s) in the package: +atlas_add_component( TrenchGeoModel + src/*.cxx + src/components/*.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${GEOMODEL_INCLUDE_DIR} ${XERCESC_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${GEOMODEL_LIBRARIES} ${XERCESC_LIBRARIES} AthenaKernel GeoModelFaserUtilities GaudiKernel + StoreGateLib GeoModelInterfaces RDBAccessSvcLib PathResolver) + +add_custom_command (OUTPUT ${CMAKE_XML_OUTPUT_DIRECTORY}/TrenchGeoModel/Trench.gdml + COMMAND mkdir -p ${CMAKE_XML_OUTPUT_DIRECTORY}/TrenchGeoModel/ + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/data/Trench.gdml ${CMAKE_XML_OUTPUT_DIRECTORY}/TrenchGeoModel/Trench.gdml ) +add_custom_target (make_cavern_gdml ALL DEPENDS ${CMAKE_XML_OUTPUT_DIRECTORY}/TrenchGeoModel/Trench.gdml) +get_filename_component( _realpath ${CMAKE_CURRENT_SOURCE_DIR}/data/Trench.gdml REALPATH ) + +install(FILES ${_realpath} DESTINATION ${CMAKE_INSTALL_PREFIX}/XML/TrenchGeoModel RENAME Trench.gdml) +unset( _realpath ) + +# Install files from the package: +#atlas_install_python_modules( python/*.py ) +#atlas_install_scripts( test/*.py ) +# Not needed as done with symlink above +#atlas_install_xmls( data/*.gdml ) diff --git a/FaserGeometryCommon/TrenchGeoModel/data/Trench.gdml b/FaserGeometryCommon/TrenchGeoModel/data/Trench.gdml new file mode 100644 index 0000000000000000000000000000000000000000..476363b731343f73f515a5f207714252772571df --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/data/Trench.gdml @@ -0,0 +1,248 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gdml xsi:noNamespaceSchemaLocation="schema/gdml.xsd"> + <define> + <position name="RampinWorldpos" unit="mm" x="576.9" y="-177.6" z="-598.8"/> + <rotation name="RampinWorldrot" unit="deg" z="0" y="-9.50625" x="0.711918"/> + <position name="Subpos" unit="mm" x="-668.4" y="245.1" z="498.3" /> + <rotation name="Subrot" unit="deg" x="90.7119" y="-9.50625" z="0" /> + <constant name="WorldSize" value="20000"/> + <constant name="RampWidth" value="7000"/> + <constant name="RampLengthZ" value="8422"/> + <constant name="RampMinThickness" value="2000"/> + <constant name="RampSlope" value="0.08533"/> + </define> + <materials> + <isotope N="1.400000000000000e+01" Z="7.000000000000000e+00" name="N140x8e46440"> + <atom unit="g/mole" value="1.400310000000000e+01"/> + </isotope> + <isotope N="1.500000000000000e+01" Z="7.000000000000000e+00" name="N150x8e48da0"> + <atom unit="g/mole" value="1.500010000000000e+01"/> + </isotope> + <element name="N0x8e48c30"> + <fraction n="9.963200000000001e-01" ref="N140x8e46440"/> + <fraction n="3.680000000000000e-03" ref="N150x8e48da0"/> + </element> + <isotope N="1.600000000000000e+01" Z="8.000000000000000e+00" name="O160x1167b880"> + <atom unit="g/mole" value="1.599490000000000e+01"/> + </isotope> + <isotope N="1.700000000000000e+01" Z="8.000000000000000e+00" name="O170x1167b7d0"> + <atom unit="g/mole" value="1.699909999999999e+01"/> + </isotope> + <isotope N="1.800000000000000e+01" Z="8.000000000000000e+00" name="O180xfb79770"> + <atom unit="g/mole" value="1.799920000000000e+01"/> + </isotope> + <element name="O0x1167b4f0"> + <fraction n="9.975700000000000e-01" ref="O160x1167b880"/> + <fraction n="3.800000000000000e-04" ref="O170x1167b7d0"/> + <fraction n="2.050000000000000e-03" ref="O180xfb79770"/> + </element> + <isotope N="2.800000000000000e+01" Z="1.400000000000000e+01" name="Si280x8146230"> + <atom unit="g/mole" value="2.797690000000000e+01"/> + </isotope> + <isotope N="2.900000000000000e+01" Z="1.400000000000000e+01" name="Si290x8146280"> + <atom unit="g/mole" value="2.897650000000000e+01"/> + </isotope> + <isotope N="3.000000000000000e+01" Z="1.400000000000000e+01" name="Si300x8146e50"> + <atom unit="g/mole" value="2.997380000000000e+01"/> + </isotope> + <element name="Si0x8147580"> + <fraction n="9.222960777039223e-01" ref="Si280x8146230"/> + <fraction n="4.683195316804684e-02" ref="Si290x8146280"/> + <fraction n="3.087196912803088e-02" ref="Si300x8146e50"/> + </element> + <isotope N="4.000000000000000e+01" Z="2.000000000000000e+01" name="Ca400xee155f0"> + <atom unit="g/mole" value="3.996260000000000e+01"/> + </isotope> + <isotope N="4.200000000000000e+01" Z="2.000000000000000e+01" name="Ca420xee15640"> + <atom unit="g/mole" value="4.195860000000000e+01"/> + </isotope> + <isotope N="4.300000000000000e+01" Z="2.000000000000000e+01" name="Ca430xee15690"> + <atom unit="g/mole" value="4.295880000000000e+01"/> + </isotope> + <isotope N="4.400000000000000e+01" Z="2.000000000000000e+01" name="Ca440xee156e0"> + <atom unit="g/mole" value="4.395550000000001e+01"/> + </isotope> + <isotope N="4.600000000000000e+01" Z="2.000000000000000e+01" name="Ca460xee15730"> + <atom unit="g/mole" value="4.595370000000000e+01"/> + </isotope> + <isotope N="4.800000000000000e+01" Z="2.000000000000000e+01" name="Ca480xee15780"> + <atom unit="g/mole" value="4.795250000000000e+01"/> + </isotope> + <element name="Ca0xee154a0"> + <fraction n="9.694100000000000e-01" ref="Ca400xee155f0"/> + <fraction n="6.470000000000000e-03" ref="Ca420xee15640"/> + <fraction n="1.350000000000000e-03" ref="Ca430xee15690"/> + <fraction n="2.086000000000000e-02" ref="Ca440xee156e0"/> + <fraction n="4.000000000000000e-05" ref="Ca460xee15730"/> + <fraction n="1.870000000000000e-03" ref="Ca480xee15780"/> + </element> + <isotope N="2.300000000000000e+01" Z="1.100000000000000e+01" name="Na230x9095660"> + <atom unit="g/mole" value="2.298980000000000e+01"/> + </isotope> + <element name="Na0x90954f0"> + <fraction n="1.000000000000000e+00" ref="Na230x9095660"/> + </element> + <isotope N="5.400000000000000e+01" Z="2.600000000000000e+01" name="Fe540x11685b60"> + <atom unit="g/mole" value="5.393959999999999e+01"/> + </isotope> + <isotope N="5.600000000000000e+01" Z="2.600000000000000e+01" name="Fe560x11685bb0"> + <atom unit="g/mole" value="5.593490000000000e+01"/> + </isotope> + <isotope N="5.700000000000000e+01" Z="2.600000000000000e+01" name="Fe570x11685c00"> + <atom unit="g/mole" value="5.693540000000000e+01"/> + </isotope> + <isotope N="5.800000000000000e+01" Z="2.600000000000000e+01" name="Fe580x11685c50"> + <atom unit="g/mole" value="5.793330000000000e+01"/> + </isotope> + <element name="Fe0x116859d0"> + <fraction n="5.845000000000000e-02" ref="Fe540x11685b60"/> + <fraction n="9.175400000000000e-01" ref="Fe560x11685bb0"/> + <fraction n="2.119000000000000e-02" ref="Fe570x11685c00"/> + <fraction n="2.820000000000000e-03" ref="Fe580x11685c50"/> + </element> + <isotope N="2.700000000000000e+01" Z="1.300000000000000e+01" name="Al270x116850d0"> + <atom unit="g/mole" value="2.698150000000000e+01"/> + </isotope> + <element name="Al0x11684f90"> + <fraction n="1.000000000000000e+00" ref="Al270x116850d0"/> + </element> + <isotope N="1.200000000000000e+01" Z="6.000000000000000e+00" name="C120x8147220"> + <atom unit="g/mole" value="1.200000000000000e+01"/> + </isotope> + <isotope N="1.300000000000000e+01" Z="6.000000000000000e+00" name="C130x8147270"> + <atom unit="g/mole" value="1.300340000000000e+01"/> + </isotope> + <element name="C0x81470c0"> + <fraction n="9.893000000000001e-01" ref="C120x8147220"/> + <fraction n="1.070000000000000e-02" ref="C130x8147270"/> + </element> + <isotope N="3.900000000000000e+01" Z="1.900000000000000e+01" name="K390x89fe1c0"> + <atom unit="g/mole" value="3.896370000000000e+01"/> + </isotope> + <isotope N="4.000000000000000e+01" Z="1.900000000000000e+01" name="K400x89fe210"> + <atom unit="g/mole" value="3.996400000000000e+01"/> + </isotope> + <isotope N="4.100000000000000e+01" Z="1.900000000000000e+01" name="K410x89fe260"> + <atom unit="g/mole" value="4.096180000000000e+01"/> + </isotope> + <element name="K0x89fe020"> + <fraction n="9.325810000000000e-01" ref="K390x89fe1c0"/> + <fraction n="1.170000000000000e-04" ref="K400x89fe210"/> + <fraction n="6.730200000000000e-02" ref="K410x89fe260"/> + </element> + <isotope N="1.000000000000000e+00" Z="1.000000000000000e+00" name="H10x8e31ab0"> + <atom unit="g/mole" value="1.007825030813723e+00"/> + </isotope> + <isotope N="2.000000000000000e+00" Z="1.000000000000000e+00" name="H20x8e31b00"> + <atom unit="g/mole" value="2.014101999666174e+00"/> + </isotope> + <element name="H0x8e31950"> + <fraction n="9.998850000000000e-01" ref="H10x8e31ab0"/> + <fraction n="1.150000000000000e-04" ref="H20x8e31b00"/> + </element> + <isotope N="36" Z="18" name="Ar36Faser"> + <atom unit="g/mole" value="35.967545105"/> + </isotope> + <isotope N="38" Z="18" name="Ar38Faser"> + <atom unit="g/mole" value="37.96273210"/> + </isotope> + <isotope N="40" Z="18" name="Ar40Faser"> + <atom unit="g/mole" value="39.9623831238"/> + </isotope> + <element name="ArgonFaser"> + <fraction n="0.996035" ref="Ar40Faser"/> + <fraction n="0.000629" ref="Ar38Faser"/> + <fraction n="0.003336" ref="Ar36Faser"/> + </element> + <!-- + <material name="Concrete" state="solid"> + <MEE unit="eV" value="1.271741855079048e+02"/> + <D unit="g/cm3" value="2.499998684602534e+00"/> + <fraction n="5.306122448979591e-01" ref="O0x1167b4f0"/> + <fraction n="3.316326530612245e-01" ref="Si0x8147580"/> + <fraction n="6.122448979591836e-02" ref="Ca0xee154a0"/> + <fraction n="1.530612244897959e-02" ref="Na0x90954f0"/> + <fraction n="2.040816326530612e-02" ref="Fe0x116859d0"/> + <fraction n="4.081632653061224e-02" ref="Al0x11684f90"/> + </material> + --> + <!-- Concrete and Air composition taken from ATLAS; elements/isotopes taken from LHCb --> + <material name="Concrete" state="solid"> + <MEE unit="eV" value="1.271741855079048e+02"/> + <D unit="g/cm3" value="2.4e+00"/> + <fraction n="0.5" ref="O0x1167b4f0"/> + <fraction n="0.2" ref="Si0x8147580"/> + <fraction n="0.2" ref="Ca0xee154a0"/> + <fraction n="0.01" ref="Na0x90954f0"/> + <fraction n="0.014" ref="Fe0x116859d0"/> + <fraction n="0.03" ref="Al0x11684f90"/> + <fraction n="0.03" ref="C0x81470c0"/> + <fraction n="0.01" ref="K0x89fe020"/> + <fraction n="0.006" ref="H0x8e31950"/> + </material> + <material name="Air" state="gas"> + <T unit="K" value="2.930000000000000e+02"/> + <MEE unit="eV" value="8.570323231865051e+01"/> + <D unit="g/cm3" value="1.214e-03"/> + <fraction n="0.7494" ref="N0x8e48c30"/> + <fraction n="0.2369" ref="O0x1167b4f0"/> + <fraction n="0.0129" ref="ArgonFaser"/> + <fraction n="0.0008" ref="H0x8e31950"/> + </material> + </materials> + <solids> + <arb8 name="ramp" lunit="mm" + v1x="-RampWidth/2" v1y="-RampMinThickness" v2x="RampWidth/2" v2y="-RampMinThickness" v3x="RampWidth/2" v3y="RampSlope*RampLengthZ" v4x="-RampWidth/2" v4y="RampSlope*RampLengthZ" + v5x="-RampWidth/2" v5y="-RampMinThickness" v6x="RampWidth/2" v6y="-RampMinThickness" v7x="RampWidth/2" v7y="0" v8x="-RampWidth/2" v8y="0" + dz="RampLengthZ/2" /> + <box name="world" lunit="mm" x="WorldSize" y="WorldSize" z="WorldSize" /> + <xtru name="trenchOutline" lunit="mm"> + <twoDimVertex x="-249.75647241976003" y="-3162.7618497323056"/> + <twoDimVertex x="436.065806982358" y="-3162.7608114181166"/> + <twoDimVertex x="750.3626731862572" y="-1286.045959074479"/> + <twoDimVertex x="750.4059394616982" y="-604.5461685406792"/> + <twoDimVertex x="750.6632036024528" y="3447.692178833775"/> + <twoDimVertex x="598.5775838786217" y="3447.7018373451183"/> + <twoDimVertex x="-251.25127807309354" y="3447.755796000657"/> + <twoDimVertex x="-624.2972688145043" y="1219.150232226327"/> + <twoDimVertex x="-659.4916199548085" y="1008.9993568866641"/> + <twoDimVertex x="-659.5757293651513" y="-315.8326195671569"/> + <twoDimVertex x="-659.6885336897632" y="-2092.6465942800164"/> + <twoDimVertex x="-249.68853582392614" y="-2092.672626612777"/> + <section zOrder="0" zPosition="-375.0" xOffset="0" yOffset="0" scalingFactor="1" /> + <section zOrder="1" zPosition="375.0" xOffset="0" yOffset="0" scalingFactor="1" /> + </xtru> + <subtraction name="faserTrench"> + <first ref="ramp"/> + <firstpositionref ref="RampinWorldpos"/> + <firstrotationref ref="RampinWorldrot"/> + <second ref="trenchOutline"/> + <!-- + <rotationref ref="Subrot"/> + <positionref ref="Subpos"/> + --> + <rotation name="Xrotation" unit="deg" x="90"/> + <position name="Yshift" unit="mm" y="75"/> + </subtraction> + </solids> + <structure> + <volume name="Trench"> + <solidref ref="faserTrench"/> + <materialref ref="Concrete"/> + </volume> + <volume name="World" > + <materialref ref="Air" /> + <solidref ref="world" /> + <physvol> + <volumeref ref="Trench" /> + <!-- + <rotationref ref="RampinWorldrot"/> + <positionref ref="RampinWorldpos"/> + --> + </physvol> + </volume> + </structure> + <setup name="Default" version="1.0" > + <world ref="World" /> + </setup> +</gdml> \ No newline at end of file diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.cxx b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..da787acdfc58391b7cd3f68b00b7aae5f1055a91 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.cxx @@ -0,0 +1,99 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TrenchDetectorFactory.h" + +#include "GeoModelXMLParser/XercesParser.h" +#include "PathResolver/PathResolver.h" + + +#include "GeoModelKernel/GeoLogVol.h" +#include "GeoModelKernel/GeoNameTag.h" +#include "GeoModelKernel/GeoPhysVol.h" +#include "StoreGate/StoreGateSvc.h" + + +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "RDBAccessSvc/IRDBAccessSvc.h" + +#include "GaudiKernel/MsgStream.h" + +#include <string> +#include <map> + +TrenchDetectorFactory::TrenchDetectorFactory(StoreGateSvc *detStore, + IRDBAccessSvc *pAccess) + :m_detectorManager(NULL), + m_detectorStore(detStore), + m_access(pAccess) +{ +} + +TrenchDetectorFactory::~TrenchDetectorFactory() +{ +} + +void TrenchDetectorFactory::create(GeoPhysVol *world) +{ + m_detectorManager=new TrenchDetectorManager(); + + std::string gdmlFile; + IRDBRecordset_ptr switchSet{m_access->getRecordsetPtr("TrenchSwitches", m_versionTag, m_versionNode, "FASERDD")}; + if (!switchSet || switchSet->size() == 0) + { + MsgStream gLog(Athena::getMessageSvc(), "TrenchDetectorFactory"); + gLog << MSG::WARNING << "Unable to retrieve switches; Trench cannot be created" << endmsg; + return; + } + const IRDBRecord* switches{(*switchSet)[0]}; + if (not switches->isFieldNull("GDMLFILE") && gdmlFile.empty()) + { + gdmlFile = switches->getString("GDMLFILE"); + } + if (gdmlFile.empty()) + { + MsgStream gLog(Athena::getMessageSvc(), "TrenchDetectorFactory"); + gLog << MSG::WARNING << "GDML file name not found; Trench cannot be created" << endmsg; + return; + } + + std::string resolvedFile = PathResolver::find_file(gdmlFile, "XMLPATH", PathResolver::RecursiveSearch); + + auto store = XMLHandlerStore::GetHandlerStore(); + // for (auto p : *store) + // { + // delete p.second; + // } + store->clear(); + + GDMLController controller {"TrenchGDMLController"}; + + // std::cout << "creating parser" << std::endl; + XercesParser xercesParser; + + // std::cout << "parsing " << resolvedFile << std::endl; + xercesParser.ParseFileAndNavigate(resolvedFile); + // std::cout << "done parsing " << resolvedFile << std::endl; + + const GeoLogVol* trenchLog = controller.retrieveLogicalVolume("Trench").first; + GeoPhysVol* trenchPhys = new GeoPhysVol(trenchLog); + GeoNameTag *tag = new GeoNameTag("Trench"); + world->add(tag); + world->add(trenchPhys); + m_detectorManager->addTreeTop(trenchPhys); +} + +const TrenchDetectorManager * TrenchDetectorFactory::getDetectorManager() const +{ + return m_detectorManager; +} + +void TrenchDetectorFactory::setTagNode(const std::string& tag, + const std::string& node) +{ + m_versionTag = tag; + m_versionNode = node; +} + diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.h b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..14cdbaa18bdc8cc941fb894c9085298ec4191f38 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorFactory.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TrenchDetectorFactory_h +#define TrenchDetectorFactory_h 1 + +#include "GeoModelKernel/GeoVDetectorFactory.h" +#include "TrenchDetectorManager.h" +#include "RDBAccessSvc/IRDBAccessSvc.h" +#include "GDMLInterface/GDMLController.h" + +#include <string> + +class StoreGateSvc; + +class TrenchDetectorFactory : public GeoVDetectorFactory +{ + + public: + + // Constructor: + TrenchDetectorFactory(StoreGateSvc *pDetStore, + IRDBAccessSvc *pAccess); + + // Destructor: + ~TrenchDetectorFactory(); + + // Creation of geometry: + virtual void create(GeoPhysVol *world); + + // Access to the results: + virtual const TrenchDetectorManager * getDetectorManager() const; + + // Set version Tag and Node + void setTagNode(const std::string& tag, const std::string& node); + + + private: + // Illegal operations: + const TrenchDetectorFactory & operator=(const TrenchDetectorFactory &right); + TrenchDetectorFactory(const TrenchDetectorFactory &right); + + // The manager: + TrenchDetectorManager *m_detectorManager; + + StoreGateSvc *m_detectorStore; + IRDBAccessSvc *m_access; + std::string m_versionTag; + std::string m_versionNode; + +// GDMLController m_controller {"TrenchGDMLController"}; + +}; + +// Class TrenchDetectorFactory +#endif + + diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.cxx b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f8df3b923f9a316af0d237285090ca34ba1107a1 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TrenchDetectorManager.h" + +TrenchDetectorManager::TrenchDetectorManager() +{ + setName("Trench"); +} + + +TrenchDetectorManager::~TrenchDetectorManager() +{ + for(unsigned int i=0; i<m_treeTops.size(); i++) + m_treeTops[i]->unref(); +} + + +unsigned int TrenchDetectorManager::getNumTreeTops() const +{ + return m_treeTops.size(); +} + +PVConstLink TrenchDetectorManager::getTreeTop(unsigned int i) const +{ + if(i<m_treeTops.size()) + return m_treeTops[i]; + else + return 0; +} + +void TrenchDetectorManager::addTreeTop(PVLink link) +{ + link->ref(); + m_treeTops.push_back(link); +} + diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.h b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.h new file mode 100644 index 0000000000000000000000000000000000000000..87ea3d0c258b7afa5d7255f8b4fa521c5f072883 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorManager.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TrenchDetectorManager_h +#define TrenchDetectorManager_h 1 + +#include "GeoModelKernel/GeoVPhysVol.h" +#include "GeoModelKernel/GeoVDetectorManager.h" +#include <vector> + +class TrenchDetectorManager : public GeoVDetectorManager +{ + public: + + // Constructor + TrenchDetectorManager(); + + // Destructor + ~TrenchDetectorManager(); + + // Access to raw geometry: + virtual unsigned int getNumTreeTops() const; + virtual PVConstLink getTreeTop(unsigned int i) const; + + void addTreeTop(PVLink); // Add a Tree top: + + private: + + const TrenchDetectorManager & operator=(const TrenchDetectorManager &right); + TrenchDetectorManager(const TrenchDetectorManager &right); + + // Tree Tops + std::vector<PVLink> m_treeTops; +}; + +#ifndef GAUDI_NEUTRAL +#include "AthenaKernel/CLASS_DEF.h" +CLASS_DEF(TrenchDetectorManager, 124400828, 1) +#endif + +#endif + + diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.cxx b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c036496ea42cef602db10a0190367d97ff25e3a3 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.cxx @@ -0,0 +1,104 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TrenchDetectorTool.h" +#include "TrenchDetectorFactory.h" +#include "TrenchDetectorManager.h" + +#include "GeoModelInterfaces/IGeoDbTagSvc.h" +#include "GeoModelFaserUtilities/GeoModelExperiment.h" +#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h" +#include "RDBAccessSvc/IRDBAccessSvc.h" +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" + +#include "boost/algorithm/string/predicate.hpp" + +TrenchDetectorTool::TrenchDetectorTool( const std::string& type, + const std::string& name, + const IInterface* parent ) + : GeoModelTool( type, name, parent ), + m_manager(0) +{ +} + +TrenchDetectorTool::~TrenchDetectorTool() +{ +} + + +StatusCode TrenchDetectorTool::create() +{ + IGeoDbTagSvc *geoDbTag; + StatusCode sc = service ("GeoDbTagSvc",geoDbTag); + if(sc.isFailure()) { + msg(MSG::ERROR) << "Could not locate GeoDbTagSvc" << endmsg; + return sc; + } + + IRDBAccessSvc* raccess = 0; + sc = service("RDBAccessSvc",raccess); + if(sc.isFailure()) { + msg(MSG::ERROR) << "Could not locate RDBAccessSvc" << endmsg; + return sc; + } + + DecodeFaserVersionKey versionKey(geoDbTag,"Trench"); + // IRDBRecordset_ptr switchSet + // = raccess->getRecordsetPtr("TrenchSwitches", versionKey.tag(), versionKey.node(),"FASERDD"); + // const IRDBRecord *switches = (*switchSet)[0]; + // msg(MSG::DEBUG) << "Retrieved TrenchSwitches" << endmsg; + + std::string trenchVersion = versionKey.tag(); + msg(MSG::INFO) << "Building Trench geometry version " << trenchVersion << endmsg; + if(trenchVersion.empty()) { + msg(MSG::INFO) << "No Trench version for the given configuration. Skip building TrenchGeoModel" << endmsg; + return StatusCode::SUCCESS; + } + + std::string versionNode = versionKey.node(); + + GeoModelExperiment* theExpt = nullptr; + if (StatusCode::SUCCESS != detStore()->retrieve(theExpt,"FASER")) { + msg(MSG::ERROR) << "Could not find GeoModelExperiment FASER" << endmsg; + return StatusCode::FAILURE; + } + + GeoPhysVol *world=&*theExpt->getPhysVol(); + + if(!m_manager) { + // If geometry has not been built yet fall back to the default factory + TrenchDetectorFactory theTrenchFactory(detStore().operator->(),raccess); + theTrenchFactory.setTagNode(trenchVersion,versionNode); + theTrenchFactory.create(world); + m_manager = theTrenchFactory.getDetectorManager(); + } + + if(m_manager) { + theExpt->addManager(m_manager); + sc = detStore()->record(m_manager, + m_manager->getName()); + if(sc.isFailure()) { + msg(MSG::ERROR) << "Could not register Trench detector manager" << endmsg; + return sc; + } + } + else { + msg(MSG::ERROR) << "ERROR. Failed to build Trench Version " << trenchVersion << endmsg; + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TrenchDetectorTool::clear() +{ + SG::DataProxy* proxy = detStore()->proxy(ClassID_traits<TrenchDetectorManager>::ID(),m_manager->getName()); + if(proxy) { + proxy->reset(); + m_manager = 0; + } + return StatusCode::SUCCESS; +} + diff --git a/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.h b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.h new file mode 100644 index 0000000000000000000000000000000000000000..6c5407662e5508608d8b189aa57c3d37d82a4eda --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/TrenchDetectorTool.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRENCHDETECTORTOOL_H +#define TRENCHDETECTORTOOL_H + +#include "GeoModelFaserUtilities/GeoModelTool.h" +class TrenchDetectorManager; + +class TrenchDetectorTool final : public GeoModelTool +{ + public: + + // Standard Constructor + TrenchDetectorTool( const std::string& type, const std::string& name, const IInterface* parent ); + + // Standard Destructor + virtual ~TrenchDetectorTool() override final; + + virtual StatusCode create() override final; + virtual StatusCode clear() override final; + + private: + const TrenchDetectorManager* m_manager; +}; + +#endif diff --git a/FaserGeometryCommon/TrenchGeoModel/src/components/TrenchGeoModel_entries.cxx b/FaserGeometryCommon/TrenchGeoModel/src/components/TrenchGeoModel_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..732ee6b6b059d51d29acadecabaab16b50562cd2 --- /dev/null +++ b/FaserGeometryCommon/TrenchGeoModel/src/components/TrenchGeoModel_entries.cxx @@ -0,0 +1,3 @@ +#include "../TrenchDetectorTool.h" + +DECLARE_COMPONENT( TrenchDetectorTool ) \ No newline at end of file diff --git a/Generators/DIFGenerator/python/DIFSampler.py b/Generators/DIFGenerator/python/DIFSampler.py index 24659c0178d8cbefc9843a24a1a10ef38bbcde21..8ec22459aba93a430093c4bd7b2a3f13e2d0f206 100644 --- a/Generators/DIFGenerator/python/DIFSampler.py +++ b/Generators/DIFGenerator/python/DIFSampler.py @@ -5,7 +5,7 @@ import ParticleGun as PG from math import sqrt, sin, cos, acos from random import uniform -from AthenaCommon.SystemOfUnits import TeV, MeV +from AthenaCommon.SystemOfUnits import TeV, GeV, MeV from AthenaCommon.PhysicalConstants import pi from ROOT import TLorentzVector @@ -90,8 +90,12 @@ class DIFSampler(PG.ParticleSampler): else: self.mom = None - def __init__(self, daughter1_pid = 11, daughter2_pid = -11, mother_pid = None, mother_mom = PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (10*MeV)**2),0,10*MeV,0),mother_pos = CylinderSampler([0, 100**2],[0, 2*pi],[-1500, 0],0)): - self._mother_sampler = PG.ParticleSampler(pid = mother_pid, mom = mother_mom, pos = mother_pos) + # def __init__(self, daughter1_pid = 11, daughter2_pid = -11, mother_pid = None, mother_mom = PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (10*MeV)**2),0,10*MeV,0),mother_pos = CylinderSampler([0, 100**2],[0, 2*pi],[-1500, 0],0)): + def __init__(self, daughter1_pid=13, daughter2_pid=-13, mother_pid=None, + mother_mom=PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (500*MeV)**2), [0, 0.0002], 500*MeV, [0, 2*pi]), + my_z_position=-1500): + # mother_pos=CylinderSampler([0, 100**2], [0, 2*pi], [-1500, 0], 0)): + self._mother_sampler = PG.ParticleSampler(pid = mother_pid, mom = mother_mom, pos=CylinderSampler([0, 100**2], [0, 2*pi], my_z_position, 0)) self.daughter1 = self.particle(daughter1_pid) self.daughter2 = self.particle(daughter2_pid) @@ -111,7 +115,7 @@ class DIFSampler(PG.ParticleSampler): return sqrt(m0**4 - (2*m0**2 * m1**2) + (m1**4) - (2*m0**2 * m2**2) - (2*m1**2 *m2**2) + (m2**4)) / (2*m0) def lorentz_transformation(self): - self.mother_mom = self.mother.mom.shoot() + #self.mother_mom = self.mother.mom.shoot() Bx = self.mother_mom.Px() / self.mother_mom.E() By = self.mother_mom.Py() / self.mother_mom.E() Bz = self.mother_mom.Pz() / self.mother_mom.E() @@ -132,6 +136,11 @@ class DIFSampler(PG.ParticleSampler): ## The magnitude of the momentum will be equal and opposite self.mother = self.mother_sampler + self.mother.mass_override = False + mother_part = self.mother.shoot()[0] + self.mother_mom = mother_part.mom + self.mother_pos = mother_part.pos + p = self.calculate_decay_p(self.mother.mom.mass(),self.daughter1.mass,self.daughter2.mass) self.daughter1.E = sqrt(self.daughter1.mass**2 + p**2) @@ -412,4 +421,4 @@ if __name__ == "__main__": DIFS = DIFSampler() DIFS.mother_sampler = SP() - print("DIFSampler: All unit tests passed") \ No newline at end of file + print("DIFSampler: All unit tests passed") diff --git a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py index 28bb6147a3276b510f3b4c3de83ad281a2997af4..ac30494a4815f5bb06a5d67408b4c0551297a63b 100644 --- a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py +++ b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py @@ -44,10 +44,18 @@ def FaserParticleGunSingleParticleCfg(ConfigFlags, **kwargs) : theta = kwargs.setdefault("theta", [0, pi/20]), phi = kwargs.setdefault("phi", [0, 2*pi]), mass = kwargs.setdefault("mass", 0.0) ) - pg.sampler.pos = PG.PosSampler(x = kwargs.setdefault("x", [-5, 5]), - y = kwargs.setdefault("y", [-5, 5]), - z = kwargs.setdefault("z", -3750.0), - t = kwargs.setdefault("t", 0.0) ) + + if "radius" in kwargs: + pg.sampler.pos = RadialPosSampler(x = kwargs.setdefault("x", 0.0), + y = kwargs.setdefault("y", 0.0), + z = kwargs.setdefault("z", -3750.0), + r = kwargs.setdefault("radius", 1.0), + t = kwargs.setdefault("t", 0.0) ) + else: + pg.sampler.pos = PG.PosSampler(x = kwargs.setdefault("x", [-5, 5]), + y = kwargs.setdefault("y", [-5, 5]), + z = kwargs.setdefault("z", -3750.0), + t = kwargs.setdefault("t", 0.0) ) return cfg @@ -140,8 +148,50 @@ def FaserParticleGunDecayInFlightCfg(ConfigFlags, **kwargs) : return cfg + +def FaserParticleGunForeseeCfg(ConfigFlags, **kwargs) : + # Supported keyword arguments: + # model_path (detault: $PWD) + # model_name (default: DarkPhoton) + # mother_mass (default: 0.01 GeV) + # com_energy (default: 14 TeV) + # daughter1_pid (default: 11) + # daughter2_pid (default: -11) + # mother_pid (default: none) + # mother_pos (default: CylinderSampler([0, 100**2],[0, 2*pi],[-1500, 0],0)) + # + # Note that ALL of these can be samplers themselves - either the simple, "literal" variety or a sampler object configured by the caller + # + + cfg = FaserParticleGunCommonCfg(ConfigFlags, **kwargs) + + pg = cfg.getPrimary() + + from ForeseeGenerator.ForeseeSampler import ForeseeNumpySampler + mother_part = ForeseeNumpySampler( + model_path = kwargs.get("model_path", "."), + model_name = kwargs.get("model_name", "DarkPhoton"), + com_energy = kwargs.get("com_energy", "14"), + mother_mass = kwargs.get("mother_mass", 0.01), + mother_pid = kwargs.get("mother_pid", None), + daughter1_pid = kwargs.get("daughter1_pid", 11), + daughter2_pid = kwargs.get("daughter2_pid", -11), + randomSeed = kwargs.get("randomSeed", None) + ) + + from DIFGenerator import DIFSampler + pg.sampler = DIFSampler( + daughter1_pid = kwargs.get("daughter1_pid", 11), + daughter2_pid = kwargs.get("daughter2_pid", -11), + ) + + pg.sampler.mother_sampler = mother_part + + return cfg + def FaserParticleGunCfg(ConfigFlags) : - generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle") + # generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle") + generator = ConfigFlags.Sim.Gun.setdefault("Generator", "DecayInFlight") kwargs = ConfigFlags.Sim.Gun if generator == "SingleEcalParticle" : return FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs) @@ -149,5 +199,7 @@ def FaserParticleGunCfg(ConfigFlags) : return FaserParticleGunCosmicsCfg(ConfigFlags, **kwargs) elif generator == "DecayInFlight" : return FaserParticleGunDecayInFlightCfg(ConfigFlags, **kwargs) + elif generator == "Foresee" : + return FaserParticleGunForeseeCfg(ConfigFlags, **kwargs) else : return FaserParticleGunSingleParticleCfg(ConfigFlags, **kwargs ) diff --git a/Generators/FaserParticleGun/python/RadialPosSampler.py b/Generators/FaserParticleGun/python/RadialPosSampler.py index 4a14987a142697816b22cbec202f56c8bf3183b5..6fcd6829b29ea474d5c7380526d3c46bab9c6871 100644 --- a/Generators/FaserParticleGun/python/RadialPosSampler.py +++ b/Generators/FaserParticleGun/python/RadialPosSampler.py @@ -34,12 +34,16 @@ class RadialPosSampler(Sampler): @property def r(self): "r position sampler" + fwhm = 2*self.radius sig = fwhm/(2 * sqrt(2 * log(2))) - # return random.uniform(0, self.radius) - return random.gauss(0, self.radius) - # return random.gauss(0, sig) + if self.radius < 0: + return sqrt(random.uniform(0, abs(self.radius**2))) + else: + x = random.gauss(0, self.radius) + y = random.gauss(0, self.radius) + return sqrt(x**2 + y**2) @property def phi(self): @@ -57,7 +61,7 @@ class RadialPosSampler(Sampler): return ROOT.TLorentzVector(x, y, z, t) if __name__ == "__main__": -# test when run from command line + # test when run from command line import numpy as np import matplotlib.pyplot as plt @@ -65,8 +69,8 @@ if __name__ == "__main__": xlist = [] ylist = [] - r = RadialPosSampler(r = 1, x = 10, y = -10, z = 10) - for i in range (10000): + r = RadialPosSampler(r = -10, x = 0, y = 0, z = 10) + for i in range (100000): res = r.shoot() xlist.append(res.X()) ylist.append(res.Y()) @@ -76,10 +80,13 @@ if __name__ == "__main__": plt.figure(figsize = (5,5)) plt.subplot(2,2,1) - plt.scatter(xarr, yarr, marker = "*") + plt.hist2d(xarr, yarr) plt.subplot(2,2,2) plt.hist(yarr) plt.subplot(2,2,3) plt.hist(xarr) + plt.subplot(2,2,4) + plt.hist(np.sqrt(xarr**2 + yarr**2)) plt.tight_layout() plt.show() + diff --git a/Generators/FlukaReader/CMakeLists.txt b/Generators/FlukaReader/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eebebd79e2b466203bb35ba1aa3d3d265d39920d --- /dev/null +++ b/Generators/FlukaReader/CMakeLists.txt @@ -0,0 +1,11 @@ +################################################################################ +# Package: FlukaReader +################################################################################ + +# Declare the package name: +atlas_subdir( FlukaReader ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +#atlas_install_joboptions( share/*.py ) diff --git a/Generators/FlukaReader/python/FlukaReaderAlg.py b/Generators/FlukaReader/python/FlukaReaderAlg.py new file mode 100644 index 0000000000000000000000000000000000000000..3a8728e37229892c56f701f7b3ae5985823c8d76 --- /dev/null +++ b/Generators/FlukaReader/python/FlukaReaderAlg.py @@ -0,0 +1,456 @@ +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from GeneratorModules.EvgenAlg import EvgenAlg +from AthenaPython.PyAthena import StatusCode, EventInfo, EventID, EventType +from AthenaCommon.SystemOfUnits import GeV, MeV, cm +from AthenaCommon.Constants import DEBUG + +from FaserCosmicGenerator import Range + +import ROOT + +import numpy as np +import math + +# TODO: correct angle for beam crossing angle: both in angel itself and position + +class FlukaReader(EvgenAlg): + def __init__(self, name="FlukaReader", MCEventKey="BeamTruthEvent", file_name = "", dist = 0, z = -1.5, randomSeed = None, nsamples = 1, test = False): + super(FlukaReader,self).__init__(name=name) + self.McEventKey = MCEventKey + self.file_name = file_name + self.dist = dist * 100 # cm + self.z = z * 1000 # mm + self.isample = 0 + self.nsamples = nsamples + self.test = test + + self.columns = ["run", "event", "type", "gen", "E", "w", "x", "y", "cosX", "cosY", "age", "_"] + + if randomSeed is not None: + self.msg.info(f"Setting seed to {randomSeed}") + self.rng = np.random.default_rng(randomSeed) + else: + self.rng = np.random.default_rng() + + self.file = open(self.file_name) + + if self.test: + self.before = dict(zip(self.columns, [[] for i in range(len(self.columns))])) + self.after = dict(zip(self.columns, [[] for i in range(len(self.columns))])) + + + return + + def genFinalize(self): + + if self.test: + self.plot() + + self.file.close() + return StatusCode.Success + + + def fillEvent(self, evt): + "This is called for every real event * the number of samplings" + + # If the sample gets to the number requested, then reset to 0 + if self.isample == self.nsamples: + self.msg.debug("Reseting samples") + self.isample = 0 + + # Only if the sample is 0 load the new fluka entry + if self.isample == 0: + self.msg.debug("Loading new fluka event") + try: + l = next(self.file) + except StopIteration: + return StatusCode.Success + + entry = dict(zip(self.columns, l.strip("\n").split())) + for i,c in enumerate(self.columns): + if i < 4: + entry[c] = int(entry[c]) + else: + entry[c] = float(entry[c]) + + self.entry = entry + + # Call for each sample of each event + self.msg.debug(f"Processing sample {self.isample}") + self.process(self.entry, evt) + self.isample += 1 + + return StatusCode.Success + + def angle(self, cosTheta): + "Convert cos(theta) wrt x or y axis to theta wrt z axis" + return np.pi/2 - np.arccos(cosTheta) + + def pid(self, ftype): + "Convert fluka particle type to PID" + if ftype == 10: # mu+ + return -13 + elif ftype == 11: # mu- + return 13 + else: + return 0 + + def path_length(self, z, cosThetaX, cosThetaY): + "Get path length traversed in the material, taking into account incident angles" + + # Convert theta wrt x and y axis to wrt z axis + thetaX = self.angle(cosThetaX) + thetaY = self.angle(cosThetaY) + + # Correct z for angle + zcorr = z / np.abs(np.cos(thetaX)) / np.abs(np.cos(thetaY)) + + return zcorr + + def energy_after_loss_exact(self, e, zcorr): + "Calculate exact energy after loss in material" + return Range.muPropagate(e, zcorr/100.) # meters + + def energy_after_loss(self, e, cosThetaX, cosThetaY, zcorr, a = 2e-3, b = 4e-6): + "Calculate approximate energy after loss in material" + + # Based on + # http://www.bartol.udel.edu/~stanev/lectures/apr17.pdf + # and PDG chapter 27 fig 27.1 + # https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiG9YjNtvr2AhUbiVwKHdQfD9sQFnoECAsQAQ&url=https%3A%2F%2Fpdg.lbl.gov%2F2005%2Freviews%2Fpassagerpp.pdf&usg=AOvVaw1HGA5PZtC2UiqA6B7_C5dz + + eps = a/b + return (e + eps) * np.exp(-b * zcorr) - eps + + def mean_scattering_angle(self, e, cosThetaX, cosThetaY, zcorr, X0 = 10.02, m = 105.66e-3, charge = 1, beta = 1): + "Calculate mean scattering angle over many scatters for given energy and length z" + + # Based on PDG chapter 27 eqns 27.10, 27.16, 27.17 + # https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiG9YjNtvr2AhUbiVwKHdQfD9sQFnoECAsQAQ&url=https%3A%2F%2Fpdg.lbl.gov%2F2005%2Freviews%2Fpassagerpp.pdf&usg=AOvVaw1HGA5PZtC2UiqA6B7_C5dz + # and + # https://pdg.lbl.gov/2014/AtomicNuclearProperties/HTML/standard_rock.html + + # Convert E to momentum [GeV] + p = np.sqrt(e**2 - m**2) + + # Mean angle [GeV and cm] + c = 1 # n.u + theta0 = 13.6e-3 / (p * c * beta) * charge * np.sqrt(zcorr/X0) * (1 + 0.38 * math.log(zcorr, X0)) + return theta0 + + def scattering_angle(self, cosTheta, theta0, rand1): + "Calculate actual scattering angle over many scatters for given start angle and mean angle" + + # Convert theta wrt x or y axis to wrt z axis + theta = self.angle(cosTheta) + + # Add random scattering angle + return theta + rand1 * theta0 + + def scattering_postition(self, x, cosThetaX, cosThetaY, zcorr, theta0, rand1, rand2): + "Calculate transverse scattering position over many scatters for given start angle and mean angle + length z" + + # Convert theta wrt x to wrt z axis + thetaX = self.angle(cosThetaX) + + xout = np.copy(x) + if xout.ndim == 0: + xout = float(xout) + + # Add displacement due to initial angle + #xang = z * np.tan(thetaX) + xang = zcorr * np.sin(thetaX) + xout += xang + + # Add displacement due to multiple scattering + dx = rand1 * zcorr * theta0 / np.sqrt(12) + rand2 * zcorr * theta0/2 + xout += dx + + return xout + + def propagate(self, entry): + "Propagate the particle through a given distance of standard rock using the small-angle approxiumation" + + if self.dist == 0: + return entry + + # Random numbers + rand1 = self.rng.normal(0, 1) + rand2 = self.rng.normal(0, 1) + + # Get entry info + e = entry["E"] + x = entry["x"] + y = entry["y"] + cosX = entry["cosX"] + cosY = entry["cosY"] + + # Correct path length for angles + z = self.path_length(self.dist, cosX, cosY) + + # Account for energy loss + #eout = self.energy_after_loss(e, cosX, cosY, z) + eout = self.energy_after_loss_exact(e, z) + + # Account for scattering on angle and position + theta0 = self.mean_scattering_angle(e, cosX, cosY, z) + thetaXout = self.scattering_angle(cosX, theta0, rand1) + thetaYout = self.scattering_angle(cosY, theta0, rand1) + xout = self.scattering_postition(x, cosX, cosY, z, theta0, rand1, rand2) + yout = self.scattering_postition(y, cosY, cosX, z, theta0, rand1, rand2) + + # Update entry info using copy for cases when resample so don't change the original + newentry = entry.copy() + newentry["E"] = eout + newentry["x"] = xout + newentry["y"] = yout + newentry["cosX"] = np.cos(np.pi/2 + thetaXout) + newentry["cosY"] = np.cos(np.pi/2 + thetaYout) + + return newentry + + + def process(self, entry, evt): + + if self.test: + for k,v in entry.items(): + self.before[k].append(float(v)) + + if self.msg.level > DEBUG: + print("Original Entry", entry) + + if self.dist != 0: + # Propoagate to FASER + newentry = self.propagate(entry) + elif self.nsamples != 1: + # Else smear if sampling more than once, using copy to avoid changing original + newentry = entry.copy() + newentry["E"] *= self.rng.normal(1, 0.05) + newentry["x"] *= self.rng.normal(1, 0.05) + newentry["y"] *= self.rng.normal(1, 0.05) + newentry["cosX"] = np.cos(np.arccos(entry["cosX"]) * self.rng.normal(1, 0.05)) + newentry["cosY"] = np.cos(np.arccos(entry["cosY"]) * self.rng.normal(1, 0.05)) + else: + # No propagation or smearing + newentry = entry + + if self.msg.level > DEBUG: + print("Propagated/Smeared Entry", newentry) + + + if self.test: + for k,v in newentry.items(): + self.after[k].append(float(v)) + + try: + from AthenaPython.PyAthena import HepMC3 as HepMC + except ImportError: + from AthenaPython.PyAthena import HepMC as HepMC + + # Add weight, correcting for mutliple sampling + evt.weights().push_back(newentry["w"] / self.nsamples) + + + # Setup MC event + mcEventType = EventType() + mcEventType.add_type(EventType.IS_SIMULATION) + + mcEventId = EventID(run_number = newentry["run"], event_number = newentry["event"]) + + mcEventInfo = EventInfo(id = mcEventId, type = mcEventType) + + self.evtStore.record(mcEventInfo, "McEventInfo", True, False) + + ROOT.SetOwnership(mcEventType, False) + ROOT.SetOwnership(mcEventId, False) + ROOT.SetOwnership(mcEventInfo, False) + + # Create HepMC Vertex + pos = HepMC.FourVector(newentry["x"] * cm, newentry["y"] * cm, self.z, 0) + gv = HepMC.GenVertex(pos) + + ROOT.SetOwnership(gv, False) + evt.add_vertex(gv) + + # TODO: skip event if below a certain energy + + # Create HepMC particle + gp = HepMC.GenParticle() + + m = 105.66 + e = newentry["E"] * 1000. #MeV + + # If the energy is less than mass then skip the event + if e < m: + self.setFilterPassed(False) + self.msg.debug("Event failed energy cut") + return False + else: + self.setFilterPassed(True) + + p = np.sqrt(e**2 - m**2) + + thetaX = self.angle(newentry["cosX"]) + thetaY = self.angle(newentry["cosY"]) + + # theta: just above z axis as phi deals with negative + theta = np.abs(thetaY) + # phi: 0 - 2pi + phi = np.arctan2(newentry["cosY"], newentry["cosX"]) + #phi = np.arctan(newentry["cosY"] / newentry["cosX"]) + if phi < 0: phi += 2*np.pi + if phi == 2*np.pi: phi = 0 + + #self.msg.debug(f"INPUT: {e}, {m}, {p}, {theta}, {phi}, {np.sin(theta)}, {np.cos(theta)}, {np.sin(phi)}, {np.cos(phi)}") + + px = p * np.sin(theta) * np.cos(phi) + py = p * np.sin(theta) * np.sin(phi) + pz = p * np.cos(theta) + + mom = HepMC.FourVector(px, py, pz, e) + + gp.set_momentum(mom) + gp.set_generated_mass(m) + gp.set_pdg_id(self.pid(newentry["type"])) + gp.set_status(1) + + #self.msg.debug(f"HEPMC:{px, py, pz, e}") + #gp.print() + + ROOT.SetOwnership(gp, False) + gv.add_particle_out(gp) + + return True + + def plot(self): + "Plot entries before and after propagation/smeating for tests" + + if not self.test: + return + + import matplotlib.pyplot as plt + + plt.figure() + ebins = np.linspace(0, 5000, 50) + plt.xlabel("Energy") + plt.hist(self.before["E"], bins=ebins, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["E"], bins = ebins, histtype='step', color = "r", fill = False, label = "after") + plt.gca().set_yscale('log') + plt.legend() + plt.savefig("energy.png") + + plt.figure() + plt.xlabel("Angle to beam in X dir") + thetaX = np.pi/2. - np.arccos(np.array(self.before["cosX"])) + thetaXout = np.pi/2. - np.arccos(np.array(self.after["cosX"])) + tbins = np.linspace(-0.5, 0.5, 100) + plt.hist(thetaX, bins = tbins, histtype='step', color = "g", fill = False, label = "before") + plt.hist(thetaXout, bins = tbins, histtype='step', color = "r", fill = False, label = "after") + plt.gca().set_yscale('log') + plt.legend() + plt.savefig("thetaX.png") + + plt.figure() + plt.xlabel("Angle to beam in Y dir") + thetaY = np.pi/2. - np.arccos(np.array(self.before["cosY"])) + thetaYout = np.pi/2. - np.arccos(np.array(self.after["cosY"])) + plt.hist(thetaY, bins = tbins, histtype='step', color = "g", fill = False, label = "before") + plt.hist(thetaYout, bins = tbins, histtype='step', color = "r", fill = False, label = "after") + plt.gca().set_yscale('log') + plt.legend() + plt.savefig("thetaY.png") + + plt.figure() + plt.xlabel("Dispacement in X dir") + xbins = np.linspace(-300, 300, 100) + plt.hist(self.before["x"], bins = xbins, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["x"], bins = xbins, histtype='step', color = "r", fill = False, label = "after") + plt.gca().set_yscale('log') + plt.legend() + plt.savefig("x.png") + + plt.figure() + plt.xlabel("Dispacement in Y dir") + plt.hist(self.before["y"], bins = xbins, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["y"], bins = xbins, histtype='step', color = "r", fill = False, label = "after") + plt.gca().set_yscale('log') + plt.legend() + plt.savefig("y.png") + + return + +def getNEvents(fname, maxEvents): + "Work out how many events are in the file" + + n = 0 + with open(fname) as f: + n = sum(1 for _ in f) + + if maxEvents != -1 and n > maxEvents: + n = maxEvents + + print(">>> Setting number of real events to", n) + + return n + +if __name__ == "__main__": + +# from AthenaCommon.AlgSequence import AlgSequence +# job = AlgSequence() +# job += FlukaReader(file_name = "/user/gwilliam/unit30_Nm", dist = (480-409)) +# +# from AthenaPoolCnvSvc.WriteAthenaPool import AthenaPoolOutputStream +# ostream = AthenaPoolOutputStream( "StreamEVGEN" , "evgen.pool.root", noTag=True ) +# ostream.ItemList.remove("EventInfo#*") +# ostream.ItemList += [ "EventInfo#McEventInfo", +# "McEventCollection#*" ] +# +# theApp.EvtMax = 1000 + + + import argparse, sys + parser = argparse.ArgumentParser(description="Run Fluka reader") + parser.add_argument("file", help = "Path to fluka file") + parser.add_argument("--dist", "-d", default = 0, type = float, help = "depth of standard rock to propagate through [m]") + parser.add_argument("--pos", "-z", default = -3.75, type = float, help = "Position in z in FASER coordinate system [m]") + parser.add_argument("--output", "-o", default = "evgen.pool.root", help = "Name of output file") + parser.add_argument("--mcEventKey", "-k", default = "BeamTruthEvent", help = "Name of MC collection") + parser.add_argument("--nevents", "-n", default = -1, type = int, help = "Number of events to process") + parser.add_argument("--randomSeed", "-r", default=12345, type=int, help = "Seed for random number generator") + parser.add_argument("--nsamples", "-s", default = 1, type = int, help = "Number of times to sample each event") + parser.add_argument("--test", "-t", action = "store_true", help = "Make test plots") + args = parser.parse_args() + + + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, INFO + + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior = 1 + + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Input.isMC = True + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Default FASER geometry + ConfigFlags.Detector.EnableFaserSCT = True + ConfigFlags.Output.EVNTFileName = args.output + ConfigFlags.lock() + + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) + + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + from AthenaConfiguration.ComponentFactory import CompFactory + + acc = ComponentAccumulator() + reader = FlukaReader("FlukaReader", MCEventKey=args.mcEventKey, file_name = args.file, dist = args.dist, z = args.pos, randomSeed = args.randomSeed, nsamples = args.nsamples, test = args.test) + reader.OutputLevel = INFO + acc.addEventAlgo(reader) + cfg.merge(acc) + + itemList = [ "EventInfo#McEventInfo", "McEventCollection#*" ] + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + cfg.merge(OutputStreamCfg(ConfigFlags, "EVNT", itemList, disableEventTag = True)) + cfg.getEventAlgo("OutputStreamEVNT").AcceptAlgs = ["FlukaReader"] + sc = cfg.run(maxEvents = getNEvents(args.file, args.nevents) * args.nsamples) + sys.exit(not sc.isSuccess()) diff --git a/Generators/ForeseeGenerator/CMakeLists.txt b/Generators/ForeseeGenerator/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e2e5137b8c50f144c2cef2528f0b6be5c5548270 --- /dev/null +++ b/Generators/ForeseeGenerator/CMakeLists.txt @@ -0,0 +1,12 @@ +################################################################################ +# Package: ForeseeGenerator +################################################################################ + +# Declare the package name: +atlas_subdir( ForeseeGenerator ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +atlas_install_joboptions( share/*.py ) + diff --git a/Generators/ForeseeGenerator/data/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy b/Generators/ForeseeGenerator/data/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy new file mode 100644 index 0000000000000000000000000000000000000000..36320c3f1c9cced47c9307b48529b444a2384be0 Binary files /dev/null and b/Generators/ForeseeGenerator/data/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy differ diff --git a/Generators/ForeseeGenerator/python/ForeseeSampler.py b/Generators/ForeseeGenerator/python/ForeseeSampler.py new file mode 100644 index 0000000000000000000000000000000000000000..2f7d7241e560e552b8df3bcd9cb9b62e321f17ff --- /dev/null +++ b/Generators/ForeseeGenerator/python/ForeseeSampler.py @@ -0,0 +1,463 @@ +import os, sys +import random +import numpy as np + +import ParticleGun as PG + +from DIFGenerator.DIFSampler import CylinderSampler + +class ForeseeNumpySampler(PG.ParticleSampler): + """ Sample from the output of Foresee generation in numpy format with columns E, theta, weight""" + def __init__(self, model_path = ".", model_name = "DarkPhoton", com_energy = "14", mother_mass = 0.01, + coupling = None, mother_pid = None, daughter1_pid = 11, daughter2_pid = -11, randomSeed = None): + + self.path = os.path.expanduser(os.path.expandvars(model_path)) + self.modelname = model_name + self.energy = com_energy + self.mass = mother_mass + self.coupling = coupling + self.pid = mother_pid + self.daughter1_pid = daughter1_pid + self.daughter2_pid = daughter2_pid + self.n = 1 + self.distance = 480 # m + self.mass_override = False + + if randomSeed is not None: + print(f"Setting seed to {randomSeed}") + self.rng = np.random.default_rng(randomSeed) + else: + self.rng = np.random.default_rng() + + self.xs = 0 + + self.read() + + def read(self): + "Read data from numpy file in format E, theta, weight" + + if self.path.endswith(".npy"): + filename = self.path + elif self.coupling is None: + filename = f"{self.path}/files/models/{self.modelname}/events/events_{self.energy}TeV_m{self.mass}GeV_to_{self.daughter1_pid}_{self.daughter2_pid}.npy" + else: + filename = f"{self.path}/files/models/{self.modelname}/events/events_{self.energy}TeV_m{self.mass}GeV_c{self.coupling}to_{self.daughter1_pid}_{self.daughter2_pid}.npy" + + print(f"Reading data from file: {filename}") + self.data = np.load(filename) + + # Create probablity for each mode as weight / sum(weights) + self.prob = self.data[2]/np.sum(self.data[2]) + + return + +# def mass(self): +# "Mass converted from GeV to MeV" +# return self._mass * 1000 + + def shoot(self): + "Choose a random item from the data, based on the probability" + + energy, theta, weight = self.rng.choice(self.data, axis = 1, p = self.prob) + + self.xs += weight + + # Convert mass to MeV + mass = self.mass * 1000 + + # Sample phi + phi = self.rng.uniform(0, 2*np.pi) + + # Sample z + z = self.rng.uniform(-1500, 0) + + # Create mother momentum, randomly sampling phi + self.mom = PG.EThetaMPhiSampler(energy, theta, mass, phi) + + # Create mother pos, randomly sampling phi + r = (self.distance * 1000 + abs(z)) * np.tan(theta) + + self.pos = CylinderSampler(r**2, phi, z, 0) + + # Create particle + p = PG.SampledParticle(self.pid) + p.mom = self.mom.shoot() + p.pos = self.pos.shoot() + p.mass = mass + #self.mom.mass = mass + + return [p] + +class ForeseeSampler(PG.MomSampler): + """Create events from foresee directly on the fly + + Requires: + * foresee to be downloaded and in python path + + cd <PATH> + git clone https://github.com/KlingFelix/FORESEE.git + export PYTHONPATH=$PYTHONPATH:<PATH>/FORESEE/src/ + + * scikit-hep installed + + pip install scikit-hep --user + + * forsee files dir symlinked to the run dir + + ln -s <PATH>/FORESEE/files . + + """ + + + def __init__(self, modelname, energy, mass, couplings, daughter1_pid, daughter2_pid, mother_pid = None): + self.modelname = modelname + self.model = Model(self.modelname) + self.energy = energy + self._mass = mass + self.couplings = [couplings] if isinstance(couplings, str) else couplings + self.mother_pid = mother_pid + self.daughter1_pid = daughter1_pid + self.daughter2_pid = daughter2_pid + + self.rng = np.random.default_rng() + self.xs = 0 + + if not os.path.exists("files"): + os.symlink(os.path.expandvars("$Calypso_DIR/../calypso/Generators/foresee/files"), "files") + + self.pid_map = { + (11, 11) : "e_e", + (13, 13) : "mu_mu", + (22, 22) : "gamma_gamma", + } + + self.mode = self.pid_map.get((self.daughter1_pid, self.daughter2_pid), None) + if self.mode is None: + sys.exit(f"Undefined decay to {self.daughter1_pid} + {self.daughter2_pid} for {self.modelname}") + + from foresee import Foresee, Model, Utility + self.foresee = Foresee() + self.foresee.set_detector(selection="np.sqrt(x.x**2 + x.y**2)< 0.1", channels=[self.mode], distance=480, length=1.5 , luminosity=150) + + + if self.modelname == "DarkPhoton": + self.data = self.darkphoton() + elif self.modelname == "ALP-W": + self.data = self.alps() + else: + sys.exit(f"Unknown model {self.modelname}") + + return + + + def mass(self): + return self._mass * 1000 + + def darkphoton(self): + + # Production modes + self.model.add_production_2bodydecay( + pid0 = "111", + pid1 = "22", + br = "2.*0.99 * coupling**2 * pow(1.-pow(mass/self.masses('111'),2),3)", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10) + + self.model.add_production_2bodydecay( + pid0 = "221", + pid1 = "22", + br = "2.*0.39 * coupling**2 * pow(1.-pow(mass/self.masses('221'),2),3)", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10) + + # Handwavey + self.model.add_production_mixing( + pid = "113", + mixing = "coupling * 0.3/5. * 0.77545**2/abs(mass**2-0.77545**2+0.77545*0.147*1j)", + generator = "EPOSLHC", + energy = self.energy, + ) + + # Question on validity as FASER gets larger + self.model.add_production_direct( + label = "Brem", + energy = self.energy, + condition = "p.pt<1", + coupling_ref=1, + ) + + self.model.add_production_direct( + label = "DY", + energy = self.energy, + coupling_ref=1, + massrange=[1.5, 10.] + ) + + return self.decays() + + + def alps(self): + + self.model.add_production_2bodydecay( + pid0 = "5", + pid1 = "321", + br = "2.2e4 * coupling**2 * np.sqrt((1-(mass+0.495)**2/5.279**2)*(1-(mass-0.495)**2/5.279**2))", + generator = "Pythia8", + energy = self.energy, + nsample = 20, # Vary over out of phi and theta + ) + + + self.model.add_production_2bodydecay( + pid0 = "-5", + pid1 = "321", + br = "2.2e4 * coupling**2 * np.sqrt((1-(mass+0.495)**2/5.279**2)*(1-(mass-0.495)**2/5.279**2))", + generator = "Pythia8", + energy = self.energy, + nsample = 20, + ) + + self.model.add_production_2bodydecay( + pid0 = "130", + pid1 = "111", + br = "4.5 * coupling**2 * np.sqrt((1-(mass+0.135)**2/0.495**2)*(1-(mass-0.135)**2/0.495**2))", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10, + ) + + self.model.add_production_2bodydecay( + pid0 = "321", + pid1 = "211", + br = "10.5 * coupling**2 * np.sqrt((1-(mass+0.135)**2/0.495**2)*(1-(mass-0.135)**2/0.495**2))", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10, + ) + + return self.decays() + + + def decays(self): + # Decays + self.model.set_ctau_1d( + filename=f"files/models/{self.modelname}/ctau.txt", + coupling_ref=1 + ) + + # TODO take into account BR + self.model.set_br_1d( + modes = [self.mode], + filenames=[f"files/models/{self.modelname}/br/{self.mode}.txt"] + ) + + # LLP spectrum + self.foresee.set_model(model=self.model) + + plt = self.foresee.get_llp_spectrum(self._mass, coupling=1, do_plot=True) # This is just a reference coupling + plt.savefig(f"{self.modelname}.png") + + def flatten(l): + return [i for sublist in l for i in sublist] + + coups, ctaus, nsigs, energies, weights, thetas = self.foresee.get_events(mass=self._mass, energy=self.energy, couplings=self.couplings) + + return [flatten(thetas), flatten(energies), flatten(weights)] + + def shoot(self): + # Create probablity for each mode as weight / sum(weights) + prob = self.data[2]/np.sum(self.data[2]) + + # Choose a random item from the data, base on the probability + # TODO: what about reuse of events? + theta_mother, e_mother, w = self.rng.choice(self.data, axis = 1, p = prob) + + self.xs += w + + # Create other momentum + mother_mom = PG.EThetaMPhiSampler(e_mother*1000, theta_mother, self.mass(), [0,2*np.pi]) + + return mother_mom.shoot() + +if __name__ == "__main__": + + # Testing ... + + from math import sqrt, log10 + import matplotlib.pyplot as plt + import matplotlib + from DIFGenerator import DIFSampler + + + path = os.path.expandvars("$Calypso_DIR/../calypso/Generators/ForeseeGenerator/data/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy") + path = "files/models/DarkPhoton/events/events_14TeV_m0.1GeV_c1e-05to_11_-11.npy" + + modelname = "DarkPhoton" + mass = 0.1 + + theta = [] + mom = [] + + d0theta = [] + d0mom = [] + + d1theta = [] + d1mom = [] + + # Accounting for rounding + epsilon = 6 + + # Create mother sampler reading data from foresee + mother_sampler = ForeseeNumpySampler(model_path = path, model_name = modelname, com_energy = "14", mother_mass = 0.1, coupling = 1e-5, mother_pid = None, daughter1_pid = 11, daughter2_pid = -11) + + # Create decay-in-flight + d = DIFSampler(11, -11, None) + d.mother_sampler = mother_sampler + + # Loop over a range of events + for i in range(100000): + + # Shoot the decay in flight + daughters = d.shoot() + + # Get mother and sum of daugthers and check these make sense. + mother_mom = d.mother_mom + s = daughters[0].mom+daughters[1].mom + + try: + assert mother_mom.E() - epsilon <= s.E() <= mother_mom.E() + epsilon + assert mother_mom.P() - epsilon <= s.P()<= mother_mom.P() + epsilon + assert mother_mom.Px() - epsilon <= s.Px() <= mother_mom.Px() + epsilon + assert mother_mom.Py() - epsilon <= s.Py() <= mother_mom.Py() + epsilon + assert mother_mom.Pz() - epsilon <= s.Pz() <= mother_mom.Pz() + epsilon + assert daughters[0].pos.X() == daughters[1].pos.X() == d.mother_pos.X() + assert daughters[0].pos.Y() == daughters[1].pos.Y() == d.mother_pos.Y() + assert daughters[0].pos.Z() == daughters[1].pos.Z() == d.mother_pos.Z() + except AssertionError: + print("Error on run " + str(i)) + + print("mother particle:") + print(" E = " + str(mother_mom.E())) + print(" M = " + str(mother_mom.M())) + print(" P = " + str(mother_mom.P())) + print(" Px = " + str(mother_mom.Px())) + print(" Py = " + str(mother_mom.Py())) + print(" Pz = " + str(mother_mom.Pz())) + print(" theta = " + str(mother_mom.Theta())) + print(" phi = " + str(mother_mom.Phi())) + print(" x = " + str(d.mother_pos.X())) + print(" y = " + str(d.mother_pos.Y())) + print(" z = " + str(d.mother_pos.Z())) + + print("daughter 0 particle:") + print(" E = " + str(daughters[0].mom.E())) + print(" M = " + str(daughters[0].mom.M())) + print(" P = " + str(daughters[0].mom.P())) + print(" Px = " + str(daughters[0].mom.Px())) + print(" Py = " + str(daughters[0].mom.Py())) + print(" Pz = " + str(daughters[0].mom.Pz())) + print(" theta = " + str(daughters[0].mom.Theta())) + print(" phi = " + str(daughters[0].mom.Phi())) + print(" x = " + str(daughters[0].pos.X())) + print(" y = " + str(daughters[0].pos.Y())) + print(" z = " + str(daughters[0].pos.Z())) + + print("daughter 1 particle:") + print(" E = " + str(daughters[1].mom.E())) + print(" M = " + str(daughters[1].mom.M())) + print(" P = " + str(daughters[1].mom.P())) + print(" Px = " + str(daughters[1].mom.Px())) + print(" Py = " + str(daughters[1].mom.Py())) + print(" Pz = " + str(daughters[1].mom.Pz())) + print(" theta = " + str(daughters[1].mom.Theta())) + print(" phi = " + str(daughters[1].mom.Phi())) + print(" x = " + str(daughters[1].pos.X())) + print(" y = " + str(daughters[1].pos.Y())) + print(" z = " + str(daughters[1].pos.Z())) + + raise + + # Store mother info to plot + theta.append(log10(mother_mom.Theta())) + mom.append(log10(mother_mom.P()/1000.)) + + # Store mother info to plot + d0theta.append(log10(daughters[0].mom.Theta())) + d0mom.append(log10(daughters[0].mom.P()/1000.)) + d1theta.append(log10(daughters[1].mom.Theta())) + d1mom.append(log10(daughters[1].mom.P()/1000.)) + + + + # Plot mother from sampling events + prange=[[-6, 0, 120],[ 0, 5, 50]] + tmin, tmax, tnum = prange[0] + pmin, pmax, pnum = prange[1] + t_edges = np.logspace(tmin, tmax, num=tnum+1) + p_edges = np.logspace(pmin, pmax, num=pnum+1) + + ticks = np.array([[np.linspace(10**(j),10**(j+1),9)] for j in range(-7,6)]).flatten() + ticks = [np.log10(x) for x in ticks] + ticklabels = np.array([[r"$10^{"+str(j)+"}$","","","","","","","",""] for j in range(-7,6)]).flatten() + matplotlib.rcParams.update({'font.size': 15}) + + + fig = plt.figure(figsize=(8,5.5)) + ax = plt.subplot(1,1,1) + h=ax.hist2d(x=theta,y=mom, + bins=[tnum,pnum],range=[[tmin,tmax],[pmin,pmax]], + norm=matplotlib.colors.LogNorm(), cmap="hsv", + ) + fig.colorbar(h[3], ax=ax) + ax.set_xlabel(r"angle wrt. beam axis $\theta$ [rad]") + ax.set_ylabel(r"momentum $p$ [GeV]") + ax.set_xticks(ticks) + ax.set_xticklabels(ticklabels) + ax.set_yticks(ticks) + ax.set_yticklabels(ticklabels) + ax.set_xlim(tmin, tmax) + ax.set_ylim(pmin, pmax) + plt.savefig(f"{modelname}_PG_m{mass}.png") + + fig = plt.figure(figsize=(8,5.5)) + ax = plt.subplot(1,1,1) + h=ax.hist2d(x=d0theta,y=d0mom, + bins=[tnum,pnum],range=[[tmin,tmax],[pmin,pmax]], + norm=matplotlib.colors.LogNorm(), cmap="hsv", + ) + fig.colorbar(h[3], ax=ax) + ax.set_xlabel(r"angle wrt. beam axis $\theta$ [rad]") + ax.set_ylabel(r"momentum $p$ [GeV]") + ax.set_xticks(ticks) + ax.set_xticklabels(ticklabels) + ax.set_yticks(ticks) + ax.set_yticklabels(ticklabels) + ax.set_xlim(tmin, tmax) + ax.set_ylim(pmin, pmax) + plt.savefig(f"{modelname}_PG_d0_m{mass}.png") + + fig = plt.figure(figsize=(8,5.5)) + ax = plt.subplot(1,1,1) + h=ax.hist2d(x=d1theta,y=d1mom, + bins=[tnum,pnum],range=[[tmin,tmax],[pmin,pmax]], + norm=matplotlib.colors.LogNorm(), cmap="hsv", + ) + fig.colorbar(h[3], ax=ax) + ax.set_xlabel(r"angle wrt. beam axis $\theta$ [rad]") + ax.set_ylabel(r"momentum $p$ [GeV]") + ax.set_xticks(ticks) + ax.set_xticklabels(ticklabels) + ax.set_yticks(ticks) + ax.set_yticklabels(ticklabels) + ax.set_xlim(tmin, tmax) + ax.set_ylim(pmin, pmax) + plt.savefig(f"{modelname}_PG_d1_m{mass}.png") + + + print (f"x-sect = {mother_sampler.xs} pb") + + + + diff --git a/Generators/ForeseeGenerator/python/Validate.py b/Generators/ForeseeGenerator/python/Validate.py new file mode 100644 index 0000000000000000000000000000000000000000..399d85ae788903d7f2829af6bd3239a69ddb0527 --- /dev/null +++ b/Generators/ForeseeGenerator/python/Validate.py @@ -0,0 +1,255 @@ +from AthenaPython.PyAthena import StatusCode, McEventCollection, HepMC, CLHEP +from GeneratorModules.EvgenAnalysisAlg import EvgenAnalysisAlg + +import ROOT as R +import numpy as np +import os +from math import sqrt + +def fix(): + "Python Fixes for HepMC" + def add(self, other): + self.set(self.x() + other.x(), self.y() + other.y(), + self.z() + other.z(), self.t() + other.t()) + return self + + HepMC.FourVector.__iadd__ = add + del add + + return + +class HistSvc(object): + "Class to deal with histograms" + + def __init__(self): + self.hists = {} + + def add(self, name, nbinsX = None, loX = None, hiX = None, nbinsY = None, loY = None, hiY = None, title = None, arrayX = None, arrayY = None): + hname = os.path.basename(name) + + if title is None: title = hname + + if nbinsY is not None: + self.hists[name] = R.TH2F(hname, title, nbinsX, loX, hiX, nbinsY, loY, hiY) + elif arrayX is not None and arrayY is not None: + self.hists[name] = R.TH2F(hname, title, len(arrayX) - 1, arrayX, len(arrayY) - 1, arrayY) + elif arrayX is not None and arrayY is None and nbinsY is not None: + self.hists[name] = R.TH2F(hname, title, len(arrayX) - 1, arrayX, nbinsY, loY, hiY) + elif arrayX is None and arrayY is not None: + self.hists[name] = R.TH2F(hname, title, nbinsX, loX, hiX, len(arrayY) - 1, arrayY) + elif arrayX is not None: + self.hists[name] = R.TH1F(hname, title, len(arrayX) - 1, arrayX) + else: + self.hists[name] = R.TH1F(hname, title, nbinsX, loX, hiX) + + def __getitem__(self, name): + return self.hists[name] + + def write(self, name): + + f = R.TFile.Open(name, "RECREATE") + + for n, h in self.hists.items(): + path = os.path.dirname(n) + if path and not f.GetDirectory(path): + f.mkdir(path) + + f.cd(path) + h.Write() + + f.Close() + + return + +class EvgenValidation(EvgenAnalysisAlg): + "Gen-level validation" + + def __init__(self, name = "EvgenValidation", ndaughters = 2, outname = "validation.root", mother_stored = False): + super(EvgenValidation, self).__init__(name=name) + self.hists = HistSvc() + self.mother_stored = mother_stored + self.ndaughters = ndaughters + self.outname = outname + + def binning(self): + "binning for theta vs phi plot" + tmin, tmax, tnum = [-6, 0, 24] + pmin, pmax, pnum = [ 0, 5, 10] + t_edges = np.logspace(tmin, tmax, num=tnum+1) + p_edges = np.logspace(pmin, pmax, num=pnum+1) + return t_edges, p_edges + + def initialize(self): + + # All daughters + self.hists.add("PIDs", 600, -300, 300) + + # Daughter i + tbins, pbins = self.binning() + for i in range(self.ndaughters): + self.hists.add(f"E_d{i}", 100, 0, 10000) + self.hists.add(f"P_d{i}", 100, 0, 10000) + self.hists.add(f"Pz_d{i}", 100, 0, 10000) + self.hists.add(f"Pt_d{i}", 100, 0, 1) + self.hists.add(f"Theta_d{i}", 20, 0, 0.001) + self.hists.add(f"Phi_d{i}", 16, -3.2, 3.2) + self.hists.add(f"ThetaVsP_d{i}", arrayX = tbins, arrayY = pbins) + self.hists.add(f"Mass_d{i}", 5000, 0, 1) + + # Mother + self.hists.add("E_M", 1000, 0, 10000) + self.hists.add("P_M", 1000, 0, 10000) + self.hists.add("Pz_M", 1000, 0, 10000) + self.hists.add("Pt_M", 1000, 0, 1) + self.hists.add("Theta_M", 200, 0, 0.02) + self.hists.add("Phi_M", 16, -3.2, 3.2) + self.hists.add("Mass_M", 200, 0, 2) + self.hists.add("ThetaVsP_M", arrayX = tbins, arrayY = pbins) + + # Vertex + self.hists.add("Vtx_X_LLP", 50, -100, 100) + self.hists.add("Vtx_Y_LLP", 50, -100, 100) + self.hists.add("Vtx_Z_LLP", 500, -5000, 0) + self.hists.add("Vtx_R_LLP", 20, 0, 200) + self.hists.add("Vtx_XY_LLP", 50, -100, 100, 50, -100, 100) + + self.hists.add("Vtx_X_All", 50, -100, 100) + self.hists.add("Vtx_Y_All", 50, -100, 100) + self.hists.add("Vtx_Z_All", 500, -5000, 0) + self.hists.add("Vtx_R_All", 20, 0, 200) + self.hists.add("Vtx_XY_All", 50, -100, 100, 50, -100, 100) + + return StatusCode.Success + + + def fillKin(self, label, p, mass = True, twoD = True): + + self.hists[f"E_{label}"].Fill(p.t()/1000, self.weight) + self.hists[f"P_{label}"].Fill(p.rho()/1000, self.weight) + self.hists[f"Pz_{label}"].Fill(p.pz()/1000, self.weight) + self.hists[f"Pt_{label}"].Fill(p.perp()/1000, self.weight) + self.hists[f"Theta_{label}"].Fill(p.theta(), self.weight) + self.hists[f"Phi_{label}"].Fill(p.phi(), self.weight) + + if mass: + self.hists[f"Mass_{label}"].Fill(p.m()/1000, self.weight) + + if twoD: + self.hists[f"ThetaVsP_{label}"].Fill(p.theta(), p.rho()/1000, self.weight) + + return + + def fillDaughter(self, p): + self.hists["PIDs"].Fill(p.pdg_id(), self.weight) + return + + def fillVertex(self, label, v): + self.hists[f"Vtx_X_{label}"].Fill(v.x(), self.weight) + self.hists[f"Vtx_Y_{label}"].Fill(v.y(), self.weight) + self.hists[f"Vtx_Z_{label}"].Fill(v.z(), self.weight) + self.hists[f"Vtx_XY_{label}"].Fill(v.x(), v.y(), self.weight) + self.hists[f"Vtx_R_{label}"].Fill(sqrt(v.x()**2 + v.y()**2), self.weight) + return + + + def execute(self): + evt = self.events()[0] + self.weight = evt.weights()[0] if evt.weights() else 1 + + # Loop over all particles in events + momenta = [] + vertices = [] + mother = HepMC.FourVector(0,0,0,0) + llp_vtx = None + + for i, p in enumerate(evt.particles): + print("--- ", i) + p.print() + self.fillDaughter(p) + + if self.mother_stored: + if i == 0: + mother = p.momentum() + else: + momenta.append(p.momentum()) + else: + momenta.append(p.momentum()) + mother += p.momentum() + + if i == 0 and p.production_vertex(): + #p.production_vertex().print() + llp_vtx = p.production_vertex().point3d() + + if p.production_vertex(): + vertices.append(p.production_vertex().point3d()) + + # Fill daughter plots + for i in range(self.ndaughters): + if i >= len(momenta): continue + self.fillKin(f"d{i}", momenta[i]) + + # Fill mother plots + self.fillKin("M", mother, mass = True) + + # Fill all vertices + for v in vertices: + self.fillVertex("All", v) + + # Fill LLP vertex plots + if llp_vtx: + self.fillVertex("LLP", llp_vtx) + + return StatusCode.Success + + def finalize(self): + self.hists.write(self.outname) + return StatusCode.Success + + +if __name__ == "__main__": + + import argparse, sys + parser = argparse.ArgumentParser(description="Run gen-level validation") + parser.add_argument("file", nargs="+", help = "full path to imput file") + parser.add_argument("--ndaughters", "-d", default = 2, type = int, help = "Number of daugthers to plot") + parser.add_argument("--mother_stored", "-m", default = False, action = "store_true", help = "Is mother stored in input?") + parser.add_argument("--output", "-o", default = "validation.root", help = "Name of output file") + parser.add_argument("--mcEventKey", "-k", default = "BeamTruthEvent", help = "Name of MC collection") + parser.add_argument("--nevents", "-n", default = -1, type = int, help = "Number of events to process") + args = parser.parse_args() + + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG + log.setLevel(DEBUG) + + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior = 1 + + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Input.isMC = True + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Default FASER geometry + ConfigFlags.Detector.EnableFaserSCT = True + ConfigFlags.Input.Files = args.file + ConfigFlags.lock() + + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) + + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + cfg.merge(PoolReadCfg(ConfigFlags)) + + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + from AthenaConfiguration.ComponentFactory import CompFactory + + import McParticleEvent.Pythonizations + fix() + + acc = ComponentAccumulator() + valid = EvgenValidation("EvgenValidation", ndaughters = args.ndaughters, outname = args.output, mother_stored = args.mother_stored) + valid.McEventKey = args.mcEventKey + acc.addEventAlgo(valid) + cfg.merge(acc) + + sc = cfg.run(maxEvents = args.nevents) + sys.exit(not sc.isSuccess()) diff --git a/Generators/ForeseeGenerator/share/convert_hepmc_to_evnt.py b/Generators/ForeseeGenerator/share/convert_hepmc_to_evnt.py new file mode 100644 index 0000000000000000000000000000000000000000..382ad439e5ec1a7d31699c482fd0f17758f18f9c --- /dev/null +++ b/Generators/ForeseeGenerator/share/convert_hepmc_to_evnt.py @@ -0,0 +1,62 @@ +def getNEvents(fname, maxEvents): + "Work out how many events are in the file" + + n = 0 + with open(fname) as f: + n = sum(1 for l in f if l.startswith("E ")) + + if maxEvents != -1 and n > maxEvents: + n = maxEvents + + print ("Setting Maximum events to", n) + return n + + +if __name__ == "__main__": + + import sys + + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG + log.setLevel(DEBUG) + + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior = 1 + + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Input.RunNumber = [12345] + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [1] + + ConfigFlags.Input.isMC = True + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Default FASER geometry + ConfigFlags.Detector.EnableFaserSCT = True + + ConfigFlags.Output.EVNTFileName = "myEVNT.pool.root" + + ConfigFlags.Exec.MaxEvents= -1 + + import sys + ConfigFlags.fillFromArgs(sys.argv[1:]) + + + ConfigFlags.Exec.MaxEvents = getNEvents(ConfigFlags.Input.Files[0], ConfigFlags.Exec.MaxEvents) + + ConfigFlags.lock() + + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) + + from HEPMCReader.HepMCReaderConfig import HepMCReaderCfg + cfg.merge(HepMCReaderCfg(ConfigFlags)) + + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) + + itemList = [ "EventInfo#McEventInfo", "McEventCollection#*" ] + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + cfg.merge(OutputStreamCfg(ConfigFlags, "EVNT", itemList, disableEventTag = True)) + + sc = cfg.run() + sys.exit(not sc.isSuccess()) diff --git a/Generators/ForeseeGenerator/share/generate_forsee_events.py b/Generators/ForeseeGenerator/share/generate_forsee_events.py new file mode 100644 index 0000000000000000000000000000000000000000..37372b7bd5d574e084dad7842ad43a54eb31f1f9 --- /dev/null +++ b/Generators/ForeseeGenerator/share/generate_forsee_events.py @@ -0,0 +1,393 @@ +import os + +import numpy as np +import matplotlib.pyplot as plt +import matplotlib + +class ForeseeGenerator(object): + """ + Generate LLP particles within FASER acceptance from FORESEE + """ + + def __init__(self, modelname, energy, mass, couplings, daughter1_pid, daughter2_pid, outdir = None, path = '.', randomSeed = 12345): + + self.modelname = modelname + self.energy = energy + self.mass = mass + self.couplings = [couplings] if isinstance(couplings, (str, int, float)) else couplings + self.daughter1_pid = daughter1_pid + self.daughter2_pid = daughter2_pid + self.outdir = outdir + self.path = path + self.version = 1 # Forsee "version": 2 is in testing + self.seed = randomSeed + + # Set decay mode ... + + self.pid_map = { + (-11, 11) : "e_e", + (11, -11) : "e_e", + (-13, 13) : "mu_mu", + (13, -13) : "mu_mu", + (22, 22) : "gamma_gamma", + } + + self.mode = self.pid_map.get((self.daughter1_pid, self.daughter2_pid), None) + if self.mode is None: + sys.exit(f"Undefined decay to {self.daughter1_pid} + {self.daughter2_pid} for {self.modelname}") + + # Set detector ... + if self.version == 1: + self.foresee = Foresee() + else: + self.foresee = Foresee(path = self.path) + + # TODO: relax this a bit as daughters may enter even if mother doesn't + self.foresee.set_detector(selection="np.sqrt(x.x**2 + x.y**2)< 0.1", + channels=[self.mode], distance=480, length=1.5 , + luminosity=1/1000.) # 1 pb-1 + + # Set model ... + if self.version == 1: + self.model = Model(self.modelname) + else: + self.model = Model(self.modelname, path = f"{self.path}/Models/{self.modelname}/") + + if self.modelname == "DarkPhoton": + self.data = self.darkphoton() + elif self.modelname == "ALP-W": + self.data = self.alp_W() + else: + sys.exit(f"Unknown model {self.modelname}") + + return + + def darkphoton(self): + + # Production modes + self.model.add_production_2bodydecay( + pid0 = "111", + pid1 = "22", + br = "2.*0.99 * coupling**2 * pow(1.-pow(mass/self.masses('111'),2),3)", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10) + + self.model.add_production_2bodydecay( + pid0 = "221", + pid1 = "22", + br = "2.*0.39 * coupling**2 * pow(1.-pow(mass/self.masses('221'),2),3)", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10) + + self.model.add_production_mixing( + pid = "113", + mixing = "coupling * 0.3/5. * 0.77545**2/abs(mass**2-0.77545**2+0.77545*0.147*1j)", + generator = "EPOSLHC", + energy = self.energy, + ) + + if self.version == 1: + self.model.add_production_direct( + label = "Brem", + energy = self.energy, + condition = "p.pt<1", + coupling_ref=1, + ) + + self.model.add_production_direct( + label = "DY", + energy = self.energy, + coupling_ref=1, + massrange=[1.5, 10.] + ) + else: + masses_brem = [ + 0.01 , 0.0126, 0.0158, 0.02 , 0.0251, 0.0316, 0.0398, + 0.0501, 0.0631, 0.0794, 0.1 , 0.1122, 0.1259, 0.1413, + 0.1585, 0.1778, 0.1995, 0.2239, 0.2512, 0.2818, 0.3162, + 0.3548, 0.3981, 0.4467, 0.5012, 0.5623, 0.6026, 0.631 , + 0.6457, 0.6607, 0.6761, 0.6918, 0.7079, 0.7244, 0.7413, + 0.7586, 0.7762, 0.7943, 0.8128, 0.8318, 0.8511, 0.871 , + 0.8913, 0.912 , 0.9333, 0.955 , 0.9772, 1. , 1.122 , + 1.2589, 1.4125, 1.5849, 1.7783, 1.9953, 2.2387, 2.5119, + 2.8184, 3.1623, 3.9811, 5.0119, 6.3096, 7.9433, 10. + ] + + self.model.add_production_direct( + label = "Brem", + energy = self.energy, + condition = "p.pt<1", + coupling_ref=1, + masses = masses_brem, + ) + + masses_dy = [ + 1.5849, 1.7783, 1.9953, 2.2387, 2.5119, 2.8184, 3.1623, 3.9811, 5.0119, 6.3096, 7.9433, 10. + ] + + self.model.add_production_direct( + label = "DY", + energy = self.energy, + coupling_ref=1, + masses = masses_dy, + ) + + return self.decays() + + + def alp_W(self): + + self.model.add_production_2bodydecay( + pid0 = "5", + pid1 = "321", + br = "2.2e4 * coupling**2 * np.sqrt((1-(mass+0.495)**2/5.279**2)*(1-(mass-0.495)**2/5.279**2))", + generator = "Pythia8", + energy = self.energy, + nsample = 20, # Vary over phi and theta + ) + + self.model.add_production_2bodydecay( + pid0 = "-5", + pid1 = "321", + br = "2.2e4 * coupling**2 * np.sqrt((1-(mass+0.495)**2/5.279**2)*(1-(mass-0.495)**2/5.279**2))", + generator = "Pythia8", + energy = self.energy, + nsample = 20, + ) + + self.model.add_production_2bodydecay( + pid0 = "130", + pid1 = "111", + br = "4.5 * coupling**2 * np.sqrt((1-(mass+0.135)**2/0.495**2)*(1-(mass-0.135)**2/0.495**2))", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10, + ) + + self.model.add_production_2bodydecay( + pid0 = "321", + pid1 = "211", + br = "10.5 * coupling**2 * np.sqrt((1-(mass+0.135)**2/0.495**2)*(1-(mass-0.135)**2/0.495**2))", + generator = "EPOSLHC", + energy = self.energy, + nsample = 10, + ) + + return self.decays() + + + def decays(self): + # Set up liftime and BRs + + if self.version == 1: + self.model.set_ctau_1d( + filename=f"files/models/{self.modelname}/ctau.txt", + coupling_ref=1 + ) + + self.model.set_br_1d( + modes = [self.mode], + filenames=[f"files/models/{self.modelname}/br/{self.mode}.txt"] + ) + else: + self.model.set_ctau_1d( + filename=f"model/ctau.txt", + coupling_ref=1 + ) + + self.model.set_br_1d( + modes = [self.mode], + finalstates = [[self.daughter1_pid, self.daughter2_pid]], + filenames=[f"model/br/{self.mode}.txt"] + ) + + # Get LLP spectrum + self.foresee.set_model(model=self.model) + # This is just a reference coupling + plt = self.foresee.get_llp_spectrum(self.mass, coupling=1, do_plot=True) + plt.savefig(f"{self.modelname}_m{self.mass}.png") + + def flatten(l): + return [i for sublist in l for i in sublist] + + # Get list of events within detector + output = self.foresee.get_events(mass=self.mass, energy=self.energy, couplings=self.couplings) + coups, ctaus, nsigs, energies, weights, thetas = output + + self.plot(flatten(thetas), flatten(energies), flatten(weights)) + + # Return energy (converting to MeV), theta and weights + return [[e*1000 for e in flatten(energies)], flatten(thetas), flatten(weights)] + + def plot(self, thetas, energies, weights): + # Plot the results in Forsee format + + t = np.array(thetas) + p = np.sqrt(np.array(energies)**2 - self.mass**2) + + prange=[[-6, 0, 120],[ 0, 5, 50]] + tmin, tmax, tnum = prange[0] + pmin, pmax, pnum = prange[1] + t_edges = np.logspace(tmin, tmax, num=tnum+1) + p_edges = np.logspace(pmin, pmax, num=pnum+1) + + ticks = np.array([[np.linspace(10**(j),10**(j+1),9)] for j in range(-7,6)]).flatten() + ticks = [np.log10(x) for x in ticks] + ticklabels = np.array([[r"$10^{"+str(j)+"}$","","","","","","","",""] for j in range(-7,6)]).flatten() + matplotlib.rcParams.update({'font.size': 15}) + + fig = plt.figure(figsize=(8,5.5)) + ax = plt.subplot(1,1,1) + h=ax.hist2d(x=np.log10(t),y=np.log10(p),weights=weights, + bins=[tnum,pnum],range=[[tmin,tmax],[pmin,pmax]], + norm=matplotlib.colors.LogNorm(), cmap="hsv", + ) + + fig.colorbar(h[3], ax=ax) + ax.set_xlabel(r"angle wrt. beam axis $\theta$ [rad]") + ax.set_ylabel(r"momentum $p$ [GeV]") + ax.set_xticks(ticks) + ax.set_xticklabels(ticklabels) + ax.set_yticks(ticks) + ax.set_yticklabels(ticklabels) + ax.set_xlim(tmin, tmax) + ax.set_ylim(pmin, pmax) + plt.savefig(f"{self.modelname}_m{self.mass}_acc.png") + + def write(self): + # Write LLP results to a file + + energies, thetas, weights = self.data + + if self.outdir is None: + if self.version == 1: + self.outdir = f"files/models/{self.modelname}/events" + else: + self.outdir = f"{self.foresee.dirpath}/Models/{self.modelname}/model/events" + + if not os.path.exists(self.outdir): + os.mkdir(self.outdir) + + if len(self.couplings) == 1: + filename = f"{self.outdir}/events_{self.energy}TeV_m{self.mass}GeV_c{self.couplings[0]}to_{self.daughter1_pid}_{self.daughter2_pid}.npy" + else: + filename = f"{self.outdir}/events_{self.energy}TeV_m{self.mass}GeV_to_{self.daughter1_pid}_{self.daughter2_pid}.npy" + + print(f"Generated {len(thetas)} events") + print(f"save data to file: {filename}") + np.save(filename,[energies,thetas, weights]) + + cfgname = filename.replace(".npy", ".cfg") + print(f"save config to file: {cfgname}") + with open(cfgname, "w") as f: + f.write(" ".join(sys.argv)) + + return + + def write_hepmc(self, nevents): + + if self.outdir is None: + self.outdir = "model/events/" + elif not os.path.exists(self.outdir): + os.mkdir(self.outdir) + + filename = f"{self.outdir}/events_{self.energy}TeV_m{self.mass}GeV_c{self.couplings[0]}to_{self.daughter1_pid}_{self.daughter2_pid}.hepmc" + + self.foresee.write_events(self.mass, self.couplings[0], self.energy, filename, nevents, zfront = -1500, seed = self.seed) + +def setup_foresee(path): + + if path is None: + return + + # Add foresee to python path + path = os.path.expandvars(os.path.expanduser(path)) + os.sys.path.append(f"{path}/FORESEE/src") + + # Symlink foresee files/Models dirs to current dir + #if not os.path.exists("files"): + # os.symlink(os.path.expandvars(f"{path}/FORESEE/files"), "files") + #if not os.path.exists("Models"): + # os.symlink(os.path.expandvars(f"{path}/FORESEE/Models"), "files") + + # Install scikit-hep if needed. + + try: + from skhep.math.vectors import LorentzVector, Vector3D + except ModuleNotFoundError: + os.system("pip install scikit-hep --user") + try: + from skhep.math.vectors import LorentzVector, Vector3D + except ModuleNotFoundError: + raise ModuleNotFoundError("Unable to find skhep. Please install the scikit-hep package") + + return + +def add_to_python_path(path): + if path in sys.path: return + path = os.path.expandvars(os.path.expanduser(path)) + os.sys.path.append(path) + return + +def parse_couplings(data, write_hepMC = False): + + if write_hepMC: + try: + couplings = float(couplings) + except ValueError: + sus.exit("Only a single coupling allowed when writing HEPMC events") + + try: + couplings = [float(d) for d in data] + except ValueError: + try: + couplings = np.logspace(*eval(data[0])) + except: + sys.exit("Unable to parse couplings") + + return couplings + +if __name__ == "__main__": + + import argparse, sys + + parser = argparse.ArgumentParser(description="Run FORSEE generation") + parser.add_argument("model", help = "Name of foresee model") + parser.add_argument("--mass", "-m", required = True, type = float, help = "Mass of mother [GeV]") + parser.add_argument("--couplings", "-c", required = True, nargs = "+", help = "Couplings of mother (either single/mulitple values or tuple to pass to np.logspace)") + parser.add_argument("--pid1", required = True, type = int, help = "PID of daughter 1") + parser.add_argument("--pid2", default = None, type = int, help = "PID of daughter 2 (if not set then will be -PID1)") + parser.add_argument("--Ecom", default = "14", help = "Center of mass energy [TeV]") + parser.add_argument("--outdir", "-o", default = None, help = "Output path") + parser.add_argument("--path", default = ".", help = "Path to foresee installation") + parser.add_argument("--hepmc", action = "store_true", help = "Write HepMC events") + parser.add_argument("--nevents", "-n", default = 10, type = int, help = "Number of HepMC events ") + parser.add_argument("--randomSeed", "-s", default = 1234, type = int, help = "Random seed for HepMC generation") + args = parser.parse_args() + + add_to_python_path(f"{args.path}/src") + + from foresee import Foresee, Model, Utility + + # Create PIDs + if args.pid2 is None: + args.pid2 = -args.pid1 + + couplings = parse_couplings(args.couplings) + + print(f"Generating {args.model} events at Ecom = {args.Ecom}") + print(f" mother mass = {args.mass} GeV") + print(f" decay = {args.pid1} {args.pid2}") + print(f" couplings = {couplings}") + + f = ForeseeGenerator(args.model, args.Ecom, args.mass, couplings, args.pid1, args.pid2, outdir = args.outdir, path = args.path, randomSeed = args.randomSeed) + + if args.hepmc: + f.write_hepmc(args.nevents) + else: + f.write() + + + diff --git a/Generators/ForeseeGenerator/share/plot_validation.py b/Generators/ForeseeGenerator/share/plot_validation.py new file mode 100644 index 0000000000000000000000000000000000000000..8429978bc6a091abd853456d1a10fa3d33ab200d --- /dev/null +++ b/Generators/ForeseeGenerator/share/plot_validation.py @@ -0,0 +1,151 @@ +import ROOT as R +from collections import namedtuple + +Hist = namedtuple("Hist", "name, xtitle, ytitle, xlo, xhi, ylo, yhi, r, d, logx, logy, ndiv", + defaults = [None, None, None, None, None, None, 1, "hist", False, False, None]) + +def plot(f, name, xtitle, ytitle, xlo = None, xhi = None, ylo = None, yhi = None, + r = 1, d = "hist", logx = False, logy = False, ndiv = None): + + h = f.Get(name) + + if xlo is not None and xhi is not None: + h.SetAxisRange(xlo, xhi) + + if ylo is not None and yhi is not None: + h.SetAxisRange(ylo, yhi, "Y") + elif not logy: + h.SetMinimum(0) + + if isinstance(r, tuple): + h.Rebin2D(r[0], r[1]) + elif r != 1: + h.Rebin(r) + + if xtitle is not None: + h.GetXaxis().SetTitle(xtitle) + + if ytitle is not None: + h.GetYaxis().SetTitle(ytitle) + + if logx: + R.gPad.SetLogx() + + if logy: + R.gPad.SetLogy() + + if ndiv is not None: + h.SetNdivisions(ndiv) + + h.SetLabelSize(0.05, "X") + h.SetTitleSize(0.05, "X") + h.SetLabelSize(0.05, "Y") + h.SetTitleSize(0.05, "Y") + + h.GetXaxis().SetTitleOffset(1.2) + + R.gPad.SetBottomMargin(0.15) + R.gPad.SetLeftMargin(0.12) + R.gPad.SetRightMargin(0.2) + + h.Draw(d) + return h + +def plotn(f, args, configs, x, y, outname): + + c = R.TCanvas() + c.Divide(x, y) + c._objs = [] + + if isinstance(configs, tuple): + configs = [configs] + + for i, cfg in enumerate(configs): + c.cd(i+1) + c._objs.append(plot(f, *cfg)) + + c.Print(f"{args.output}/{outname}.eps") + + return + +if __name__ == "__main__": + + + R.gROOT.SetBatch(True) + R.gStyle.SetOptStat(0) + + import argparse, sys, os + parser = argparse.ArgumentParser(description="Run gen-level validation plotting") + parser.add_argument("file", help = "full path to imput file") + parser.add_argument("--output", "-o", default = "valplot", help = "Name of output directory") + parser.add_argument("--ndaughters", "-d", default = 2, type = int, help = "Number of daugthers to plot") + args = parser.parse_args() + + if not os.path.exists(args.output): + os.mkdir(args.output) + + print (args.file) + f = R.TFile.Open(args.file) + + for i in range(args.ndaughters): + config = [Hist(f"P_d{i}", logy = True, xtitle = "p^{0} [GeV]", ndiv = 5, r = 5), + Hist(f"Theta_d{i}", xtitle = "#theta [rad]", ndiv = -4), + Hist(f"Mass_d{i}", xtitle = "m^{0} [GeV]", xlo = 0, xhi = 0.1, ndiv = 4), + Hist(f"Pt_d{i}", logy = True, xtitle = "p_{T}^{0} [GeV]", ndiv = 10, r = 5), + Hist(f"Phi_d{i}", xtitle = "#phi [rad]"), + Hist(f"ThetaVsP_d{i}", ytitle = "p^{0} [GeV]", xtitle = "#theta [rad]", logx = True, logy = True, d = "colz") + ] + + plotn(f, args, config, 3, 2, f"daug{i}") + + config = [Hist("P_M", logy = True, xtitle = "p^{0} [GeV]", ndiv = 5, xlo = 0, xhi = 10000, r=10), + Hist("Theta_M", xtitle = "#theta [rad]", ndiv = -4, r = 10), + Hist("Mass_M", xtitle = "m^{0} [GeV]", xlo = 0, xhi = 1., ndiv = 5), + Hist("Pt_M", logy = True, xtitle = "p_{T}^{0} [GeV]", ndiv = 10, r = 50), + Hist("Phi_M", xtitle = "#phi [rad]", r = 2), + Hist("ThetaVsP_M", ytitle = "p^{0} [GeV]", xtitle = "#theta [rad]", logx = True, logy = True, d = "colz") + ] + + plotn(f, args, config, 3, 2, "mother") + + plotn(f, args, Hist("PIDs", xtitle="PDG Id"), 1, 1, "pid") + + +# config = [Hist("ThetaVsP_M", ytitle = "p^{0} [GeV]", xtitle = "#theta [rad]", logx = True, logy = True, d = "colz"), +# Hist("ThetaVsP_d0", ytitle = "p^{0} [GeV]", xtitle = "#theta [rad]", logx = True, logy = True, d = "colz"), +# Hist("ThetaVsP_d1", ytitle = "p^{0} [GeV]", xtitle = "#theta [rad]", logx = True, logy = True, d = "colz") +# ] +# +# plotn(f, args, config, 2, 2, "twod") + + config = [Hist("Vtx_X_LLP", xtitle = "x [mm]", r = 5), + Hist("Vtx_Y_LLP", xtitle = "y [mm]", r = 5), + Hist("Vtx_Z_LLP", xtitle = "z [mm]", r = 5, ndiv = 5), + Hist("Vtx_XY_LLP", xtitle = "x [mm]", ytitle = "y [mm]", d = "colz", r = (5,5)), + Hist("Vtx_R_LLP", xtitle = "r [mm]", r = 5, ndiv = 5) + ] + + plotn(f, args, config, 3, 2, "vtx_llp") + + + config = [Hist("Vtx_X_All", xtitle = "x [mm]", r = 5), + Hist("Vtx_Y_All", xtitle = "y [mm]", r = 5), + Hist("Vtx_Z_All", xtitle = "z [mm]", r = 5, ndiv = 5), + Hist("Vtx_XY_All", xtitle = "x [mm]", ytitle = "y [mm]", d = "colz", r = (5,5)), + Hist("Vtx_R_All", xtitle = "r [mm]", r = 5, ndiv = 5) + ] + + plotn(f, args, config, 3, 2, "vtx_all") + + +# config = [Hist("Vtx_X", xtitle = "x [mm]", r = 5), +# Hist("Vtx_Y", xtitle = "y [mm]", r = 5), +# Hist("Vtx_Z", xtitle = "z [mm]", r = 5, ndiv = 5), +# Hist("Vtx_XY", xtitle = "x [mm]", ytitle = "y [mm]", d = "colz", r = (5,5)), +# Hist("Vtx_R", xtitle = "r [mm]", r = 5, ndiv = 5) +# ] +# +# plotn(f, args, config, 3, 2, "vtx") + + + diff --git a/Generators/GeneratorUtils/CMakeLists.txt b/Generators/GeneratorUtils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d471fbe183ae3da80c2a0ce1a49785ca0b907387 --- /dev/null +++ b/Generators/GeneratorUtils/CMakeLists.txt @@ -0,0 +1,10 @@ +################################################################################ +# Package: GeneratorUtils +################################################################################ + +# Declare the package name: +atlas_subdir( GeneratorUtils ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + diff --git a/Generators/GeneratorUtils/python/ShiftLOS.py b/Generators/GeneratorUtils/python/ShiftLOS.py new file mode 100644 index 0000000000000000000000000000000000000000..44a94c7a2572bdef501c4f8954a79c3fa8e2a544 --- /dev/null +++ b/Generators/GeneratorUtils/python/ShiftLOS.py @@ -0,0 +1,178 @@ + +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from AthenaPython import PyAthena +from AthenaPython.PyAthena import StatusCode, McEventCollection, CLHEP +from AthenaCommon.SystemOfUnits import m +import ROOT + +try: + from AthenaPython.PyAthena import HepMC3 as HepMC +except ImportError: + from AthenaPython.PyAthena import HepMC as HepMC + +class ShiftLOS(PyAthena.Alg): + def __init__(self, name="ShiftLOS", InputMCEventKey="BeamTruthEvent", OutputMCEventKey="BeamTruthEventShifted", xcross = 0, ycross = 0, xshift = 0, yshift = 0): + super(ShiftLOS,self).__init__(name=name) + self.InputMCEventKey = InputMCEventKey + self.OutputMCEventKey = OutputMCEventKey + self.xcross = xcross + self.ycross = ycross + self.xshift = xshift + self.yshift = yshift + self.distance = 480 * m # Assumes 480m is 0 of FASER coordinate system + return + + def shift_vertices(self, evt): + + # Don't need to shift if at IP unless request explicit shift + if not self.distance and not self.xshift and not self.yshift: + return evt + + # Loop over all vertices + for v in evt.vertices: + # Get position + pos = v.position() + x = pos.x() + y = pos.y() + z = pos.z() + dz = self.distance + z + + # Shift x or y by appropriate crossing angle + if self.xcross: + x += dz * self.xcross + self.msg.debug(f"Shifting x by {self.xcross*1E6} urad over {dz/1E3:.2} m: {pos.x()} -> {x} mm ") + elif self.ycross: + y += dz * self.ycross + self.msg.debug(f"Shifting y by {self.ycross*1E6} urad over {dz/1E3:.2} m: {pos.y()} -> {y} mm ") + + if self.xshift: + x += self.xshift + self.msg.debug(f"Shifting x by {self.xshift} mm: {pos.x()} -> {x} mm ") + elif self.yshift: + y += self.yshift + self.msg.debug(f"Shifting y by {self.yshift} mm: {pos.y()} -> {y} mm ") + + v.set_position(HepMC.FourVector(x, y, z, pos.t())) + + return evt + + + def boost_particles(self, evt): + + if self.xcross == self.ycross == 0: + return evt + + pxsum, pysum = 0,0 + pxsum_orig, pysum_orig = 0,0 + + # Loop over all particles + for p in evt.particles: + # Get momentum + mom = p.momentum() + + pxsum_orig += mom.x() + pysum_orig += mom.y() + + # Boost in x or y using CLHEP + boost = CLHEP.Hep3Vector(self.xcross, self.ycross, 0.0) + tmp = CLHEP.HepLorentzVector(mom.px(), mom.py(), mom.pz(), mom.e()) + tmp.boost(boost) + + pxsum += tmp.x() - mom.x() + pysum += tmp.y() - mom.y() + + # Convert back to HepMC + p.set_momentum(HepMC.FourVector(tmp.px(), tmp.py(), tmp.pz(), tmp.e())) + + self.msg.debug(f"Change in total px = {pxsum:.1f} MeV ({pxsum/pxsum_orig * 100: .3f} %), change in total py = {pysum:.1f} MeV ({pysum/pysum_orig * 100: .3f} %)") + + return evt + + def execute(self): + self.msg.debug(f"Exectuing {self.getName()}") + + if not self.xcross and not self.ycross and not self.xshift and not self.yshift: + return StatusCode.Success + + self.msg.debug(f"Reading {self.InputMCEventKey}") + inevt = self.evtStore[self.InputMCEventKey][0] + + self.msg.debug("Creating output event and collection") + outcoll = McEventCollection() + ROOT.SetOwnership(outcoll, False) + + # Clone input event + outevt = HepMC.GenEvent(inevt.__follow__()) # go from ElementProxy to element itself + + # Modify + outevt = self.shift_vertices(outevt) + outevt = self.boost_particles(outevt) + + # Write output + outcoll.push_back(outevt) + ROOT.SetOwnership(outevt, False) + + self.msg.debug(f"Recording {self.OutputMCEventKey}") + self.evtStore.record(outcoll, self.OutputMCEventKey, True, False) + + return StatusCode.Success + +if __name__ == "__main__": + import argparse, sys + parser = argparse.ArgumentParser(description="Run ShiftLOS") + parser.add_argument("infile", help = "Path to input EVNT file") + parser.add_argument("outfile", help = "Path to output EVNT file") + parser.add_argument("--InputMCEventKey", "-i", default = "BeamTruthEvent", help = "Name of Input MC collection") + parser.add_argument("--OutputMCEventKey", "-o", default = "BeamTruthEventShifted", help = "Name of Output MC collection") + parser.add_argument("--xcross", "-x", default = 0, type = float, help = "Crossing angle of LHC beam in x [urad]") + parser.add_argument("--ycross", "-y", default = 0, type = float, help = "Crossing angle of LHC beam in y [urad]") + parser.add_argument("--xshift", default = 0, type = float, help = "Shift of LHC beam in x [mm]") + parser.add_argument("--yshift", default = 0, type = float, help = "Shift of LHC beam in y [mm]") + parser.add_argument("--nevents", "-n", default = -1, type = int, help = "Number of events to process") + args = parser.parse_args() + + from AthenaCommon.Logging import log + from AthenaCommon.Constants import DEBUG, INFO + + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior = 1 + + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Input.isMC = True + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Default FASER geometry + ConfigFlags.Detector.EnableFaserSCT = True + ConfigFlags.Input.Files = [ args.infile ] + ConfigFlags.Output.EVNTFileName = args.outfile + ConfigFlags.lock() + + # Configure components + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(ConfigFlags) + + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + + cfg = MainServicesCfg(ConfigFlags) + cfg.merge(PoolReadCfg(ConfigFlags)) + + import McParticleEvent.Pythonizations + + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + from AthenaConfiguration.ComponentFactory import CompFactory + + acc = ComponentAccumulator() + alg = ShiftLOS("ShiftLOS", InputMCEventKey=args.InputMCEventKey, OutputMCEventKey=args.OutputMCEventKey, + xcross = args.xcross * 1e-6, ycross = args.ycross * 1e-6, xshift = args.xshift, yshift = args.yshift) + alg.OutputLevel = INFO + acc.addEventAlgo(alg) + cfg.merge(acc) + + itemList = [ "EventInfo#McEventInfo", "McEventCollection#*" ] + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + cfg.merge(OutputStreamCfg(ConfigFlags, "EVNT", itemList, disableEventTag = True)) + + sc = cfg.run(maxEvents = args.nevents) + sys.exit(not sc.isSuccess()) + + diff --git a/Generators/GeneratorUtils/python/ShiftLOSConfig.py b/Generators/GeneratorUtils/python/ShiftLOSConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..ffc5c79b926b1674ac43d9e8947bfbbe1750da16 --- /dev/null +++ b/Generators/GeneratorUtils/python/ShiftLOSConfig.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# import sys +from AthenaConfiguration.MainServicesConfig import AthSequencer +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator, ConfigurationError +from AthenaConfiguration.ComponentFactory import CompFactory + +from GeneratorUtils.ShiftLOS import ShiftLOS + + +def ShiftLOSCfg(ConfigFlags, **kwargs) : + import McParticleEvent.Pythonizations + + cfg = ComponentAccumulator() + + shift = ShiftLOS(name = kwargs.setdefault("name", "ShiftLOS")) + shift.InputMCEventKey = kwargs.setdefault("InputMCEventKey", "BeamTruthEvent_ATLASCoord") + shift.OutputMCEventKey = kwargs.setdefault("OutputMCEventKey", "BeamTruthEvent") + shift.xcross = kwargs.setdefault("xcross", 0) + shift.ycross = kwargs.setdefault("ycross", 0) + shift.xshift = kwargs.setdefault("xshift", 0) + shift.yshift = kwargs.setdefault("yshift", 0) + + try: + # Run for PG + cfg.addEventAlgo(shift, sequenceName = "AthBeginSeq", primary = True) # to run *before* G4 + except ConfigurationError: + # Run for pool or hepmc + cfg.addEventAlgo(shift, sequenceName = "AthAlgSeq", primary = True) # to run *before* G4 + + return cfg diff --git a/Generators/HEPMCReader/CMakeLists.txt b/Generators/HEPMCReader/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3076e7abc887d5cc1fabaedddc42d5db36286270 --- /dev/null +++ b/Generators/HEPMCReader/CMakeLists.txt @@ -0,0 +1,9 @@ +################################################################################ +# Package: HEPMCGenie +################################################################################ + +# Declare the package name: +atlas_subdir( HEPMCReader ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) diff --git a/Generators/HEPMCReader/python/HepMCReaderConfig.py b/Generators/HEPMCReader/python/HepMCReaderConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..510b63c5ea51b6d69d2ae36c3d477c0123c69495 --- /dev/null +++ b/Generators/HEPMCReader/python/HepMCReaderConfig.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +import sys, tempfile, pathlib +from AthenaConfiguration.MainServicesConfig import AthSequencer +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory + +from TruthIO.TruthIOConf import HepMCReadFromFile + +def get_file_skip_events(ConfigFlags): + "Create a file with events from ConfigFlags.Exec.SkipEvents to ConfigFlags.Exec.SkipEvents + ConfigFlags.Exec.MaxEvents" + + usetemp = True + #usetemp = False + + skip = ConfigFlags.Exec.SkipEvents + fname = ConfigFlags.Input.Files[0] + evtMax = ConfigFlags.Exec.MaxEvents + + if skip == 0: + return fname + + print(f"get_file_skip_events skipping {skip} events with max {evtMax}") + + if usetemp: + fout = tempfile.NamedTemporaryFile("w", delete = False) + foutname = fout.name + else: + infile = pathlib.Path(fname) + # Put this in current working directory + if evtMax > 0: + end = skip+evtMax + else: + end = 'all' + + foutname = f"{infile.stem}=evts{skip}-{end}.{infile.suffix}" + #foutname, fext = ".".join(fname.split('.')[:-1]), fname.split('.')[-1] + #foutname = f"{foutname}-evts{skip}-{skip+evtMax}{fext}" + fout = open(foutname, "w") + + fout.write("HepMC::Version 2.06.09\nHepMC::IO_GenEvent-START_EVENT_LISTING\n") + + ievt = 0 + with open(fname) as fin: + for l in fin: + if l.startswith("E "): + ievt += 1 + + if evtMax > 0 and ievt > skip + evtMax: + break + + if ievt > skip: + #print(f"Writing event {ievt}") + fout.write(l) + # else: + # print(f"Skipping event {ievt}") + + fout.write("HepMC::IO_GenEvent-END_EVENT_LISTING\n") + fout.close() + + #print(f"Wrote to file {foutname}") + + return foutname + + +def HepMCReaderCfg(ConfigFlags, **kwargs) : + cfg = ComponentAccumulator(AthSequencer("AthBeginSeq", Sequential = True)) + from TruthIO.TruthIOConf import HepMCReadFromFile + hepmc = CompFactory.HepMCReadFromFile(name = kwargs.setdefault("name", "FASERHepMCReader")) + hepmc.InputFile = get_file_skip_events(ConfigFlags) # ConfigFlags.Input.Files[0] + hepmc.McEventKey = kwargs.setdefault("McEventKey", "BeamTruthEvent") + + cfg.addEventAlgo(hepmc, sequenceName = "AthBeginSeq", primary = True) # to run *before* G4 + + return cfg diff --git a/Generators/ParticleGun/CMakeLists.txt b/Generators/ParticleGun/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1794305ed0291e77478aae72b1216db87fce0810 --- /dev/null +++ b/Generators/ParticleGun/CMakeLists.txt @@ -0,0 +1,14 @@ +################################################################################ +# Package: ParticleGun +################################################################################ + +# Declare the package name: +atlas_subdir( ParticleGun ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +# Install files from the package: +atlas_install_joboptions( share/common/*.py + share/example/*.py ) + diff --git a/Generators/ParticleGun/README b/Generators/ParticleGun/README new file mode 100644 index 0000000000000000000000000000000000000000..6cdb698eda4f549c076ac3a3ce732ad65225c11d --- /dev/null +++ b/Generators/ParticleGun/README @@ -0,0 +1,5 @@ +ParticleGun documentation +------------------------- +See https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/ParticleGunForAtlas +for some coherent documentation that should be kept up to date. + diff --git a/Generators/ParticleGun/python/__init__.py b/Generators/ParticleGun/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4e88fc56c49679a210ad57b62055a6a7c0867ddd --- /dev/null +++ b/Generators/ParticleGun/python/__init__.py @@ -0,0 +1,129 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from GeneratorModules.EvgenAlg import EvgenAlg +from ParticleGun.samplers import ParticleSampler +from ParticleGun.samplers import * # noqa: F401, F403 (import into our namespace) +# commenting out the HepMC import for now +#try: +# from AthenaPython.PyAthena import HepMC3 as HepMC +#except ImportError: +# from AthenaPython.PyAthena import HepMC as HepMC + +from AthenaPython.PyAthena import StatusCode +import ROOT,random + +__author__ = "Andy Buckley <andy.buckley@cern.ch>" + +class ParticleGun(EvgenAlg): + """ + A simple but flexible algorithm for generating events from simple distributions. + """ + + def __init__(self, name="ParticleGun", randomSvcName="AtRndmGenSvc", randomStream="ParticleGun", randomSeed=None): + super(ParticleGun, self).__init__(name=name) + self.samplers = [ParticleSampler()] + self.randomStream = randomStream + self.randomSvcName = randomSvcName + self.randomSeed = randomSeed + + @property + def sampler(self): + "Get the first (and presumed only) sampler" + return self.samplers[0] if self.samplers else None + @sampler.setter + def sampler(self, s): + "Set the samplers list to include only a single sampler, s" + self.samplers = [s] + + + def initialize(self): + """ + Pass the AtRndmGenSvc seed to Python's random module, or use a fixed value set via pg.randomSeed. + """ + seed = None + ## Use self.randomSeed directly, or if it's None find a seed string from the ATLAS random number service + if self.randomSeed is not None: + seed = self.randomSeed + else: + randomSvc = getattr(svcMgr, self.randomSvcName, None) + if randomSvc is not None: + for seedstr in randomSvc.Seeds: + if seedstr.startswith(self.randomStream): + seed = seedstr + self.msg.info("ParticleGun: Using random seed '%s' ", seed) + break + if seed is None: + self.msg.warning("ParticleGun: Failed to find a seed for the random stream named '%s' ", self.randomStream) + else: + self.msg.warning("ParticleGun: Failed to find random number service called '%s' ", self.randomSvcName) + ## Apply the seed + if seed is not None: + random.seed(seed) + return StatusCode.Success + else: + self.msg.error("ParticleGun: randomSeed property not set, and no %s random number service found", self.randomSvcName) + return StatusCode.Failure + + + def fillEvent(self, evt): + """ + Sample a list of particle properties, which are then used to create a new GenEvent in StoreGate. + """ + ## Set event weight(s) + # TODO: allow weighted sampling? + try: + from AthenaPython.PyAthena import HepMC3 as HepMC + except ImportError: + from AthenaPython.PyAthena import HepMC as HepMC + evt.weights().push_back(1.0) + + ## Make and fill particles + for s in self.samplers: + particles = s.shoot() + for p in particles: + ## Debug printout of particle properties + #print DEBUG0, p.pid, p.mom.E(), p.mom.Pt(), p.mom.M() + #print "DEBUG1 (px,py,pz,E) = (%0.2e, %0.2e, %0.2e, %0.2e)" % (p.mom.Px(), p.mom.Py(), p.mom.Pz(), p.mom.E()) + #print "DEBUG2 (eta,phi,pt,m) = (%0.2e, %0.2e, %0.2e, %0.2e)" % (p.mom.Eta(), p.mom.Phi(), p.mom.Pt(), p.mom.M()) + #print "DEBUG3 (x,y,z,t) = (%0.2e, %0.2e, %0.2e, %0.2e)" % (p.pos.X(), p.pos.Y(), p.pos.Z(), p.pos.T()) + + ## Make particle-creation vertex + # TODO: do something cleverer than one vertex per particle? + pos = HepMC.FourVector(p.pos.X(), p.pos.Y(), p.pos.Z(), p.pos.T()) + gv = HepMC.GenVertex(pos) + ROOT.SetOwnership(gv, False) + evt.add_vertex(gv) + + ## Make particle with status == 1 + mom = HepMC.FourVector(p.mom.Px(), p.mom.Py(), p.mom.Pz(), p.mom.E()) + gp = HepMC.GenParticle() + gp.set_status(1) + gp.set_pdg_id(p.pid) + gp.set_momentum(mom) + if p.mass is not None: + gp.set_generated_mass(p.mass) + ROOT.SetOwnership(gp, False) + gv.add_particle_out(gp) + + return StatusCode.Success + + +## PyAthena HepMC notes +# +## evt.print() isn't valid syntax in Python2 due to reserved word +# TODO: Add a Pythonisation, e.g. evt.py_print()? +#getattr(evt, 'print')() +# +## How to check that the StoreGate key exists and is an McEventCollection +# if self.sg.contains(McEventCollection, self.sgkey): +# print self.sgkey + " found!" +# +## Modifying an event other than that supplied as an arg +# mcevts = self.sg[self.sgkey] +# for vtx in mcevts[0].vertices: # only way to get the first vtx?! +# gp2 = HepMC.GenParticle() +# gp2.set_momentum(HepMC.FourVector(1,2,3,4)) +# gp2.set_status(1) +# vtx.add_particle_out(gp2) +# break diff --git a/Generators/ParticleGun/python/histsampling.py b/Generators/ParticleGun/python/histsampling.py new file mode 100644 index 0000000000000000000000000000000000000000..c64112cc84e23963b63ea381817d1457f1c2a122 --- /dev/null +++ b/Generators/ParticleGun/python/histsampling.py @@ -0,0 +1,132 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +""" +Tools for histogram sampling, in particular inverse transform sampling which is +missing from ROOT's TH2 classes. +""" + +__author__ = "Andy Buckley <andy.buckley@cern.ch>" + +import random, ROOT + + +def load_hist(*args): + """ + Load a histogram from a filename/TFile and histo name. If a single arg is + provided, it has to be a histo object and will be cloned before return. + """ + h = None + if len(args) == 1 and issubclass(type(args[0]), ROOT.TH1): + h = args[0].Clone() + elif len(args) == 2: + if isinstance(args[0], str) and isinstance(args[1], str) : + f = ROOT.TFile.Open(args[0]) + h = f.Get(args[1]).Clone() + #f.Close() + elif type(args[0]) is ROOT.TFile and type(args[1]) is str: + h = args[0].Get(args[1]).Clone() + if h is None: + raise Exception("Error in histogram loading from " + args) + return h + + +def get_sampling_vars(h): + """ + Get the following from a histogram h, since the ROOT API sucks: + * list of global bin IDs (not even contiguous for 2D, gee thanks ROOT) + * dict mapping global bin IDs to a tuple of axis bin IDs + * list of nbins+1 cumulative bin values, in the same order as globalbins + """ + globalbin_to_axisbin = {} # for reverse axis bin lookup to get edges + globalbins = [] # because they aren't easily predicted, nor contiguous + cheights = [0] # cumulative "histogram" from which to uniformly sample + if issubclass(type(h), ROOT.TH1): + for ix in range(1, h.GetNbinsX()+1): + iglobal = h.GetBin(ix) + globalbins.append(iglobal) + globalbin_to_axisbin[iglobal] = (ix,) + cheights.append(cheights[-1] + h.GetBinContent(iglobal)) + elif issubclass(type(h), ROOT.TH2): + for ix in range(1, h.GetNbinsX()+1): + for iy in range(1, h.GetNbinsY()+1): + iglobal = h.GetBin(ix, iy) + globalbins.append(iglobal) + globalbin_to_axisbin[iglobal] = (ix, iy) + cheights.append(cheights[-1] + h.GetBinContent(iglobal)) + return globalbins, globalbin_to_axisbin, cheights + + +def get_random_bin(globalbins, cheights): + """ + Choose a random bin from the cumulative distribution list of nbins+1 entries. + + TODO: Search more efficiently (lin and log guesses, then lin search or + binary split depending on vector size). + """ + assert len(cheights) == len(globalbins)+1 + randomheight = random.uniform(0, cheights[-1]) + for i, iglobal in enumerate(globalbins): + if randomheight >= cheights[i] and randomheight < cheights[i+1]: + return iglobal + raise Exception("Sample fell outside range of cumulative distribution?!?!") + + +def get_random_x(h, globalbins, cheights, globalbin_to_axisbin): + """ + Choose a random bin via get_random_bin, then pick a uniform random x + point in that bin (without any attempt at estimating the in-bin distribution). + """ + irand = get_random_bin(globalbins, cheights) + axisids = globalbin_to_axisbin.get(irand) + assert axisids is not None + xrand = random.uniform(h.GetXaxis().GetBinLowEdge(axisids[0]), h.GetXaxis().GetBinUpEdge(axisids[0])) + return xrand + + +def get_random_xy(h2, globalbins, cheights, globalbin_to_axisbin): + """ + Choose a random bin via get_random_bin, then pick a uniform random x,y + point in that bin (without any attempt at estimating the in-bin distribution). + """ + irand = get_random_bin(globalbins, cheights) + axisids = globalbin_to_axisbin.get(irand) + assert axisids is not None + xrand = random.uniform(h2.GetXaxis().GetBinLowEdge(axisids[0]), h2.GetXaxis().GetBinUpEdge(axisids[0])) + yrand = random.uniform(h2.GetYaxis().GetBinLowEdge(axisids[1]), h2.GetYaxis().GetBinUpEdge(axisids[1])) + return xrand, yrand + + +class TH1(object): + "Minimal wrapper for ROOT TH1, for sampling consistency and easy loading" + + def __init__(self, *args): + self.th1 = load_hist(*args) + self.globalbins, self.globalbin_to_axisbin, self.cheights = None, None, None + + def GetRandom(self): + "A GetRandom that works for TH1s and uses Python random numbers" + if self.globalbins is None or self.globalbin_to_axisbin is None or self.cheights is None: + self.globalbins, self.globalbin_to_axisbin, self.cheights = get_sampling_vars(self.th1) + return get_random_x(self.th1, self.globalbins, self.cheights, self.globalbin_to_axisbin) + + def __getattr__(self, attr): + "Forward all attributes to the contained TH1" + return getattr(self.th1, attr) + + +class TH2(object): + "Minimal wrapper for ROOT TH2, for easy loading and to allow 2D sampling" + + def __init__(self, *args): + self.th2 = load_hist(*args) + self.globalbins, self.globalbin_to_axisbin, self.cheights = None, None, None + + def GetRandom(self): + "A GetRandom that works for TH2s" + if self.globalbins is None or self.globalbin_to_axisbin is None or self.cheights is None: + self.globalbins, self.globalbin_to_axisbin, self.cheights = get_sampling_vars(self.th2) + return get_random_xy(self.th2, self.globalbins, self.cheights, self.globalbin_to_axisbin) + + def __getattr__(self, attr): + "Forward other attributes to the contained TH2" + return getattr(self.th2, attr) diff --git a/Generators/ParticleGun/python/samplers.py b/Generators/ParticleGun/python/samplers.py new file mode 100644 index 0000000000000000000000000000000000000000..90e9676a5ce20dc1b52e48c79f0b36a7da49f639 --- /dev/null +++ b/Generators/ParticleGun/python/samplers.py @@ -0,0 +1,912 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +import ROOT, math, random +from ParticleGun.histsampling import TH1 + +## For convenience +PI = math.pi +TWOPI = 2*math.pi + + +class Sampler(object): + "Base class for all samplers" + + def shoot(self): + return RuntimeError("Can't sample from an abstract sampler object.") + + def __call__(self): + """This is the call method that will actually be used (so that normal + functions can also be passed in as samplers).""" + return self.shoot() + + # TODO: add a sampling weight? + + +class ConstSampler(Sampler): + "A special-case sampler which just returns one value rather than sampling." + + def __init__(self, val): + self.val = val + + def shoot(self): + return self.val + + def __repr__(self): + return "ConstSampler[%s]" % str(self.val) + + +## Continuous distribution samplers + +class ContinuousSampler(Sampler): + "Base class for samplers from continuous distributions." + pass + + +class UniformSampler(ContinuousSampler): + "Uniformly sample in the range [low,high)." + + def __init__(self, low, high): + assert(low <= high) + self.low = float(low) + self.high = float(high) + + def shoot(self): + return random.uniform(self.low, self.high) + + +class ModUniformSampler(ContinuousSampler): + "Uniformly sample in the modulus range (-high,low]+[low,high)." + + def __init__(self, low, high): + assert(low == abs(low) and high == abs(high)) + assert(low <= high) + self.low = float(low) + self.high = float(high) + + def shoot(self): + val = random.uniform(self.low, self.high) + if random.random() > 0.5: + val *= -1 + return val + + +class DisjointUniformSampler(ContinuousSampler): + "Uniformly sample from a set of disjoint intervals." + + def __init__(self, ranges): + """ + The ranges variable can either be a list of increasing numbers or a + list of pairs of numbers. + + The former case will be treated as + defining alternating on/off ranges for sampling, starting with an active + one (i.e. it's a list of bin edges). The latter way specifically lists + the 'on' regions only, with their start and end values in the pairs. + + The behaviour is undefined if the numbers are not ordered or overlap -- + i.e. it might work but hasn't been designed that way and might change in + future. Don't rely on this behaviour! + """ + if not ranges: + raise Exception("You must supply at least one non-null sampling range") + if hasattr(ranges[0], "__len__"): + assert all(len(x) == 2 for x in ranges) + self.ranges = ranges + else: + assert len(ranges) > 1 + lows = [x for x in ranges[:-1]] + highs = [x for x in ranges[1:]] + myranges = [] + for i, pair in enumerate(zip(lows, highs)): + if i % 2 == 0: + myranges.append(pair) + assert len(myranges) == len(ranges) // 2 + self.ranges = myranges + + def _getRanges(self): + return self._ranges + + def _setRanges(self, ranges): + # TODO: Check that ranges don't overlap + self._ranges = ranges + self._totalwidth = sum(r[1] - r[0] for r in ranges) + + runningwidth = 0.0 + self._divisions = [0.0] + for r in ranges: + assert(r[1] >= r[0]) + runningwidth += float(r[1] - r[0]) + self._divisions.append(runningwidth) + self._totalwidth = runningwidth + for i in range(len(self._divisions)): + self._divisions[i] = float(self._divisions[i]) / float(self._totalwidth) + + ranges = property(_getRanges, _setRanges) + + def _map_unit_to_val(self, x): + assert(x >= 0 and x <= 1) + idx = None + rem = None + for i in range(len(self._divisions) - 1): + if x >= self._divisions[i] and x < self._divisions[i+1]: + idx = i + rem = x - self._divisions[i] + break + if idx is None: + raise ValueError("No matching division found in unit interval! How?") + val = self.ranges[idx][0] + self._totalwidth * rem + return val + + def shoot(self): + rand = random.random() + val = self._map_unit_to_val(rand) + return val + + +class LogSampler(ContinuousSampler): + "Randomly sample from an exponential distribution (i.e. uniformly on a log scale)." + + def __init__(self, low, high): + self.low = float(low) + self.high = float(high) + + def shoot(self): + rand = random.random() + logval = rand * math.log(self.high) + (1 - rand) * math.log(self.low) + val = math.exp(logval) + return val + + +class GaussianSampler(ContinuousSampler): + "Randomly sample from a 1D Gaussian distribution." + + def __init__(self, mean, sigma, oneside = False): + self.mean = float(mean) + self.sigma = float(sigma) + self.oneside = bool(oneside) + + def shoot(self): + if self.oneside: + return abs(random.gauss(self.mean, self.sigma)) + else: + return random.gauss(self.mean, self.sigma) + +class InvSampler(ContinuousSampler): + "Randomly sample from a 1/x distribution." + + def __init__(self, low, high): + self.low = float(low) + self.high = float(high) + + def shoot(self): + invx = random.uniform(1/self.high, 1/self.low) #< limit inversion not actually necessary + return 1./invx + + +######################################## + + +class TH1Sampler(ContinuousSampler): + "Randomly sample from a 1D ROOT histogram." + + def __init__(self, *args): + self.hist = TH1(*args) + if self.hist.GetEntries() < 1: + raise Exception("Histogram %s is EMPTY! Cannot sample" % self.hist.GetName()) + + def shoot(self): + return self.hist.GetRandom() + + +######################################## + + +## Discrete sequence samplers + +class DiscreteSampler(Sampler): + "Base class for samplers from lists of discrete values" + pass + + +class RandomSeqSampler(DiscreteSampler): + "Uniformly random sample from a list of values." + + def __init__(self, *args): + if len(args) == 1: + self.sequence = args[0] + else: + self.sequence = args + + def shoot(self): + return random.choice(self.sequence) +# Alias: +RndmSeq = RandomSeqSampler + + +class CyclicSeqSampler(DiscreteSampler): + "Sequentially sample from a list of values, returning to the beginning once exhausted." + + def __init__(self, *args): + if len(args) == 1: + self.sequence = args[0] + else: + self.sequence = args + self.index = 0 + + def shoot(self): + self.index = (self.index + 1) % len(self.sequence) + return self.sequence[self.index] +## Alias: +Sequence = CyclicSeqSampler + + +######################################## + + +## Convenience function for sampler-making from Python literals + +def mksampler(x): + """ + Automatically cast the provided object to a sampler type. This is used + extensively inside the particle and position samplers, so that the user + can pass in a primitive type like a number or list and it will be + treated as if the more verbose sampler constructors had been called. + + Behaviour: + - if x can be called, i.e. x() is valid, we just return x; + - a Python list (square brackets) will be converted to a continuous + UniformSampler or DisjointUniformSampler; + - a Python tuple (round brackets/parentheses) will be treated + as a discrete CyclicSeqSampler; + - a Python set (curly brackets/braces) will be treated + as a discrete RandomSeqSampler; + - otherwise a ConstSampler will be created from x, so that x is + returned when the sampler is called. + """ + if hasattr(x, "__call__"): + return x + elif type(x) is list: + # NB: disjoint ranges can be given as nested lists, e.g. [(1,2), (4,5)] + if len(x) == 2 and type(x[0]) in (int,float) and type(x[1]) in (int,float): + #print "MKSAMPLER: Casting %s to UniformSampler" % str(x) + return UniformSampler(*x) + elif len(x) > 2 or (len(x) > 0 and type(x[0]) not in (int,float)): + #print "MKSAMPLER: Casting %s to DisjointUniformSampler" % str(x) + return DisjointUniformSampler(x) + if len(x) < 2: + raise Exception("Supplied list could not be converted to a continuous sampler") + elif type(x) is tuple: + #print "MKSAMPLER: Casting %s to CyclicSeqSampler" % str(x) + return CyclicSeqSampler(*x) + elif type(x) is set: + #print "MKSAMPLER: Casting %s to RandomSeqSampler" % str(x) + return RandomSeqSampler(*x) + else: + #print "MKSAMPLER: Casting %s to ConstSampler" % str(x) + return ConstSampler(x) + + +######################################## + + +## Beam-spot (origin vertex) sampling + +class PosSampler(Sampler): + """ + Sampler of position 3-vectors, for modelling a beamspot. + """ + + def __init__(self, x, y, z, t=0): + self.x = x + self.y = y + self.z = z + self.t = t + + @property + def x(self): + "x position sampler" + return self._x + @x.setter + def x(self, x): + self._x = mksampler(x) + + @property + def y(self): + "y position sampler" + return self._y + @y.setter + def y(self, y): + self._y = mksampler(y) + + @property + def z(self): + "z position sampler" + return self._z + @z.setter + def z(self, z): + self._z = mksampler(z) + + @property + def t(self): + "Time sampler" + return self._t + @t.setter + def t(self, t): + self._t = mksampler(t) + + def shoot(self): + x = self.x() + y = self.y() + z = self.z() + t = self.t() + #print "POS =", x, y, z, t + return ROOT.TLorentzVector(x, y, z, t) + + +# TODO: Make a 3-Gaussian BeamspotSampler + + +## Momentum sampling + +class MomSampler(Sampler): + """ + Base class for four-momentum sampling. + + There are many ways to unambiguously specify four-momenta. Not all are sensible/useful, + though. The following are implemented here: + * M,px,py,pz + * E,M,phi,eta + * E,M,phi,y + * E,M,phi,theta + * pT,M,phi,eta + * pT,M,phi,y + * pT,M,phi,theta + + Possibly the following (not yet implemented) could be useful: let us know if you + need one of these: + * E,px,py,pz + * pT,E,M,phi + """ + pass + + +class NullMomSampler(MomSampler): + "A momentum sampler which just returns a null vector with the given mass." + + def __init__(self, mass=0.0): + self.mass = mass + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + def shoot(self): + v4 = ROOT.TLorentzVector(0, 0, 0, self.mass) + return v4 + + +class MXYZSampler(MomSampler): + "Create a 4-momentum vector from mass, px, py, pz distributions/samplers." + + def __init__(self, px, py, pz, mass=0.0): + self.mass = mass + self.px = px + self.py = py + self.pz = pz + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def px(self): + "px sampler" + return self._px + @px.setter + def px(self, x): + self._px = mksampler(x) + + @property + def py(self): + "py sampler" + return self._py + @py.setter + def py(self, x): + self._py = mksampler(x) + + @property + def pz(self): + "pz sampler" + return self._pz + @pz.setter + def pz(self, x): + self._pz = mksampler(x) + + def shoot(self): + m = self.mass() + px = self.px() + py = self.py() + pz = self.pz() + e = math.sqrt(px**2 + py**2 + pz**2 + m**2) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class EEtaMPhiSampler(MomSampler): + "Create a 4-momentum vector from E, eta, m and phi distributions/samplers." + + # TODO: ensure that E >= m! + + def __init__(self, energy, eta, mass=0.0, phi=[0, TWOPI]): + self.energy = energy + self.eta = eta + self.mass = mass + self.phi = phi + + @property + def energy(self): + "Energy sampler" + return self._e + @energy.setter + def energy(self, x): + self._e = mksampler(x) + + @property + def eta(self): + "Pseudorapidity sampler" + return self._eta + @eta.setter + def eta(self, x): + self._eta = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + eta = - ln(tan(theta/2)) / 2 + => theta = 2 atan( exp(-eta) ) + """ + eta = self.eta() + theta = 2 * math.atan(math.exp(-eta)) + e = self.energy() + m = self.mass() + p = math.sqrt( e**2 - m**2 ) + pz = p * math.cos(theta) + pt = p * math.sin(theta) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class ERapMPhiSampler(MomSampler): + "Create a 4-momentum vector from E, y, m and phi distributions." + + # TODO: ensure that E >= m! + + def __init__(self, energy, rap, mass=0.0, phi=[0, TWOPI]): + self.energy = energy + self.rap = rap + self.mass = mass + self.phi = phi + + @property + def energy(self): + "Energy sampler" + return self._e + @energy.setter + def energy(self, x): + self._e = mksampler(x) + + @property + def rap(self): + "Rapidity sampler" + return self._rap + @rap.setter + def rap(self, x): + self._rap = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + y = 0.5 * ln((E+pz)/(E-pz)) + -> (E^2 - pz^2) exp(2y) = (E+pz)^2 + & (E^2 - pz^2) exp(-2y) = (E-pz)^2 + -> E = sqrt(pt^2 + m^2) cosh(y) + -> pz = sqrt(pt^2 + m^2) sinh(y) + -> sqrt(pt^2 + m^2) = E / cosh(y) + """ + e = self.energy() + y = self.rap() + sqrt_pt2_m2 = e / math.cosh(y) + pz = sqrt_pt2_m2 * math.sinh(y) + m = self.mass() + pt = math.sqrt( sqrt_pt2_m2**2 - m**2 ) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class EThetaMPhiSampler(MomSampler): + "Create a 4-momentum vector from E, theta, m and phi distributions/samplers." + + # TODO: ensure that E >= m! + + def __init__(self, energy, theta, mass=0.0, phi=[0, TWOPI]): + self.energy = energy + self.theta = theta + self.mass = mass + self.phi = phi + + @property + def energy(self): + "Energy sampler" + return self._e + @energy.setter + def energy(self, x): + self._e = mksampler(x) + + @property + def theta(self): + "Polar angle sampler" + return self._theta + @theta.setter + def theta(self, x): + self._theta = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + p = sqrt(e^2 - m^2) + pz = p cos(theta) + pt = p sin(theta) + """ + e = self.energy() + m = self.mass() + p = math.sqrt( e**2 - m**2 ) + theta = self.theta() + pz = p * math.cos(theta) + pt = p * math.sin(theta) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class PtEtaMPhiSampler(MomSampler): + "Create a 4-momentum vector from pt, eta, m and phi distributions/samplers." + + def __init__(self, pt, eta, mass=0.0, phi=[0, TWOPI]): + self.pt = pt + self.eta = eta + self.mass = mass + self.phi = phi + + @property + def pt(self): + "Transverse momentum sampler" + return self._pt + @pt.setter + def pt(self, x): + self._pt = mksampler(x) + + @property + def eta(self): + "Pseudorapidity sampler" + return self._eta + @eta.setter + def eta(self, x): + self._eta = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + eta = - ln(tan(theta/2)) / 2 + => theta = 2 atan( exp(-eta) ) + """ + eta = self.eta() + theta = 2 * math.atan(math.exp(-eta)) + pt = self.pt() + p = pt / math.sin(theta) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + pz = p * math.cos(theta) + m = self.mass() + e = math.sqrt( p**2 + m**2 ) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class PtRapMPhiSampler(MomSampler): + "Create a 4-momentum vector from pt, y, m and phi distributions/samplers." + + def __init__(self, pt, rap, mass=0.0, phi=[0, TWOPI]): + self.pt = pt + self.rap = rap + self.mass = mass + self.phi = phi + + @property + def pt(self): + "Transverse momentum sampler" + return self._pt + @pt.setter + def pt(self, x): + self._pt = mksampler(x) + + @property + def rap(self): + "Rapidity sampler" + return self._rap + @rap.setter + def rap(self, x): + self._rap = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + y = 0.5 * ln((E+pz)/(E-pz)) + -> (E^2 - pz^2) exp(2y) = (E+pz)^2 + & (E^2 - pz^2) exp(-2y) = (E-pz)^2 + -> E = sqrt(pt^2 + m^2) cosh(y) + -> pz = sqrt(pt^2 + m^2) sinh(y) + -> sqrt(pt^2 + m^2) = E / cosh(y) + """ + pt = self.pt() + assert pt >= 0 + m = self.mass() + assert m >= 0 + sqrt_pt2_m2 = math.sqrt( pt**2 + m**2 ) + y = self.rap() + e = sqrt_pt2_m2 * math.cosh(y) + pz = sqrt_pt2_m2 * math.sinh(y) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +class PtThetaMPhiSampler(MomSampler): + "Create a 4-momentum vector from pt, theta, m and phi distributions/samplers." + + def __init__(self, pt, theta, mass=0.0, phi=[0, TWOPI]): + self.pt = pt + self.theta = theta + self.mass = mass + self.phi = phi + + @property + def pt(self): + "Transverse momentum sampler" + return self._pt + @pt.setter + def pt(self, x): + self._pt = mksampler(x) + + @property + def theta(self): + "Polar angle sampler" + return self._theta + @theta.setter + def theta(self, x): + self._theta = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + """ + p = pt / math.sin(theta) + pz = p cos(theta) + pt = p sin(theta) + E = sqrt(p^2 + m^2) + """ + theta = self.theta() + pt = self.pt() + p = pt / math.sin(theta) + phi = self.phi() + px = pt * math.cos(phi) + py = pt * math.sin(phi) + pz = p * math.cos(theta) + m = self.mass() + e = math.sqrt( p**2 + m**2 ) + v4 = ROOT.TLorentzVector(px, py, pz, e) + return v4 + + +# TODO: add the missing ways to specify/sample 4-momenta + + +########################################################### + + +## Combined samplers returning a particle configuration + + +## A default dictionary of particle masses (in MeV) +MASSES = { 22 : 0.0, # photon + 11 : 0.5, # electron + 12 : 0.0, # nu_e + 13 : 105.7, # muon + 14 : 0.0, # nu_mu + 15 : 1777.8, # tau + 16 : 0.0, # nu_tau + 2212 : 938.0, # proton + 2112 : 940.0, # neutron + 111 : 135.0, # pi0 + 211 : 140.0, # pi+- + 221 : 547.0, # eta + 321 : 494.0, # K+- + 311 : 598.0 # K0 + } + + +class SampledParticle(object): + """ + A particle object for use as a return value from the particle samplers. + """ + def __init__(self, pid=None, mom=ROOT.TLorentzVector(0,0,0,0), pos=ROOT.TLorentzVector(0,0,0,0)): + """ + Constructor/initializer: PID is the (int) PDG particle ID code + of this particle, mom is its momentum 4-vector, and pos is + the vertex 4-position (both as ROOT.TLorentzVector, in MeV). + """ + self.pid = pid + self.mom = mom + self.pos = pos + self.mass = None + + +class ParticleSampler(Sampler): + """ + A simple N-independent-particle sampler. + """ + + def __init__(self, pid=999, + mom=NullMomSampler(), + n=1, + pos=PosSampler(0, 0, 0)): + self.pid = pid + self.mom = mom + self.n = n + self.pos = pos + self.massdict = MASSES + self.mass_override = True + + @property + def pid(self): + "Particle ID code sampler" + return self._pid + @pid.setter + def pid(self, x): + self._pid = mksampler(x) + + @property + def n(self): + "Particle number sampler" + return self._n + @n.setter + def n(self, x): + self._n = mksampler(x) + + def shoot(self): + "Return a vector of sampled particles" + numparticles = self.n() + rtn = [] + for i in range(numparticles): + ## Sample the particle ID and create a particle + pid = self.pid() + p = SampledParticle(pid) + ## Pass mass info to the v4 sampler and set same generated mass + if self.mass_override and abs(pid) in self.massdict: + m = self.massdict[abs(pid)] + self.mom.mass = m + p.mass = m + # TODO: Should the particle generated_mass be set from the sampler by default? + ## Sample momentum and vertex positions into the particle + p.mom = self.mom() + p.pos = self.pos() + ## Add particle to output list + rtn.append(p) + return rtn diff --git a/Generators/ParticleGun/share/common/ParticleGun_Common.py b/Generators/ParticleGun/share/common/ParticleGun_Common.py new file mode 100644 index 0000000000000000000000000000000000000000..3fab6fb0b7c4093fe92bd0e34e57bc7093b0281a --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_Common.py @@ -0,0 +1,4 @@ +## Common setup for ParticleGun +import ParticleGun as PG +genSeq += PG.ParticleGun() +evgenConfig.generators += ["ParticleGun"] diff --git a/Generators/ParticleGun/share/common/ParticleGun_EoverP_Config.py b/Generators/ParticleGun/share/common/ParticleGun_EoverP_Config.py new file mode 100644 index 0000000000000000000000000000000000000000..8b78a953f31c253a9ead42158bf4d8b0dab77ce0 --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_EoverP_Config.py @@ -0,0 +1,66 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for E/p event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["zach.marshall@cern.ch"] + +import ParticleGun as PG +import ROOT +from ParticleGun.samplers import * +class PEtaSampler(PG.MomSampler): + "Create a 4-momentum vector from pt, eta, m and phi distributions/samplers." + + def __init__(self, momentum, eta, pid=211, phi=[0, math.pi*2.]): + self.momentum = momentum + self.eta = eta + pdg_table = ROOT.TDatabasePDG.Instance() + mass = pdg_table.GetParticle(pid).Mass() + self.mass = mass + self.phi = phi + + @property + def momentum(self): + "Momentum sampler" + return self._momentum + @momentum.setter + def momentum(self, x): + self._momentum = mksampler(x) + + @property + def eta(self): + "Pseudorapidity sampler" + return self._eta + @eta.setter + def eta(self, x): + self._eta = mksampler(x) + + @property + def mass(self): + "Mass sampler" + return self._m + @mass.setter + def mass(self, x): + self._m = mksampler(x) + + @property + def phi(self): + "Azimuthal angle sampler" + return self._phi + @phi.setter + def phi(self, x): + self._phi = mksampler(x) + + def shoot(self): + v4 = ROOT.TLorentzVector() + pt = p / math.cosh(self.eta()) + v4.SetPtEtaPhiM(pt, self.eta(), self.phi(), self.mass()) + return v4 + +a_particle = int(jofile.split('_')[-1].split('.py')[0].replace('m','-')) + +pg = PG.ParticleGun() +pg.sampler.pid = int(a_particle) #PID +pg.sampler.mom = PEtaSampler(momentum=(500,800,1000,1200,1500,2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,13000,15000,17000,20000,\ + 25000,35000,50000,75000,100000,200000,350000,500000), eta=[-0.3,0.3], pid=int(a_particle)) +genSeq += pg + diff --git a/Generators/ParticleGun/share/common/ParticleGun_FastCalo_ChargeFlip_Config.py b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_ChargeFlip_Config.py new file mode 100644 index 0000000000000000000000000000000000000000..a5399a64019b935aa729244f88c4b5c0ebe5b35f --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_ChargeFlip_Config.py @@ -0,0 +1,78 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for FastCaloSim event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["david.sosa@cern.ch"] + +import ParticleGun as PG +import ROOT + +class MyParticleSampler(PG.ParticleSampler): + def __init__(self,energy,eta,pid,shift_z=0): + self.pid = pid + self.shift_z = shift_z + pdg_table = ROOT.TDatabasePDG.Instance() + mass = pdg_table.GetParticle(self.pid()).Mass() + self.mom1 = PG.EEtaMPhiSampler(energy=energy,eta=eta,mass=mass) + + def shoot(self): + pid = self.pid() + + shift_z = self.shift_z + + mom = self.mom1.shoot() + pos_temp = mom.Vect().Unit() + + # Would it hit the barrel, or the endcap? + if abs(pos_temp.Z())/3550.<pos_temp.Perp()/1148.: # Hit the barrel! + pos_temp *= 1148./pos_temp.Perp() + else: # Hit the endcap! + pos_temp *= 3550./abs(pos_temp.Z()) + + # Shift position of vector in the Z direction + pos_temp_2 = ROOT.TVector3() + pos_temp_2.SetXYZ(pos_temp.X(), pos_temp.Y(), pos_temp.Z()+shift_z) + pos_temp_2 *= 1. / pos_temp_2.Mag(); # reduce magnitude of vector + + # recalculate; Would it hit the barrel, or the endcap? + if abs(pos_temp_2.Z())/3550.<pos_temp_2.Perp()/1148.: + pos_temp_2 *= 1148./pos_temp_2.Perp() + else: + pos_temp_2 *= 3550./abs(pos_temp_2.Z()) + + pos = ROOT.TLorentzVector(pos_temp_2.X(),pos_temp_2.Y(),pos_temp_2.Z(), pos_temp_2.Mag()) + + #print "pid ",pid + + return [ PG.SampledParticle( pid , mom , pos ) ] + +myE = float(jofile.split('_E')[1].split('_')[0]) +myZV = float(jofile.split('_')[-1].split('.py')[0].replace("m","-")) + +myPDGID = jofile.split('_pid')[1].split('_')[0].replace('n','-') +myPDGID = int(float(myPDGID.replace('p',''))) + +eta_li = [] + +if "disj" in jofile: + myLowEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[0].replace('m','-')) + myLowEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[1].replace('m','-')) + myHighEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[2].replace('m','-')) + myHighEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[3].replace('m','-')) + eta_li.extend([myLowEta1,myLowEta2,myHighEta1,myHighEta2]) + +else: + myLowEta = 0.01*float(jofile.split('eta')[1].split('_')[0].replace('m','-')) + myHighEta = 0.01*float(jofile.split('eta')[1].split('_')[1].replace('m','-')) + eta_li.extend([myLowEta,myHighEta]) + + +print "================ SETTTINGS =================" +print ("energy = ", myE) +print ("eta = ", eta_li) +print ("pid = ", myPDGID) +print ("shift_z = ", myZV) +print "============================================" + +genSeq += PG.ParticleGun() +genSeq.ParticleGun.sampler = MyParticleSampler(energy=myE,eta=eta_li,pid=(myPDGID,myPDGID),shift_z=myZV) #unmixed diff --git a/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config.py b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config.py new file mode 100644 index 0000000000000000000000000000000000000000..1b2e9a68bc5e1c1612bf2e294c58dcc472f700fb --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config.py @@ -0,0 +1,101 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for FastCaloSim event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["david.sosa@cern.ch"] + +import ParticleGun as PG +import ROOT + +class MyParticleSampler(PG.ParticleSampler): + def __init__(self,energy,eta,pid,shift_z=0): + self.pid = pid + self.shift_z = shift_z + pdg_table = ROOT.TDatabasePDG.Instance() + mass = pdg_table.GetParticle(self.pid()).Mass() + self.mom1 = PG.EEtaMPhiSampler(energy=energy,eta=eta,mass=mass) + + def shoot(self): + pid = self.pid() + + shift_z = self.shift_z + + mom = self.mom1.shoot() + pos_temp = mom.Vect().Unit() + + # Define geometry + barrelR1 = 1148.0 + barrelR2 = 120.0 + barrelR3 = 41.0 + endcapZ1 = 3550.0 + endcapZ2 = 4587.0 + + # Would it hit the barrel, or the endcap? + tanTheta = pos_temp.Perp() / abs( pos_temp.Z() ); + if tanTheta > barrelR1 / endcapZ1: + pos_temp *= barrelR1 / pos_temp.Perp() + elif tanTheta > barrelR2 / endcapZ1: + pos_temp *= endcapZ1 / abs( pos_temp.Z() ) + elif tanTheta > barrelR2 / endcapZ2: + pos_temp *= barrelR2 / pos_temp.Perp() + elif tanTheta > barrelR3 / endcapZ2: + pos_temp *= endcapZ2 / abs( pos_temp.Z() ) + else: + pos_temp *= barrelR3 / pos_temp.Perp() + + # Shift position of vector in the Z direction + pos_temp_2 = ROOT.TVector3() + pos_temp_2.SetXYZ(pos_temp.X(), pos_temp.Y(), pos_temp.Z()+shift_z) + pos_temp_2 *= 1. / pos_temp_2.Mag(); # reduce magnitude of vector + + # recalculate; Would it hit the barrel, or the endcap? + tanTheta_2 = pos_temp_2.Perp() / abs( pos_temp_2.Z() ); + if tanTheta_2 > barrelR1 / endcapZ1: + pos_temp_2 *= barrelR1 / pos_temp_2.Perp() + elif tanTheta_2 > barrelR2 / endcapZ1: + pos_temp_2 *= endcapZ1 / abs( pos_temp_2.Z() ) + elif tanTheta_2 > barrelR2 / endcapZ2: + pos_temp_2 *= barrelR2 / pos_temp_2.Perp() + elif tanTheta_2 > barrelR3 / endcapZ2: + pos_temp_2 *= endcapZ2 / abs( pos_temp_2.Z() ) + else: + pos_temp_2 *= barrelR3 / pos_temp_2.Perp() + + pos = ROOT.TLorentzVector(pos_temp_2.X(),pos_temp_2.Y(),pos_temp_2.Z(), pos_temp_2.Mag()) + + #print "pid ",pid + + return [ PG.SampledParticle( pid , mom , pos ) ] + +myE = float(jofile.split('_E')[1].split('_')[0]) +myZV = float(jofile.split('_')[-1].split('.py')[0].replace("m","-")) +myPDGID = int(float(jofile.split('_pid')[1].split('_')[0].replace('m','-'))) + +eta_li = [] + +if "disj" in jofile: + myLowEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[0].replace('m','-')) + myLowEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[1].replace('m','-')) + myHighEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[2].replace('m','-')) + myHighEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[3].replace('m','-')) + eta_li.extend([myLowEta1,myLowEta2,myHighEta1,myHighEta2]) + +else: + myLowEta = 0.01*float(jofile.split('eta')[1].split('_')[0].replace('m','-')) + myHighEta = 0.01*float(jofile.split('eta')[1].split('_')[1].replace('m','-')) + eta_li.extend([myLowEta,myHighEta]) + + +print "================ SETTTINGS =================" +print ("energy = ", myE) +print ("eta = ", eta_li) +print ("pid = ", myPDGID) +print ("shift_z = ", myZV) +print "============================================" + +genSeq += PG.ParticleGun() +if myPDGID != 22: + genSeq.ParticleGun.sampler = MyParticleSampler(energy=myE,eta=eta_li,pid=(-myPDGID,myPDGID),shift_z=myZV) +else: + genSeq.ParticleGun.sampler = MyParticleSampler(energy=myE,eta=eta_li,pid=myPDGID,shift_z=myZV) + diff --git a/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config_Erange.py b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config_Erange.py new file mode 100644 index 0000000000000000000000000000000000000000..75ebc0621e7ba4e6803ae25c20a6d7438fc45466 --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_Config_Erange.py @@ -0,0 +1,103 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for FastCaloSim event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["david.sosa@cern.ch"] + +import ParticleGun as PG +import ROOT + +class MyParticleSampler(PG.ParticleSampler): + def __init__(self,energy,eta,pid,shift_z=0): + self.pid = pid + self.shift_z = shift_z + pdg_table = ROOT.TDatabasePDG.Instance() + mass = pdg_table.GetParticle(self.pid()).Mass() + self.mom1 = PG.EEtaMPhiSampler(energy=energy,eta=eta,mass=mass) + + def shoot(self): + pid = self.pid() + + shift_z = self.shift_z + + mom = self.mom1.shoot() + pos_temp = mom.Vect().Unit() + + # Define geometry + barrelR1 = 1148.0 + barrelR2 = 120.0 + barrelR3 = 41.0 + endcapZ1 = 3550.0 + endcapZ2 = 4587.0 + + # Would it hit the barrel, or the endcap? + tanTheta = pos_temp.Perp() / abs( pos_temp.Z() ); + if tanTheta > barrelR1 / endcapZ1: + pos_temp *= barrelR1 / pos_temp.Perp() + elif tanTheta > barrelR2 / endcapZ1: + pos_temp *= endcapZ1 / abs( pos_temp.Z() ) + elif tanTheta > barrelR2 / endcapZ2: + pos_temp *= barrelR2 / pos_temp.Perp() + elif tanTheta > barrelR3 / endcapZ2: + pos_temp *= endcapZ2 / abs( pos_temp.Z() ) + else: + pos_temp *= barrelR3 / pos_temp.Perp() + + # Shift position of vector in the Z direction + pos_temp_2 = ROOT.TVector3() + pos_temp_2.SetXYZ(pos_temp.X(), pos_temp.Y(), pos_temp.Z()+shift_z) + pos_temp_2 *= 1. / pos_temp_2.Mag(); # reduce magnitude of vector + + # recalculate; Would it hit the barrel, or the endcap? + tanTheta_2 = pos_temp_2.Perp() / abs( pos_temp_2.Z() ); + if tanTheta_2 > barrelR1 / endcapZ1: + pos_temp_2 *= barrelR1 / pos_temp_2.Perp() + elif tanTheta_2 > barrelR2 / endcapZ1: + pos_temp_2 *= endcapZ1 / abs( pos_temp_2.Z() ) + elif tanTheta_2 > barrelR2 / endcapZ2: + pos_temp_2 *= barrelR2 / pos_temp_2.Perp() + elif tanTheta_2 > barrelR3 / endcapZ2: + pos_temp_2 *= endcapZ2 / abs( pos_temp_2.Z() ) + else: + pos_temp_2 *= barrelR3 / pos_temp_2.Perp() + + pos = ROOT.TLorentzVector(pos_temp_2.X(),pos_temp_2.Y(),pos_temp_2.Z(), pos_temp_2.Mag()) + + #print "pid ",pid + + return [ PG.SampledParticle( pid , mom , pos ) ] + +E_li = [] +myLowE = float(jofile.split('_E')[1].split('_')[0]) +myHighE = float(jofile.split('_E')[1].split('_')[1]) +E_li.extend([myLowE,myHighE]) + +myZV = float(jofile.split('_')[-1].split('.py')[0].replace("m","-")) +myPDGID = int(float(jofile.split('_pid')[1].split('_')[0].replace('m','-'))) + +eta_li = [] + +if "disj" in jofile: + myLowEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[0].replace('m','-')) + myLowEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[1].replace('m','-')) + myHighEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[2].replace('m','-')) + myHighEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[3].replace('m','-')) + eta_li.extend([myLowEta1,myLowEta2,myHighEta1,myHighEta2]) + +else: + myLowEta = 0.01*float(jofile.split('eta')[1].split('_')[0].replace('m','-')) + myHighEta = 0.01*float(jofile.split('eta')[1].split('_')[1].replace('m','-')) + eta_li.extend([myLowEta,myHighEta]) + + +print "================ SETTTINGS =================" +print ("energy = ", E_li) +print ("eta = ", eta_li) +print ("pid = ", myPDGID) +print ("shift_z = ", myZV) +print "============================================" + +genSeq += PG.ParticleGun() +print "E_li = ", E_li, ", eta_li = ", eta_li, ", pid = ", myPDGID, ", myZV = ", myZV +genSeq.ParticleGun.sampler = MyParticleSampler(energy=E_li,eta=eta_li,pid=myPDGID,shift_z=myZV) + diff --git a/Generators/ParticleGun/share/common/ParticleGun_FastCalo_NoChargeFlip_Config.py b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_NoChargeFlip_Config.py new file mode 100644 index 0000000000000000000000000000000000000000..7ba60ef2bc9d3a9195ada72e9a2232864f173567 --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_FastCalo_NoChargeFlip_Config.py @@ -0,0 +1,78 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for FastCaloSim event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["david.sosa@cern.ch"] + +import ParticleGun as PG +import ROOT + +class MyParticleSampler(PG.ParticleSampler): + def __init__(self,energy,eta,pid,shift_z=0): + self.pid = pid + self.shift_z = shift_z + pdg_table = ROOT.TDatabasePDG.Instance() + mass = pdg_table.GetParticle(self.pid()).Mass() + self.mom1 = PG.EEtaMPhiSampler(energy=energy,eta=eta,mass=mass) + + def shoot(self): + pid = self.pid() + + shift_z = self.shift_z + + mom = self.mom1.shoot() + pos_temp = mom.Vect().Unit() + + # Would it hit the barrel, or the endcap? + if abs(pos_temp.Z())/3550.<pos_temp.Perp()/1148.: # Hit the barrel! + pos_temp *= 1148./pos_temp.Perp() + else: # Hit the endcap! + pos_temp *= 3550./abs(pos_temp.Z()) + + # Shift position of vector in the Z direction + pos_temp_2 = ROOT.TVector3() + pos_temp_2.SetXYZ(pos_temp.X(), pos_temp.Y(), pos_temp.Z()+shift_z) + pos_temp_2 *= 1. / pos_temp_2.Mag(); # reduce magnitude of vector + + # recalculate; Would it hit the barrel, or the endcap? + if abs(pos_temp_2.Z())/3550.<pos_temp_2.Perp()/1148.: + pos_temp_2 *= 1148./pos_temp_2.Perp() + else: + pos_temp_2 *= 3550./abs(pos_temp_2.Z()) + + pos = ROOT.TLorentzVector(pos_temp_2.X(),pos_temp_2.Y(),pos_temp_2.Z(), pos_temp_2.Mag()) + + #print "pid ",pid + + return [ PG.SampledParticle( pid , mom , pos ) ] + +myE = float(jofile.split('_E')[1].split('_')[0]) +myZV = float(jofile.split('_')[-1].split('.py')[0].replace("m","-")) + +myPDGID = jofile.split('_pid')[1].split('_')[0].replace('n','-') +myPDGID = int(float(myPDGID.split('_pid')[1].split('_')[0].replace('p',''))) + +eta_li = [] + +if "disj" in jofile: + myLowEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[0].replace('m','-')) + myLowEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[1].replace('m','-')) + myHighEta1 = 0.01*float(jofile.split('eta_')[1].split('_')[2].replace('m','-')) + myHighEta2 = 0.01*float(jofile.split('eta_')[1].split('_')[3].replace('m','-')) + eta_li.extend([myLowEta1,myLowEta2,myHighEta1,myHighEta2]) + +else: + myLowEta = 0.01*float(jofile.split('eta')[1].split('_')[0].replace('m','-')) + myHighEta = 0.01*float(jofile.split('eta')[1].split('_')[1].replace('m','-')) + eta_li.extend([myLowEta,myHighEta]) + + +print "================ SETTTINGS =================" +print ("energy = ", myE) +print ("eta = ", eta_li) +print ("pid = ", myPDGID) +print ("shift_z = ", myZV) +print "============================================" + +genSeq += PG.ParticleGun() +genSeq.ParticleGun.sampler = MyParticleSampler(energy=myE,eta=eta_li,pid=(myPDGID,myPDGID),shift_z=myZV) #unmixed diff --git a/Generators/ParticleGun/share/common/ParticleGun_SamplingFraction.py b/Generators/ParticleGun/share/common/ParticleGun_SamplingFraction.py new file mode 100644 index 0000000000000000000000000000000000000000..54557f0d5d2afacedb09999acac22e02ad8576ac --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_SamplingFraction.py @@ -0,0 +1,97 @@ +#! -*- python -*- +evgenConfig.description = "Single particle gun for Sampling Fraction event generation" +evgenConfig.keywords = ["singleParticle",] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["michael.duehrssen@cern.ch"] + +import ParticleGun as PG +import ROOT, math, random + +class MyParticleSampler(PG.ParticleSampler): + """ + Projective showers starting at entrance of calorimeter, flat in eta, constant energy + """ + + def __init__(self,pid=11,momentum=50000.,eta1=0.,eta2=1.4,bec=0,radius=1500.,z=3740.5): + self.pid = pid + self.momentum = momentum + self.eta1 = eta1 + self.eta2 = eta2 + pdg_table = ROOT.TDatabasePDG.Instance() + self.mass = pdg_table.GetParticle(self.pid()).Mass() + self.bec=bec + self.radius=radius + self.z=z + + def shoot(self): + rtn=[] + eta = random.uniform(self.eta1, self.eta2) + phi = random.uniform(0, math.tau) # tau = 2 * pi + v4 = ROOT.TLorentzVector() + pt = self.momentum / math.cosh(eta) + v4.SetPtEtaPhiM(pt, eta, phi, self.mass) + if self.bec==0: + radius= self.radius + x=radius*math.cos(phi) + y=radius*math.sin(phi) + z=radius*math.sinh(eta) + else: + z=self.z + radius=z/math.sinh(eta) + x=radius*math.cos(phi) + y=radius*math.sin(phi) + t=math.sqrt(x*x+y*y+z*z) + vp = ROOT.TLorentzVector(x,y,z,t) + p = PG.SampledParticle(pid=self.pid(),mom=v4,pos=vp) + #print "E,eta,phi,mass ",e,eta,phi,self.mass," position ",x,y,z," pid=",p.pid + rtn.append(p) + return rtn + +##MC15 style with Generate_tf.py +#args=jofile.split('.py')[0] + +##MC16 style with Gen_tf.py +FIRST_DIR = (os.environ['JOBOPTSEARCHPATH']).split(":")[0] +jofiles = [f for f in os.listdir(FIRST_DIR) if (f.startswith('mc') and f.endswith('.py'))] + +print "================ SETTTINGS =================" +print ("jofiles = ", jofiles) + +### parse options from MC job-options filename +args = jofiles[0].split('.py')[0] +print ("args = ", args) + +myMomentum = float(args.split('_Mom')[1].split('_')[0]) +print ("Momentum = ", myMomentum,"MeV") + +myPDGID = int(float(args.split('_pid')[1].split('_')[0].replace('m','-'))) +print ("pid = ", myPDGID) + +myLowEta = 0.01*float(args.split('eta_')[1].split('_')[0].replace('m','-')) +print ("etalow = ", myLowEta) + +myHighEta = 0.01*float(args.split('eta_')[1].split('_')[1].replace('m','-')) +print ("etahigh = ", myHighEta) + +if "_Radius" in args: + myRadius = 0.001*float(args.split('_Radius')[1].split('_')[0]) #Argument needs to by in mum, since a "." in the filename is not allowed +else: + myRadius = 1500. +print ("radius = ", myRadius,"mm") + +if "_Z" in args: + myZ = 0.001*float(args.split('_Z')[1].split('_')[0]) #Argument needs to by in mum, since a "." in the filename is not allowed +else: + myZ = 3740.5 +print ("Z = ", myZ,"mm") + +if "bec" in args: + bec=1 +else: + bec=0 +print ("bec = ", bec) +print "============================================" + +genSeq += PG.ParticleGun() +genSeq.ParticleGun.sampler = MyParticleSampler(momentum=myMomentum,eta1=myLowEta,eta2=myHighEta,pid=myPDGID,bec=bec,radius=myRadius,z=myZ) + diff --git a/Generators/ParticleGun/share/common/ParticleGun_SingleHECO.py b/Generators/ParticleGun/share/common/ParticleGun_SingleHECO.py new file mode 100644 index 0000000000000000000000000000000000000000..8ffb36dd28235948f0ec1d298c121902267f27d1 --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_SingleHECO.py @@ -0,0 +1,74 @@ + +PDG = 10000000 + int(float(charge)*100.0) +loE = (float(mass) + 10.)*1000. +hiE = (float(mass) + 6000.)*1000. +MeVmass=float(mass)*1000. +#-------------------------------------------------------------- +# Configuration for EvgenJobTransforms +#-------------------------------------------------------------- +evgenConfig.description = "Single HECO generation for Mass=%s, Charge=%s in MC15" % (mass,charge) +evgenConfig.keywords = ["exotic", "singleParticle","highElectricChargeObject"] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["anlionti@cern.ch"] + +evgenConfig.specialConfig = 'MASS=%s;CHARGE=%s;preInclude=SimulationJobOptions/preInclude.Qball.py' % (mass,charge) + + + +#-------------------------------------------------------------- +# Configuration for ParticleGun +#-------------------------------------------------------------- +include("ParticleGun/ParticleGun_Common.py") + +import ParticleGun as PG +PG.MASSES[PDG] = float(MeVmass) +genSeq.ParticleGun.sampler.pid = (-PDG, PDG) +genSeq.ParticleGun.sampler.mom = PG.EEtaMPhiSampler(energy=[loE,hiE], eta=[-2,2]) + + +#-------------------------------------------------------------- +# Edit PDGTABLE.MeV with monopole mass +#-------------------------------------------------------------- +ALINE1="M %s %s.E+03 +0.0E+00 -0.0E+00 Monopole 0" % (PDG,mass) +ALINE2="W %s 0.E+00 +0.0E+00 -0.0E+00 Monopole 0" % (PDG) + +import os +import sys + +pdgmod = os.path.isfile('PDGTABLE.MeV') +if pdgmod is True: + os.remove('PDGTABLE.MeV') +os.system('get_files -data PDGTABLE.MeV') +f=open('PDGTABLE.MeV','a') +f.writelines(str(ALINE1)) +f.writelines('\n') +f.writelines(str(ALINE2)) +f.writelines('\n') +f.close() + +del ALINE1 +del ALINE2 + +#-------------------------------------------------------------- +# Edit G4particle_whitelist.txt with monopole +#-------------------------------------------------------------- + +ALINE1="%s qb %s.E+03 (Mev/c) lepton %s" % (PDG,mass,charge) +ALINE2="-%s qbbar %s.E+03 (Mev/c) lepton -%s" % (PDG,mass,charge) + +import os +import sys + +pdgmod = os.path.isfile('G4particle_whitelist.txt') +if pdgmod is True: + os.remove('G4particle_whitelist.txt') +os.system('get_files -data G4particle_whitelist.txt') +f=open('G4particle_whitelist.txt','a') +f.writelines(str(ALINE1)) +f.writelines('\n') +f.writelines(str(ALINE2)) +f.writelines('\n') +f.close() + +del ALINE1 +del ALINE2 diff --git a/Generators/ParticleGun/share/common/ParticleGun_SingleMonopole.py b/Generators/ParticleGun/share/common/ParticleGun_SingleMonopole.py new file mode 100644 index 0000000000000000000000000000000000000000..3a6bf0574561af0f4cab4a20e68248dcc3111bae --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_SingleMonopole.py @@ -0,0 +1,74 @@ + +PDG = 4110000 +loE = (float(monmass) + 10.)*1000. +hiE = (float(monmass) + 6000.)*1000. +MeVmass=float(monmass)*1000. +#-------------------------------------------------------------- +# Configuration for EvgenJobTransforms +#-------------------------------------------------------------- +evgenConfig.description = "Single magnetic monopole generation for Mass=%s, Gcharge=%s in MC15" % (monmass,gcharge) +evgenConfig.keywords = ["exotic", "magneticMonopole", "singleParticle"] +evgenConfig.generators = ["ParticleGun"] +evgenConfig.contact = ["anlionti@cern.ch"] + +evgenConfig.specialConfig = 'MASS=%s;GCHARGE=%s;preInclude=SimulationJobOptions/preInclude.Monopole.py' % (monmass,gcharge) + + + +#-------------------------------------------------------------- +# Configuration for ParticleGun +#-------------------------------------------------------------- +include("ParticleGun/ParticleGun_Common.py") + +import ParticleGun as PG +PG.MASSES[4110000] = float(MeVmass) +genSeq.ParticleGun.sampler.pid = (-PDG, PDG) +genSeq.ParticleGun.sampler.mom = PG.EEtaMPhiSampler(energy=[loE,hiE], eta=[-2,2]) + + +#-------------------------------------------------------------- +# Edit PDGTABLE.MeV with monopole mass +#-------------------------------------------------------------- +ALINE1="M 4110000 %s.E+03 +0.0E+00 -0.0E+00 Monopole 0" % (monmass) +ALINE2="W 4110000 0.E+00 +0.0E+00 -0.0E+00 Monopole 0" + +import os +import sys + +pdgmod = os.path.isfile('PDGTABLE.MeV') +if pdgmod is True: + os.remove('PDGTABLE.MeV') +os.system('get_files -data PDGTABLE.MeV') +f=open('PDGTABLE.MeV','a') +f.writelines(str(ALINE1)) +f.writelines('\n') +f.writelines(str(ALINE2)) +f.writelines('\n') +f.close() + +del ALINE1 +del ALINE2 + +#-------------------------------------------------------------- +# Edit G4particle_whitelist.txt with monopole +#-------------------------------------------------------------- + +ALINE1="4110000 mm %s.E+03 (Mev/c) lepton %s" % (monmass,gcharge) +ALINE2="-4110000 mmbar %s.E+03 (Mev/c) lepton -%s" % (monmass,gcharge) + +import os +import sys + +pdgmod = os.path.isfile('G4particle_whitelist.txt') +if pdgmod is True: + os.remove('G4particle_whitelist.txt') +os.system('get_files -data G4particle_whitelist.txt') +f=open('G4particle_whitelist.txt','a') +f.writelines(str(ALINE1)) +f.writelines('\n') +f.writelines(str(ALINE2)) +f.writelines('\n') +f.close() + +del ALINE1 +del ALINE2 diff --git a/Generators/ParticleGun/share/common/ParticleGun_egammaET.py b/Generators/ParticleGun/share/common/ParticleGun_egammaET.py new file mode 100644 index 0000000000000000000000000000000000000000..04ea9b92a3e209afc279d743307dff393f1d8839 --- /dev/null +++ b/Generators/ParticleGun/share/common/ParticleGun_egammaET.py @@ -0,0 +1,51 @@ +__doc__ = "Holds a 4-momentum sampler according to the egamma Et spectrum" + +import ParticleGun as PG +from GaudiKernel.SystemOfUnits import GeV + +def dbnFermiDirac(x,mu,kT): + import math + arg = (x-mu)/kT + if arg < -20 : # avoid numerical underflows + result = 1 + elif arg > 20 : # avoid numerical overflows + result = 0 + else : + div = math.exp(arg)+1 + result = 1/div + return result + +class egammaETSampler(PG.PtEtaMPhiSampler): + "4-momentum sampler according to the egamma Et spectrum." + def __init__(self, pid, eta=[-2.5, 2.5], phi=[0, PG.TWOPI], + mu1 = 0.5, kT1 = 0.1, mu2 = 200, kT2 = 20, y0 = 0.005, PtMin = 0 , PtMax = 3e3, nBins=None): + """ + Parameters for the MVA-shaped spectrum : higher density in the < 100 GeV range + PtMin = 0 # minimum Pt + PtMax = 3000 # maximum Pt (3 TeV) + nBins # number of bins (one every 100 MeV by default) + mu1 = 0.5 # mu1,kT1 : smooth but steep ramp-up from 0 to 1 GeV (requested by TauCP) + kT1 = 0.1 + mu2 = 200 # mu2,kT2 : smooth, slow ramp-down in the 100-300 GeV range + kT2 = 20 + y0 = 0.005 # y0 : baseline for low-density at high ET up to PtMax + """ + self.m = PG.MASSES[abs(pid)] + self.eta = eta + self.phi = phi + + # Create and fill a very fine-grained histogram + from ROOT import TH1D + etSpectrumFullRange = TH1D("ETSpectrumFullRange", + "Reference ET spectrum for egamma MVA calib", + int(nBins or (PtMax - PtMin)*10), PtMin , PtMax) + for i in xrange(etSpectrumFullRange.GetNbinsX()): + x = etSpectrumFullRange.GetBinCenter(i+1) + y1 = dbnFermiDirac(x,mu1,kT1) + y2 = dbnFermiDirac(x,mu2,kT2) + y = y0 - y1 + y2 + etSpectrumFullRange.SetBinContent(i+1,y) + self.hist = PG.TH1(etSpectrumFullRange) #< wrap *after* populating + + def pt(self): + return self.hist.GetRandom() * GeV diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_constenergy_flateta.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_constenergy_flateta.py new file mode 100644 index 0000000000000000000000000000000000000000..3c3cb0321b37e7f3d5ec3fcfc2602b2f1cba2cb0 --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_constenergy_flateta.py @@ -0,0 +1,17 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG +pg = PG.ParticleGun() +pg.randomSeed = 123456 +pg.sampler.pid = {11,-11,211,111} +pg.sampler.mom = PG.EEtaMPhiSampler(energy=10000, eta=[-2,2]) +topSeq += pg + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_correlated.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_correlated.py new file mode 100644 index 0000000000000000000000000000000000000000..cb0a9437388d3b21fffd744c67cfe590dbddaf4e --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_correlated.py @@ -0,0 +1,34 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG + +class MyParticleSampler(PG.ParticleSampler): + "A special sampler with two _correlated_ particles." + + def __init__(self): + self.mom1 = PG.PtEtaMPhiSampler(pt=25000, eta=[-2,2]) + + def shoot(self): + "Return a vector of sampled particles" + p1 = PG.SampledParticle(11, self.mom1.shoot()) + eta1 = p1.mom.Eta() + phi1 = p1.mom.Phi() + # TODO: will phi be properly wrapped into range? + mom2 = PG.PtEtaMPhiSampler(pt=25000, + eta=[eta1-0.5, eta1+0.5], + phi=[phi1-0.5, phi1+0.5]) + p2 = PG.SampledParticle(11, mom2.shoot()) + return [p1, p2] + +topSeq += PG.ParticleGun() +topSeq.ParticleGun.randomSeed = 123456 +topSeq.ParticleGun.sampler = MyParticleSampler() + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_corrhist.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_corrhist.py new file mode 100644 index 0000000000000000000000000000000000000000..7c0cd41b88e35f0290b137e5eebe80296a90b3ca --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_corrhist.py @@ -0,0 +1,41 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +## ROOT 2D histogram sampling alg (in ParticleGun.histsampling) by Andy Buckley +## Thanks to Alejandro Alonso for the initial Athena example on which this is based. + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG + +class PtEtaHistParticleSampler(PG.ParticleSampler): + "Particle sampler with correlated pT and eta from a 2D histogram." + + def __init__(self, pid, histfile, num=100): + self.pid = PG.mksampler(pid) + self.hist = PG.TH2(histfile, "h_pt_eta") + self.numparticles = num + + def shoot(self): + "Return a vector of sampled particles from the provided pT--eta histogram" + particles = [] + for i in xrange(self.numparticles): + ptrand, etarand = self.hist.GetRandom() + ptrand *= 1000 # NB. This _particular_ histogram is in GeV, but Athena needs MeV! + # TODO: Provide 4-mom construction functions to avoid building this one-time sampler + pid = self.pid() + mom = PG.PtEtaMPhiSampler(pt=ptrand, eta=etarand, mass=PG.MASSES[abs(pid)]) + p = PG.SampledParticle(pid, mom()) + #print p.mom.Pt(), "\t", p.mom.Eta(), "\t", p.mom.Phi(), "\t", p.mom.M() + particles.append(p) + return particles + +topSeq += PG.ParticleGun() +topSeq.ParticleGun.randomSeed = 123456 +topSeq.ParticleGun.sampler = PtEtaHistParticleSampler(11, "data_histos_el_1470pt.root") + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatcurvature_flatip.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatcurvature_flatip.py new file mode 100644 index 0000000000000000000000000000000000000000..38233563de9673b1d9ebd1ae434b57f6051ae70e --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatcurvature_flatip.py @@ -0,0 +1,41 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG + +class MyParticleSampler(PG.ParticleSampler): + """ + A special sampler to generate single particles flat in 1/pT and in + impact parameter to the beam, with flat z0. + """ + + def __init__(self): + psamp = PG.PtEtaMPhiSampler(pt=PG.InvSampler(4000, 400000), eta=[0.1,0.3], phi=[0.3, 0.5]) + xsamp = PG.PosSampler(0, 0, [-150,150], 0) + PG.ParticleSampler.__init__(self, pid={13,-13}, mom=psamp, pos=xsamp) + self.ip = PG.mksampler([-2,2]) + + def shoot(self): + "Return a vector of sampled particles" + ps = PG.ParticleSampler.shoot(self) + assert len(ps) == 1 + p = ps[0] + from math import sqrt + m = -p.mom.X() / p.mom.Y() #< gradient of azimuthal IP sampling line, perp to mom + x = self.ip() / sqrt(1 + m**2) #< just decomposing sampled IP into x component... + y = m*x #< ... and y-component + p.pos.SetX(x) + p.pos.SetY(m*x) + return [p] + +topSeq += PG.ParticleGun() +topSeq.ParticleGun.randomSeed = 123456 +topSeq.ParticleGun.sampler = MyParticleSampler() + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatpt_2particle.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatpt_2particle.py new file mode 100644 index 0000000000000000000000000000000000000000..97ed64f8857e82dbcaeb06085fc84d84eb246c0b --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_flatpt_2particle.py @@ -0,0 +1,20 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG +pg = PG.ParticleGun() +pg.randomSeed = 123456 +pg.samplers.append(PG.ParticleSampler()) # add a second sampler +pg.samplers[0].pid = (-13, 13) # cycle mu+- +pg.samplers[0].mom = PG.PtEtaMPhiSampler(pt=[4000, 100000], eta=[1.0, 3.2]) # flat in pt and +ve eta +pg.samplers[1].pid = (13, -13) # cycle mu-+ +pg.samplers[1].mom = PG.PtEtaMPhiSampler(pt=[4000, 100000], eta=[-3.2, -1.0]) # flat in pt and -ve eta +topSeq += pg + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_fwd_sequence.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_fwd_sequence.py new file mode 100644 index 0000000000000000000000000000000000000000..d1d4746fb7b7002fb8e096058c1b2b5d1c4eb348 --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_fwd_sequence.py @@ -0,0 +1,19 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG +pg = PG.ParticleGun() +pg.randomSeed = 123456 +pg.sampler.pid = (2112, 22, 2112, 22) +pg.sampler.mom = PG.EThetaMPhiSampler(energy=(1360000, 500000, 1360000, 500000), + theta=(0, 0, PG.PI, PG.PI)) +pg.sampler.pos = PG.PosSampler(x=[-120,-100], y=[-10,10], z=203950) +topSeq += pg + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Generators/ParticleGun/share/examples/jobOption.ParticleGun_vtx.py b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_vtx.py new file mode 100644 index 0000000000000000000000000000000000000000..cdacb7ff5a678cb95894a39a14f0ead507c41a4b --- /dev/null +++ b/Generators/ParticleGun/share/examples/jobOption.ParticleGun_vtx.py @@ -0,0 +1,18 @@ +#! -*- python -*- + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +include("GeneratorUtils/StdEvgenSetup.py") +theApp.EvtMax = 100 + +import ParticleGun as PG +pg = PG.ParticleGun() +pg.randomSeed = 123456 +pg.sampler.pid = 13 +pg.sampler.pos = PG.PosSampler(x=3140.0, y=[-154.134,154.134], z=[4938.76,5121.29], t=5929.7) +pg.sampler.mom = PG.EEtaMPhiSampler(energy=100000, eta=1.25, phi=0.0) +topSeq += pg + +include("GeneratorUtils/postJO.CopyWeights.py") +include("GeneratorUtils/postJO.PoolOutput.py") +include("GeneratorUtils/postJO.DumpMC.py") diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx index eae5fd1e07a8e70ec9bcec697d3deeb4da41d4d0..4f3a48084e7c3e7e2357844508fed2c17ac8de46 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.cxx @@ -80,6 +80,8 @@ EmulsionDataBase::EmulsionDataBase(const EmulsionGeoModelAthenaComps * athenaCom m_emulsionPlates = rdbSvc->getRecordsetPtr("EmulsionPlates", versionTag, versionNode, "FASERDD"); msg(MSG::DEBUG) << "Table EmulsionPlates Fetched" << endmsg; + m_emulsionSupport = rdbSvc->getRecordsetPtr("EmulsionSupport", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table EmulsionSupport Fetched" << endmsg; } const EmulsionGeoModelAthenaComps* EmulsionDataBase::athenaComps() const { return m_athenaComps; } @@ -91,6 +93,8 @@ IRDBRecordset_ptr EmulsionDataBase::scalingTable() const {return m_scalingTable; // //const IRDBRecord* EmulsionDataBase::atls() const {return *m_atls)[0];} IRDBRecordset_ptr EmulsionDataBase::topLevelTable() const {return m_topLevel;} +IRDBRecordset_ptr EmulsionDataBase::emulsionSupportTable() const {return m_emulsionSupport;} + // IRDBRecordset_ptr EmulsionDataBase::conditionsTable() const {return m_conditions;} // const IRDBRecord* EmulsionDataBase::conditions() const {return (*m_conditions)[0];} diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h index 35bf120c7a04cfe5ecaa88effd524785642271a2..879a5e01012fb257d283c568c0688eb4557fbe19 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDataBase.h @@ -25,6 +25,7 @@ public: IRDBRecordset_ptr weightTable() const; IRDBRecordset_ptr scalingTable() const; IRDBRecordset_ptr topLevelTable() const; + IRDBRecordset_ptr emulsionSupportTable() const; const IRDBRecord* emulsionGeneral() const; const IRDBRecord* emulsionFilm() const; @@ -54,6 +55,7 @@ private: IRDBRecordset_ptr m_emulsionGeneral; IRDBRecordset_ptr m_emulsionFilm; IRDBRecordset_ptr m_emulsionPlates; + IRDBRecordset_ptr m_emulsionSupport; }; diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx index 25fc89125f7974ef00f89ae2899a67a7b68d2551..30cb89edb936f0d61397ac6bc6522d0a7636d07d 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionDetectorFactory.cxx @@ -14,6 +14,7 @@ #include "EmulsionGeometryManager.h" #include "EmulsionMaterialManager.h" #include "EmulsionGeneralParameters.h" +#include "EmulsionSupportParameters.h" #include "NeutrinoReadoutGeometry/Version.h" #include "NeutrinoReadoutGeometry/NeutrinoCommonItems.h" #include "NeutrinoReadoutGeometry/NeutrinoDD_Defs.h" @@ -143,13 +144,16 @@ void EmulsionDetectorFactory::create(GeoPhysVol *world) // The tree tops get added to world. We name it "neutrino" though. GeoPhysVol *neutrino = world; + // const EmulsionSupportParameters* emulsionSupport = m_geometryManager->supportParameters(); + // msg(MSG::ALWAYS) << "Found " << emulsionSupport->supportElements().size() << " emulsion support elements" << endmsg; + const EmulsionGeneralParameters * emulsionGeneral = m_geometryManager->generalParameters(); GeoTrf::Transform3D emulsionTransform = emulsionGeneral->partTransform("Emulsion"); - std::string stationA_Label = "StationA"; + std::string stationA_Label = "StationA"; - bool stationA_Present = emulsionGeneral->partPresent(stationA_Label); + bool stationA_Present = emulsionGeneral->partPresent(stationA_Label); // // Plate is the same for all stations diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx index 679678fba793dddd06cb3b2e13169f57a08a1b0d..dca5f2d2ad0b16f977f58026d9e86854dcc0ec4c 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.cxx @@ -11,6 +11,7 @@ #include "EmulsionPlatesParameters.h" #include "EmulsionDataBase.h" #include "EmulsionGeneralParameters.h" +#include "EmulsionSupportParameters.h" #include "EmulsionGeoModel/EmulsionGeoModelAthenaComps.h" EmulsionGeometryManager::EmulsionGeometryManager(EmulsionDataBase* rdb) @@ -23,6 +24,7 @@ EmulsionGeometryManager::EmulsionGeometryManager(EmulsionDataBase* rdb) m_filmParameters = std::make_unique<EmulsionFilmParameters>(m_rdb); m_platesParameters = std::make_unique<EmulsionPlatesParameters>(m_rdb); m_generalParameters = std::make_unique<EmulsionGeneralParameters>(m_rdb); + m_supportParameters = std::make_unique<EmulsionSupportParameters>(m_rdb); m_distortedMatManager = std::make_unique<NeutrinoDD::DistortedMaterialManager>(); } @@ -79,6 +81,12 @@ EmulsionGeometryManager::generalParameters() const return m_generalParameters.get(); } +const EmulsionSupportParameters * +EmulsionGeometryManager::supportParameters() const +{ + return m_supportParameters.get(); +} + const NeutrinoDD::DistortedMaterialManager * EmulsionGeometryManager::distortedMatManager() const { @@ -95,6 +103,7 @@ EmulsionGeometryManager::operator=(const EmulsionGeometryManager& right) { m_filmParameters.reset(new EmulsionFilmParameters(m_rdb)); m_platesParameters.reset(new EmulsionPlatesParameters(m_rdb)); m_generalParameters.reset(new EmulsionGeneralParameters(m_rdb)); + m_supportParameters.reset(new EmulsionSupportParameters(m_rdb)); m_distortedMatManager.reset(new NeutrinoDD::DistortedMaterialManager()); } return *this; @@ -108,5 +117,6 @@ EmulsionGeometryManager::EmulsionGeometryManager(const EmulsionGeometryManager& m_filmParameters.reset(new EmulsionFilmParameters(m_rdb)); m_platesParameters.reset(new EmulsionPlatesParameters(m_rdb)); m_generalParameters.reset(new EmulsionGeneralParameters(m_rdb)); + m_supportParameters.reset(new EmulsionSupportParameters(m_rdb)); m_distortedMatManager.reset(new NeutrinoDD::DistortedMaterialManager()); } diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h index a068602e658925ba5a363bd571d0486fa08a04ec..989520e43084b873c843cebc5f0e01546f375a8d 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionGeometryManager.h @@ -18,6 +18,7 @@ class EmulsionFilmParameters; class EmulsionPlatesParameters; class EmulsionDataBase; class EmulsionGeneralParameters; +class EmulsionSupportParameters; class EmulsionGeoModelAthenaComps; class EmulsionGeometryManager { @@ -43,6 +44,7 @@ public: const EmulsionFilmParameters* filmParameters() const; const EmulsionPlatesParameters* platesParameters() const; const EmulsionGeneralParameters* generalParameters() const; + const EmulsionSupportParameters* supportParameters() const; const NeutrinoDD::DistortedMaterialManager* distortedMatManager() const; EmulsionGeometryManager& operator=(const EmulsionGeometryManager& right); @@ -58,6 +60,7 @@ private: std::unique_ptr<EmulsionFilmParameters> m_filmParameters; std::unique_ptr<EmulsionPlatesParameters> m_platesParameters; std::unique_ptr<EmulsionGeneralParameters> m_generalParameters; + std::unique_ptr<EmulsionSupportParameters> m_supportParameters; std::unique_ptr<NeutrinoDD::DistortedMaterialManager> m_distortedMatManager; }; diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx index 7424987e17929d371002aa7f778e7a2a0ae08b06..5b97b1a1ca65476d0c61d285c549b675a44e24bf 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.cxx @@ -40,23 +40,26 @@ EmulsionPlates::EmulsionPlates(const std::string & name, m_logVolume = preBuild(); } - void EmulsionPlates::getParameters() { const EmulsionGeneralParameters * generalParameters = m_geometryManager->generalParameters(); const EmulsionPlatesParameters * platesParameters = m_geometryManager->platesParameters(); + const EmulsionSupportParameters* supportParameters = m_geometryManager->supportParameters(); - m_width = platesParameters->platesWidth(); - m_height = platesParameters->platesHeight(); - m_thickness = platesParameters->platesThickness(); - m_material = m_materials->getMaterial(platesParameters->platesMaterial()); + m_tungstenWidth = platesParameters->platesWidth(); + m_tungstenHeight = platesParameters->platesHeight(); + m_tungstenThickness = platesParameters->platesThickness(); + m_absorberMaterial = m_materials->getMaterial(platesParameters->platesMaterial()); + m_airMaterial = m_materials->gasMaterial(); m_nBasesPerModule = generalParameters->nBasesPerModule(); m_nModules = generalParameters->nModules(); m_firstBaseZ = generalParameters->firstBaseZ(); m_lastBaseZ = generalParameters->lastBaseZ(); + m_supportElements = supportParameters->supportElements(); + m_detectorManager->numerology().setNumBasesPerModule(m_nBasesPerModule); } @@ -66,12 +69,36 @@ EmulsionPlates::preBuild() // create child element m_base = new EmulsionBase("Base", m_detectorManager, m_geometryManager, m_materials); + double width = m_tungstenWidth/2; + double height = m_tungstenHeight/2; + // double thickness = m_tungstenThickness/2; + double minZ = -m_tungstenThickness/2; + double maxZ = m_tungstenThickness/2; + + for (auto e : m_supportElements) + { + width = std::max(width, std::max(std::abs(e.x + e.dx/2),std::abs(e.x - e.dx/2))); + height = std::max(height, std::max(std::abs(e.y + e.dy/2),std::abs(e.y - e.dy/2))); + minZ = std::min(minZ, e.z - e.dz/2); + maxZ = std::max(maxZ, e.z + e.dz/2); + const GeoBox* supportShape = new GeoBox(e.dx/2, e.dy/2, e.dz/2); + GeoLogVol* supportLog = new GeoLogVol(e.label, supportShape, m_materials->getMaterial(e.mat)); + m_supportVolumes.push_back(supportLog); + } + + m_width = 2 * width; + m_height = 2 * height; + m_thickness = maxZ - minZ; + m_zShift = -(maxZ + minZ)/2; // Build a box to hold everything const GeoBox* platesShape = new GeoBox(0.5*m_width, 0.5*m_height, 0.5*m_thickness); // GeoLogVol * platesLog = new GeoLogVol(getName(), platesShape, m_materials->gasMaterial()); - GeoLogVol * platesLog = new GeoLogVol(getName(), platesShape, m_material); + GeoLogVol * platesLog = new GeoLogVol(getName(), platesShape, m_airMaterial); + + const GeoBox* absorberShape = new GeoBox(m_tungstenWidth/2, m_tungstenHeight/2, m_tungstenThickness/2); + m_absorberVolume = new GeoLogVol(getName()+"_absorber", absorberShape, m_absorberMaterial); // m_baseboardPos = new GeoTrf::Translate3D(0.0, 0.0, 0.0); // m_frontPos = new GeoTrf::Translate3D(0.0, 0.0, -(m_baseThickness + m_filmThickness)/2); @@ -83,7 +110,12 @@ EmulsionPlates::preBuild() GeoVPhysVol * EmulsionPlates::build(EmulsionIdentifier id) { - GeoFullPhysVol * plates = new GeoFullPhysVol(m_logVolume); + GeoFullPhysVol * plates = new GeoFullPhysVol(m_logVolume); + GeoPhysVol * physAbsorber = new GeoPhysVol(m_absorberVolume); + GeoAlignableTransform* absorberTransform = new GeoAlignableTransform( GeoTrf::Translate3D { 0.0, 0.0, m_zShift} ); + plates->add(absorberTransform); + plates->add(new GeoNameTag("Absorber")); + plates->add(physAbsorber); int nBases = 0; int nBasesTotal = m_nModules * m_nBasesPerModule; @@ -97,16 +129,33 @@ EmulsionPlates::build(EmulsionIdentifier id) for (int base = 0; base < m_nBasesPerModule; base++) { id.setBase(base); + // GeoAlignableTransform* theTransform = new GeoAlignableTransform( GeoTrf::Translate3D {0.0, 0.0, m_zShift + m_firstBaseZ + ((m_lastBaseZ - m_firstBaseZ)/(nBasesTotal-1))*nBases++} ); + // plates->add(theTransform); + // plates->add(new GeoNameTag("Base#"+intToString(module*100 + base))); + // plates->add(new GeoIdentifierTag(module*100 + base)); + // GeoVPhysVol* physBase = m_base->build(id); + // plates->add(physBase); GeoAlignableTransform* theTransform = new GeoAlignableTransform( GeoTrf::Translate3D {0.0, 0.0, m_firstBaseZ + ((m_lastBaseZ - m_firstBaseZ)/(nBasesTotal-1))*nBases++} ); - plates->add(theTransform); - plates->add(new GeoNameTag("Base#"+intToString(module*100 + base))); - plates->add(new GeoIdentifierTag(module*100 + base)); + physAbsorber->add(theTransform); + physAbsorber->add(new GeoNameTag("Base#"+intToString(module*100 + base))); + physAbsorber->add(new GeoIdentifierTag(module*100 + base)); GeoVPhysVol* physBase = m_base->build(id); - plates->add(physBase); + physAbsorber->add(physBase); m_detectorManager->addAlignableTransform(1, id.getFilmId(), theTransform, physBase); } m_detectorManager->numerology().useModule(module); } + auto iv = m_supportVolumes.begin(); + for (auto e : m_supportElements) + { + GeoVPhysVol* pv = new GeoPhysVol(*iv); + GeoTransform* theTransform = new GeoTransform( GeoTrf::Translate3D {e.x, e.y, e.z + m_zShift}); + plates->add(theTransform); + plates->add(new GeoNameTag(e.label)); + plates->add(pv); + iv++; + } + return plates; } diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h index b827265b9f0753fd834f24d0d051eb02ba2a5675..7af04358b41879a5f23155d0367a5c6d4f137b09 100644 --- a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionPlates.h @@ -6,6 +6,7 @@ #define EMULSIONGEOMODEL_EMULSIONPLATES_H #include "EmulsionComponentFactory.h" +#include "EmulsionSupportParameters.h" #include "EmulsionBase.h" #include "GeoPrimitives/GeoPrimitives.h" #include "GeoModelKernel/GeoDefinitions.h" @@ -28,6 +29,7 @@ public: double thickness() const {return m_thickness;} double width() const {return m_width;} double height() const {return m_height;} + double shift() const {return m_zShift;} virtual GeoVPhysVol * build(EmulsionIdentifier id); @@ -38,14 +40,23 @@ private: double m_thickness; double m_width; double m_height; - const GeoMaterial * m_material; + double m_tungstenThickness; + double m_tungstenWidth; + double m_tungstenHeight; + double m_zShift; + const GeoMaterial * m_absorberMaterial; + const GeoMaterial * m_airMaterial; int m_nModules; int m_nBasesPerModule; double m_firstBaseZ; double m_lastBaseZ; + std::vector<EmulsionSupportParameters::SupportElement> m_supportElements; + EmulsionBase* m_base; + GeoLogVol* m_absorberVolume; + std::vector<GeoLogVol*> m_supportVolumes; }; diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.cxx b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7ed41a0050ee15c99c6dc4f840cce3e572ee663e --- /dev/null +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.cxx @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "EmulsionSupportParameters.h" +#include "EmulsionGeometryManager.h" + +#include "EmulsionDataBase.h" + +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <cmath> + + +EmulsionSupportParameters::EmulsionSupportParameters(EmulsionDataBase* rdb) +{ + m_rdb = rdb; +} + +std::vector<EmulsionSupportParameters::SupportElement> +EmulsionSupportParameters::supportElements() const +{ + std::vector<SupportElement> result; + IRDBRecordset_ptr table = m_rdb->emulsionSupportTable(); + if (table.get() == nullptr) return result; + + size_t numElements = table->size(); + for (size_t i = 0; i < numElements; i++) + { + const IRDBRecord* element = (*table)[i]; + result.push_back(SupportElement(element->getDouble("DX"), + element->getDouble("DY"), + element->getDouble("DZ"), + element->getDouble("X"), + element->getDouble("Y"), + element->getDouble("Z"), + element->getString("MATERIAL"), + element->getString("LABEL"))); + } + + return result; + +} \ No newline at end of file diff --git a/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.h b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..b357bfcb02fcbf06b90db67d2e26a7b16254287f --- /dev/null +++ b/Neutrino/NeutrinoDetDescr/EmulsionGeoModel/src/EmulsionSupportParameters.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef EmulsionGeoModel_EmulsionSupportParameters_H +#define EmulsionGeoModel_EmulsionSupportParameters_H + +#include <string> +#include <vector> + +class EmulsionDataBase; + +class EmulsionSupportParameters { + +public: + + // Constructor + EmulsionSupportParameters(EmulsionDataBase* rdb); + + + class SupportElement + { + public: + SupportElement(double width, double height, double thickness, double xPos, double yPos, double zPos, std::string material, std::string name) + : dx{width}, dy{height}, dz{thickness}, x{xPos}, y{yPos}, z{zPos}, mat{material}, label{name} {} + double dx; + double dy; + double dz; + double x; + double y; + double z; + std::string mat; + std::string label; + }; + + // General + + std::vector<SupportElement> supportElements() const; + + private: + EmulsionDataBase * m_rdb; + +}; + + +#endif // EmulsionGeoModel_EmulsionSupportParameters_H diff --git a/README.md b/README.md index 0b334b19690dd56d1a0bae23fd5c0849c1cd83dd..2d7e57abb75b58112939efb7b2726607bcfb6ec3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ source ./setup.sh Don't omit the dot in the `source ./setup.sh` command! -It can be convenient to alias the "asetup --input=calypso/asetup.faser" to something like "fsetup" +It can be convenient to alias the command "asetup --input=calypso/asetup.faser" to something like "fsetup" **Lxplus/afs setup** @@ -44,12 +44,12 @@ When compiling, CERN IT recommends using condor to submit batch jobs. The basics * It is now essential to use the tags `ConfigFlags.GeoModel.FaserVersion` and `ConfigFlags.IOVDb.GlobalTag` in a consistent way. If nothing is specified the first option (baseline) should be chosen by default. -** `ConfigFlags.GeoModel.FaserVersion = "FASER-01"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-01` enables the baseline TI-12 detector +** `ConfigFlags.GeoModel.FaserVersion = "FASER-01"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-01` enables the baseline TI-12 detector (obsolete and no longer supported) -** `ConfigFlags.GeoModel.FaserVersion = "FASER-02"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the interface tracker and repositioned Veto +** `ConfigFlags.GeoModel.FaserVersion = "FASER-02"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the interface tracker and repositioned Veto (obsolete and no longer supported) -** `ConfigFlags.GeoModel.FaserVersion = "FASERNU-02"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the full FaserNu (IFT + emulsion) setup +** `ConfigFlags.GeoModel.FaserVersion = "FASERNU-03"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-02` enables the full FaserNu (IFT + emulsion) setup ** `ConfigFlags.GeoModel.FaserVersion = "FASER-TB00"` and `ConfigFlags.IOVDb.GlobalTag = OFLCOND-FASER-TB00` enables the 2021 Test-beam setup. -* The command `lsetup "lcgenv -p LCG_98python3_ATLAS_8 x86_64-centos7-gcc8-opt sqlite"` may be necessary to avoid errors when generating a database +* The command `source /cvmfs/sft.cern.ch/lcg/releases/LCG_101_ATLAS_6/sqlite/3320300/x86_64-centos7-gcc11-opt/sqlite-env.sh` may be necessary to avoid errors when generating a database diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml index 13d77e21372822bd19cbdb4c5b7ae3046d27693f..54552a212ae62ae33650c186ea6529c383524518 100644 --- a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml +++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator.xml @@ -4,6 +4,7 @@ <label name="Veto" value="1" /> <label name="Trigger" value="2" /> <label name="Preshower" value="3" /> + <label name="VetoNu" value="4" /> </field> <region> @@ -26,4 +27,12 @@ <range field="plate" minvalue="0" maxvalue="1" /> <range field="pmt" minvalue="0" maxvalue="0" /> </region> -</IdDictionary> \ No newline at end of file + + <region> + <range field="part" value="VetoNu" /> + <range field="station" minvalue="0" maxvalue="0" /> + <range field="plate" minvalue="0" maxvalue="1" /> + <range field="pmt" minvalue="0" maxvalue="0" /> + </region> + +</IdDictionary> diff --git a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml index a4b3f0c98f58f58bf64ef490bf6d6f446bb0256b..71fd8298645674dae3bd0d54c411d099742a6416 100644 --- a/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml +++ b/Scintillator/ScintDetDescr/ScintIdDictFiles/data/IdDictScintillator_TB00.xml @@ -4,8 +4,8 @@ <label name="Veto" value="1" /> <label name="Trigger" value="2" /> <label name="Preshower" value="3" /> + <label name="VetoNu" value="4" /> </field> - <region> <range field="part" value="Veto" /> <range field="station" minvalue="0" maxvalue="0" /> @@ -24,4 +24,10 @@ <range field="plate" minvalue="0" maxvalue="1" /> <range field="pmt" minvalue="0" maxvalue="0" /> </region> -</IdDictionary> \ No newline at end of file + <region> + <range field="part" value="VetoNu" /> + <range field="station" minvalue="0" maxvalue="0" /> + <range field="plate" minvalue="0" maxvalue="1" /> + <range field="pmt" minvalue="0" maxvalue="0" /> + </region> +</IdDictionary> diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt b/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt index 6dc9408f8ffb04b6a32144d7d03dc338ab9ad8bb..5874ae0de68035f16d71d47887a95cdfb8f857a6 100644 --- a/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt +++ b/Scintillator/ScintDetDescr/ScintIdentifier/CMakeLists.txt @@ -11,6 +11,7 @@ find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) # Component(s) in the package: atlas_add_library( ScintIdentifier src/VetoID.cxx + src/VetoNuID.cxx src/TriggerID.cxx src/PreshowerID.cxx # src/ScintillatorID.cxx diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h index 9f3832c16e73859facfe81aa17f4864cf63a9b19..0968f0b4136d48216bcea7305e4933dac7337e2d 100644 --- a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h +++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/ScintIdentifierDict.h @@ -16,5 +16,6 @@ #include "ScintIdentifier/PreshowerID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" #endif // SCINTIDENTIFIER_SCINTIDENTIFIERDICT_H diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/VetoNuID.h b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/VetoNuID.h new file mode 100644 index 0000000000000000000000000000000000000000..064f9a132378b5cc5740103b402e88d32c48d84d --- /dev/null +++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/VetoNuID.h @@ -0,0 +1,541 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SCINTIDENTIFIER_VETONUID_H +#define SCINTIDENTIFIER_VETONUID_H +/** + * @file VetoNuID.h + * + * @brief This is an Identifier helper class for the VetoNu + * subdetector. This class is a factory for creating compact + * Identifier objects and IdentifierHash or hash ids. And it also + * allows decoding of these ids. + * + */ + +//<<<<<< INCLUDES >>>>>> + +#include "FaserDetDescr/FaserDetectorID.h" +#include "Identifier/Identifier.h" +#include "Identifier/IdentifierHash.h" +#include "Identifier/Range.h" +#include "Identifier/IdHelper.h" +#include "IdDict/IdDictFieldImplementation.h" +#include "AthenaKernel/CLASS_DEF.h" + +#include <string> +#include <assert.h> +#include <algorithm> + +//<<<<<< PUBLIC DEFINES >>>>>> +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> + +class IdDictDictionary; + +//<<<<<< PUBLIC VARIABLES >>>>>> +//<<<<<< PUBLIC FUNCTIONS >>>>>> +//<<<<<< CLASS DECLARATIONS >>>>>> + +/** + ** @class VetoNuID + ** + ** @brief This is an Identifier helper class for the VetoNu + ** subdetector. This class is a factory for creating compact + ** Identifier objects and IdentifierHash or hash ids. And it also + ** allows decoding of these ids. + ** + ** Definition and the range of values for the levels of the + ** identifier are: + ** + ** @verbatim + ** element range meaning + ** ------- ----- ------- + ** + ** station 0 to 1 longitudinal location + ** plate 0 to 1 two plates per station + ** pmt 0 single pmt per plate + ** + ** @endverbatim + ** + */ +class VetoNuID : public FaserDetectorID +{ +public: + + /// @name public typedefs + //@{ + typedef Identifier::size_type size_type; + typedef std::vector<Identifier>::const_iterator const_id_iterator; + typedef MultiRange::const_identifier_factory const_expanded_id_iterator; + //@} + + /// @name strutors + //@{ + VetoNuID(void); + virtual ~VetoNuID(void) = default; + //@} + + /// @name Creators for plate ids and pmt ids + //@{ + /// For a single station + Identifier station_id ( int station ) const; + Identifier station_id ( int station, + bool checks) const; + + /// For a station from a plate id + Identifier station_id ( const Identifier& plate_id ) const; + + /// For a single plate + Identifier plate_id ( int station, + int plate ) const; + Identifier plate_id ( int station, + int plate, + bool checks) const; + + /// For a single plate from a pmt id + Identifier plate_id ( const Identifier& pmt_id ) const; + + /// From hash - optimized + Identifier plate_id ( IdentifierHash plate_hash ) const; + + /// For an individual pmt + Identifier pmt_id ( int station, + int plate, + int pmt ) const; + + Identifier pmt_id ( int station, + int plate, + int pmt, + bool check ) const; + + Identifier pmt_id ( const Identifier& plate_id, + int pmt ) const; + + //@} + + + /// @name Hash table maximum sizes + //@{ + size_type plate_hash_max (void) const; + size_type pmt_hash_max (void) const; + //@} + + /// @name Access to all ids + //@{ + /// Iterators over full set of ids. Plate iterator is sorted + const_id_iterator plate_begin (void) const; + const_id_iterator plate_end (void) const; + /// For pmt ids, only expanded id iterators are available. Use + /// following "pmt_id" method to obtain a compact identifier + const_expanded_id_iterator pmt_begin (void) const; + const_expanded_id_iterator pmt_end (void) const; + //@} + + + /// @name Optimized accessors - ASSUMES id IS a vetonu id, i.e. NOT other + //@{ + /// wafer hash from id - optimized + IdentifierHash plate_hash (Identifier plate_id) const; + + /// Values of different levels (failure returns 0) + int station (const Identifier& id) const; + int plate (const Identifier& id) const; + int pmt (const Identifier& id) const; + + /// Max/Min values for each field (-999 == failure) + int station_max (const Identifier& id) const; + int plate_max (const Identifier& id) const; + int pmt_max (const Identifier& id) const; + //@} + + /// @name module navigation + //@{ + /// Previous plate in z + int get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const; + /// Next plate in z + int get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const; + // /// Previous wafer hash in phi (return == 0 for neighbor found) + // int get_prev_in_phi (const IdentifierHash& id, IdentifierHash& prev) const; + // /// Next wafer hash in phi (return == 0 for neighbor found) + // int get_next_in_phi (const IdentifierHash& id, IdentifierHash& next) const; + // /// Previous wafer hash in eta (return == 0 for neighbor found) + // int get_prev_in_eta (const IdentifierHash& id, IdentifierHash& prev) const; + // /// Next wafer hash in eta (return == 0 for neighbor found) + // int get_next_in_eta (const IdentifierHash& id, IdentifierHash& next) const; + // /// Wafer hash on other side + // int get_other_side (const IdentifierHash& id, IdentifierHash& other) const; + + // // To check for when phi wrap around may be needed, use + // bool is_phi_module_max(const Identifier& id) const; + // /// For the barrel + // bool is_eta_module_min(const Identifier& id) const; + // /// For the barrel + // bool is_eta_module_max(const Identifier& id) const; + //@} + + /// @name contexts to distinguish plate id from pixel id + //@{ + IdContext plate_context (void) const; + IdContext pmt_context (void) const; + //@} + + /// @name methods from abstract interface - slower than opt version + //@{ + /// Create compact id from hash id (return == 0 for OK) + virtual int get_id (const IdentifierHash& hash_id, + Identifier& id, + const IdContext* context = 0) const; + + /// Create hash id from compact id (return == 0 for OK) + virtual int get_hash (const Identifier& id, + IdentifierHash& hash_id, + const IdContext* context = 0) const; + //@} + + /// Return the lowest bit position used in the channel id + int base_bit (void) const; + + /// Calculate a channel offset between the two identifiers. + Identifier::diff_type calc_offset(const Identifier& base, + const Identifier& target) const; + + /// Create an identifier with a given base and channel offset + Identifier pmt_id_offset(const Identifier& base, + Identifier::diff_type offset) const; + + /// @name interaction with id dictionary + //@{ + /// Create strip Identifier from expanded id, which is returned by the + /// id_iterators + Identifier pmt_id (const ExpandedIdentifier& pmt_id) const; + + /// Create expanded id from compact id (return == 0 for OK) + void get_expanded_id (const Identifier& id, + ExpandedIdentifier& exp_id, + const IdContext* context = 0) const; + + /// Initialization from the identifier dictionary + virtual int initialize_from_dictionary(const IdDictMgr& dict_mgr); + + /// Tests of packing + void test_plate_packing (void) const; + //@} + +private: + + enum {NOT_VALID_HASH = 64000}; + + typedef std::vector<Identifier> id_vec; + typedef id_vec::const_iterator id_vec_it; + typedef std::vector<unsigned short> hash_vec; + typedef hash_vec::const_iterator hash_vec_it; + + void plate_id_checks ( int station, + int plate ) const; + + void pmt_id_checks ( int station, + int plate, + int pmt ) const; + + + int initLevelsFromDict(void); + + int init_hashes(void); + + int init_neighbors(void); + + // Temporary method for adapting an identifier for the MultiRange + // check - MR is missing the InnerDetector level + // Identifier idForCheck (const Identifier& id) const; + + size_type m_vetonu_region_index; + size_type m_SCINT_INDEX; + size_type m_VETONU_INDEX; + size_type m_STATION_INDEX; + size_type m_PLATE_INDEX; + size_type m_PMT_INDEX; + + const IdDictDictionary* m_dict; + MultiRange m_full_plate_range; + MultiRange m_full_pmt_range; + size_type m_plate_hash_max; + size_type m_pmt_hash_max; + // Range::field m_barrel_field; + id_vec m_plate_vec; + hash_vec m_prev_z_plate_vec; + hash_vec m_next_z_plate_vec; + // hash_vec m_prev_phi_wafer_vec; + // hash_vec m_next_phi_wafer_vec; + // hash_vec m_prev_eta_wafer_vec; + // hash_vec m_next_eta_wafer_vec; + // bool m_hasRows ; + + IdDictFieldImplementation m_scint_impl ; + IdDictFieldImplementation m_vetonu_impl ; + IdDictFieldImplementation m_station_impl ; + IdDictFieldImplementation m_plate_impl ; + IdDictFieldImplementation m_pmt_impl ; +}; + + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> + +///////////////////////////////////////////////////////////////////////////// +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> +///////////////////////////////////////////////////////////////////////////// + +//using the macros below we can assign an identifier (and a version) +//This is required and checked at compile time when you try to record/retrieve +CLASS_DEF(VetoNuID, 247779284, 1) + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::station_id ( int station, + bool checks) const +{ + + // Build identifier + Identifier result((Identifier::value_type)0); + + // Pack fields independently + m_scint_impl.pack (scint_field_value(), result); + m_vetonu_impl.pack (vetonu_field_value(), result); + m_station_impl.pack (station, result); + // Do checks + if(checks) + { + plate_id_checks ( station, 0 ); + } + + return result; +} + +inline Identifier +VetoNuID::station_id ( int station ) const +{ + return station_id (station, do_checks()); +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::station_id ( const Identifier& plate_id ) const +{ + Identifier result(plate_id); + // Reset the plate and pmt fields + m_plate_impl.reset(result); + m_pmt_impl.reset(result); + return (result); +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::plate_id ( int station, + int plate, + bool checks) const +{ + // Build identifier + Identifier result((Identifier::value_type)0); + + // Pack fields independently + m_scint_impl.pack (scint_field_value(), result); + m_vetonu_impl.pack (vetonu_field_value(), result); + m_station_impl.pack (station, result); + m_plate_impl.pack (plate, result); + + // Do checks + if(checks) + { + plate_id_checks ( station, plate ); + } + return result; +} + +inline Identifier +VetoNuID::plate_id ( int station, + int plate ) const +{ + return plate_id (station, plate, do_checks()); +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::plate_id ( const Identifier& pmt_id ) const +{ + Identifier result(pmt_id); + // reset the pmt field + m_pmt_impl.reset(result); + return (result); +} + +//---------------------------------------------------------------------------- +inline Identifier VetoNuID::plate_id ( IdentifierHash plate_hash ) const +{ + return (m_plate_vec[plate_hash]); +} + +//---------------------------------------------------------------------------- +inline IdentifierHash VetoNuID::plate_hash (Identifier plate_id) const +{ + // MsgStream log(m_msgSvc, "VetoNuID"); + // log << MSG::VERBOSE << "m_plate_vec size: " << m_plate_vec.size() << endmsg; + // log << MSG::VERBOSE << "input id = " << plate_id << endmsg; + // for (size_t i = 0; i < m_plate_vec.size(); i++) + // { + // log << MSG::VERBOSE << "Hash = " << i << " : ID = " << m_plate_vec[i] << endmsg; + // } + id_vec_it it = std::lower_bound(m_plate_vec.begin(), + m_plate_vec.end(), + plate_id); + // Require that plate_id matches the one in vector + if (it != m_plate_vec.end() && plate_id == (*it)) { + return (it - m_plate_vec.begin()); + } + IdentifierHash result; + return (result); // return hash in invalid state +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::pmt_id ( int station, + int plate, + int pmt, + bool checks) const +{ + // Build identifier + Identifier result((Identifier::value_type)0); + + // Pack fields independently + m_scint_impl.pack (scint_field_value(), result); + m_vetonu_impl.pack (vetonu_field_value(),result); + m_station_impl.pack (station, result); + m_plate_impl.pack (plate, result); + m_pmt_impl.pack (pmt, result); + + // Do checks + if(checks) { + pmt_id_checks ( station, plate, pmt ); + } + return result; +} + +inline Identifier +VetoNuID::pmt_id ( int station, + int plate, + int pmt ) const +{ + return pmt_id (station, plate, pmt, do_checks()); +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::pmt_id (const ExpandedIdentifier& id) const +{ + // Build identifier + Identifier result((Identifier::value_type)0); + + // Pack fields independently + m_scint_impl.pack (scint_field_value(), result); + m_vetonu_impl.pack (vetonu_field_value(), result); + m_station_impl.pack (id[m_STATION_INDEX], result); + m_plate_impl.pack (id[m_PLATE_INDEX], result); + m_pmt_impl.pack (id[m_PMT_INDEX], result); + + // Do checks + if(m_do_checks) + { + pmt_id_checks ( id[m_STATION_INDEX], + id[m_PLATE_INDEX], + id[m_PMT_INDEX]); + } + return result; +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::pmt_id ( const Identifier& plate_id, int pmt ) const +{ + // Build identifier + Identifier result(plate_id); + + // Reset strip and then add in value + m_pmt_impl.reset (result); + m_pmt_impl.pack (pmt, result); + + if(m_do_checks) + { + pmt_id_checks ( station(result), + plate(result), + pmt ); + } + return result; +} + +//---------------------------------------------------------------------------- +inline Identifier::diff_type +VetoNuID::calc_offset(const Identifier& base, const Identifier& target) const +{ + Identifier::diff_type tval = static_cast<Identifier::diff_type>(target.get_compact() >> base_bit()); + Identifier::diff_type bval = static_cast<Identifier::diff_type>(base.get_compact() >> base_bit()); + return (tval - bval); +} + +//---------------------------------------------------------------------------- +inline Identifier +VetoNuID::pmt_id_offset(const Identifier& base, + Identifier::diff_type offset) const +{ + Identifier::value_type bval = base.get_compact() >> base_bit(); + return Identifier((bval + offset) << base_bit()); +} + +//---------------------------------------------------------------------------- +inline int +VetoNuID::base_bit ( void ) const +{ + int base = static_cast<int>(m_pmt_impl.shift()); // lowest field base + return (base > 32) ? 32 : base; + // max base is 32 so we can still read old strip id's and differences + // from non-SLHC releases. +} + +//---------------------------------------------------------------------------- +inline IdContext +VetoNuID::plate_context (void) const +{ + ExpandedIdentifier id; + return (IdContext(id, 0, m_PLATE_INDEX)); +} + +//---------------------------------------------------------------------------- +inline IdContext +VetoNuID::pmt_context (void) const +{ + ExpandedIdentifier id; + return (IdContext(id, 0, m_PMT_INDEX)); +} + +//---------------------------------------------------------------------------- +inline int +VetoNuID::station (const Identifier& id) const +{ + return (m_station_impl.unpack(id)); +} + +//---------------------------------------------------------------------------- +inline int +VetoNuID::plate (const Identifier& id) const +{ + return (m_plate_impl.unpack(id)); +} + +//---------------------------------------------------------------------------- +inline int +VetoNuID::pmt (const Identifier& id) const +{ + return (m_pmt_impl.unpack(id)); +} + + +#endif // SCINTIDENTIFIER_VETONUID_H diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml index 543856daa22bebedab8c75cff790f07b7f7468f5..bebeff9ec46d1ef9554a176ba64038033469d21b 100644 --- a/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml +++ b/Scintillator/ScintDetDescr/ScintIdentifier/ScintIdentifier/selection.xml @@ -3,6 +3,7 @@ <class name="ScintillatorID" /> --> <class name="VetoID" /> + <class name="VetoNuID" /> <class name="TriggerID" /> <class name="PreshowerID" /> </lcgdict> diff --git a/Scintillator/ScintDetDescr/ScintIdentifier/src/VetoNuID.cxx b/Scintillator/ScintDetDescr/ScintIdentifier/src/VetoNuID.cxx new file mode 100644 index 0000000000000000000000000000000000000000..837b3c892da1ec7a338bd1e6a7c0da18d9eeeeca --- /dev/null +++ b/Scintillator/ScintDetDescr/ScintIdentifier/src/VetoNuID.cxx @@ -0,0 +1,1030 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + Scintillator identifier package + ------------------------------------------- +***************************************************************************/ + +//<<<<<< INCLUDES >>>>>> +#include "GaudiKernel/MsgStream.h" + +#include "ScintIdentifier/VetoNuID.h" +#include "Identifier/IdentifierHash.h" +#include "IdDict/IdDictDefs.h" +#include <set> +#include <algorithm> +#include <iostream> + +//<<<<<< PRIVATE DEFINES >>>>>> +//<<<<<< PRIVATE CONSTANTS >>>>>> +//<<<<<< PRIVATE TYPES >>>>>> +//<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>> +//<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>> +//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> +//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> +//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>> +//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>> + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + + +VetoNuID::VetoNuID(void) + : + m_vetonu_region_index(0), + m_SCINT_INDEX(0), + m_VETONU_INDEX(1), + m_STATION_INDEX(2), + m_PLATE_INDEX(3), + m_PMT_INDEX(4), + m_dict(0), + m_plate_hash_max(0), + m_pmt_hash_max(0) +{ +} + +void +VetoNuID::plate_id_checks ( int station, + int plate ) const +{ + + // Check that id is within allowed range + + // Fill expanded id + ExpandedIdentifier id; + id << scint_field_value() << vetonu_field_value() + << station << plate; + + if (!m_full_plate_range.match(id)) { // module range check is sufficient + MsgStream log(m_msgSvc, "VetoNuID"); + log << MSG::ERROR << " VetoNuID::plate_id result is NOT ok. ID, range " + << (std::string)id << " " << (std::string)m_full_plate_range << endmsg; + } +} + +void +VetoNuID::pmt_id_checks ( int station, + int plate, + int pmt) const +{ + + // Check that id is within allowed range + + // Fill expanded id + ExpandedIdentifier id; + id << scint_field_value() << vetonu_field_value() + << station << plate << pmt; + + if (!m_full_pmt_range.match(id)) { + MsgStream log(m_msgSvc, "VetoNuID"); + log << MSG::ERROR << " VetoNuID::pmt_id result is NOT ok. ID, range " + << (std::string)id << " " << (std::string)m_full_pmt_range << std::endl; + } +} + +int +VetoNuID::station_max(const Identifier& id) const +{ + // get max from dictionary + ExpandedIdentifier expId; + IdContext plate_context1 = plate_context(); + get_expanded_id(id, expId, &plate_context1); + for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) { + const Range& range = m_full_plate_range[i]; + if (range.match(expId)) { + const Range::field& station_field = range[m_STATION_INDEX]; + if (station_field.has_maximum()) { + return (station_field.get_maximum()); + } + } + } + return (-999); // default +} + +int +VetoNuID::pmt_max (const Identifier& id) const +{ + ExpandedIdentifier expId; + IdContext station_context(expId, 0, m_STATION_INDEX); + get_expanded_id(id, expId, &station_context); + int result = -999; + for (unsigned int i = 0; i < m_full_pmt_range.size(); ++i) { + const Range& range = m_full_pmt_range[i]; + if (range.match(expId)) { + const Range::field& pmt_field = range[m_PMT_INDEX]; + if (pmt_field.has_maximum()) { + int pmt = pmt_field.get_maximum(); + if (result < pmt) result = pmt; + } + } + } + return (result); +} + +int +VetoNuID::plate_max(const Identifier& id) const +{ + // get max from dictionary + ExpandedIdentifier expId; + IdContext plate_context1 = plate_context(); + get_expanded_id(id, expId, &plate_context1); + for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) { + const Range& range = m_full_plate_range[i]; + if (range.match(expId)) { + const Range::field& plate_field = range[m_PLATE_INDEX]; + if (plate_field.has_maximum()) { + return (plate_field.get_maximum()); + } + } + } + return -1; +} + +int +VetoNuID::initialize_from_dictionary(const IdDictMgr& dict_mgr) +{ + MsgStream log(m_msgSvc, "VetoNuID"); + log << MSG::INFO << "Initialize from dictionary" << endmsg; + + // Check whether this helper should be reinitialized + if (!reinitialize(dict_mgr)) { + log << MSG::INFO << "Request to reinitialize not satisfied - tags have not changed" << endmsg; + return (0); + } + else { + if (m_msgSvc) { + log << MSG::DEBUG << "(Re)initialize" << endmsg; + } + else { + std::cout << " DEBUG (Re)initialize" << std::endl; + } + } + + // init base object + if(FaserDetectorID::initialize_from_dictionary(dict_mgr)) return (1); + + // Register version of InnerDetector dictionary + if (register_dict_tag(dict_mgr, "Scintillator")) return(1); + + m_dict = dict_mgr.find_dictionary ("Scintillator"); + if(!m_dict) { + log << MSG::ERROR << " VetoNuID::initialize_from_dict - cannot access Scintillator dictionary " << endmsg; + return 1; + } + + // Initialize the field indices + if(initLevelsFromDict()) return (1); + + // + // Build multirange for the valid set of identifiers + // + + + // Find value for the field Scintillator + const IdDictDictionary* faserDict = dict_mgr.find_dictionary ("FASER"); + int scintField = -1; + if (faserDict->get_label_value("subdet", "Scintillator", scintField)) { + log << MSG::ERROR << "Could not get value for label 'Scintillator' of field 'subdet' in dictionary " + << faserDict->m_name + << endmsg; + return (1); + } + + // Find value for the field VetoNu + int vetonuField = -1; + if (m_dict->get_label_value("part", "VetoNu", vetonuField)) { + log << MSG::ERROR << "Could not get value for label 'VetoNu' of field 'part' in dictionary " + << m_dict->m_name + << endmsg; + return (1); + } + if (m_msgSvc) { + log << MSG::DEBUG << " VetoNuID::initialize_from_dict " + << "Found field values: VetoNu " + << vetonuField + << std::endl; + } + else { + std::cout << " DEBUG VetoNuID::initialize_from_dict " + << "Found field values: VetoNu " + << vetonuField + << std::endl; + } + + // Set up id for region and range prefix + ExpandedIdentifier region_id; + region_id.add(scintField); + region_id.add(vetonuField); + Range prefix; + m_full_plate_range = m_dict->build_multirange(region_id, prefix, "plate"); + m_full_pmt_range = m_dict->build_multirange(region_id, prefix); + + // Setup the hash tables + if(init_hashes()) return (1); + + // Setup hash tables for finding neighbors + if(init_neighbors()) return (1); + + if (m_msgSvc) { + log << MSG::INFO << " VetoNuID::initialize_from_dict " << endmsg; + log << MSG::DEBUG + << "Plate range -> " << (std::string)m_full_plate_range + << endmsg; + log << MSG::DEBUG + << "Pmt range -> " << (std::string)m_full_pmt_range + << endmsg; + } + else { + std::cout << " INFO VetoNuID::initialize_from_dict " << std::endl; + std::cout << " DEBUG Plate range -> " << (std::string)m_full_plate_range + << std::endl; + std::cout << " DEBUG Pmt range -> " << (std::string)m_full_pmt_range + << std::endl; + } + + return 0; +} + +int +VetoNuID::init_hashes(void) +{ + + // + // create a vector(s) to retrieve the hashes for compact ids. For + // the moment, we implement a hash for plates but NOT for pmts + // + MsgStream log(m_msgSvc, "VetoNuID"); + // plate hash + m_plate_hash_max = m_full_plate_range.cardinality(); + m_plate_vec.resize(m_plate_hash_max); + unsigned int nids = 0; + std::set<Identifier> ids; + for (unsigned int i = 0; i < m_full_plate_range.size(); ++i) { + const Range& range = m_full_plate_range[i]; + Range::const_identifier_factory first = range.factory_begin(); + Range::const_identifier_factory last = range.factory_end(); + for (; first != last; ++first) { + const ExpandedIdentifier& exp_id = (*first); + Identifier id = plate_id(exp_id[m_STATION_INDEX], + exp_id[m_PLATE_INDEX]); + if(!(ids.insert(id)).second) { + log << MSG::ERROR << " VetoNuID::init_hashes " + << " Error: duplicated id for plate id. nid " << nids + << " compact id " << id.getString() + << " id " << (std::string)exp_id << endmsg; + return (1); + } + nids++; + } + } + if(ids.size() != m_plate_hash_max) { + log << MSG::ERROR << " VetoNuID::init_hashes " + << " Error: set size NOT EQUAL to hash max. size " << ids.size() + << " hash max " << m_plate_hash_max + << endmsg; + return (1); + } + + nids = 0; + std::set<Identifier>::const_iterator first = ids.begin(); + std::set<Identifier>::const_iterator last = ids.end(); + for (; first != last && nids < m_plate_vec.size(); ++first) { + m_plate_vec[nids] = (*first); + nids++; + } + + // pmt hash - we do not keep a vec for the pmts + m_pmt_hash_max = m_full_pmt_range.cardinality(); + + return (0); +} + + int + VetoNuID::get_prev_in_z(const IdentifierHash& id, IdentifierHash& prev) const + { + unsigned short index = id; + if (index < m_prev_z_plate_vec.size()) + { + if (m_prev_z_plate_vec[index] == NOT_VALID_HASH) return (1); + prev = m_prev_z_plate_vec[index]; + return (0); + } + return (1); + } + + int + VetoNuID::get_next_in_z(const IdentifierHash& id, IdentifierHash& next) const + { + unsigned short index = id; + if (index < m_next_z_plate_vec.size()) + { + if (m_next_z_plate_vec[index] == NOT_VALID_HASH) return (1); + next = m_next_z_plate_vec[index]; + return (0); + } + return (1); + } + +// int +// VetoNuID::get_prev_in_phi(const IdentifierHash& id, IdentifierHash& prev) const +// { +// unsigned short index = id; +// if (index < m_prev_phi_wafer_vec.size()) { +// if (m_prev_phi_wafer_vec[index] == NOT_VALID_HASH) return (1); +// prev = m_prev_phi_wafer_vec[index]; +// return (0); +// } +// return (1); +// } + +// int +// VetoNuID::get_next_in_phi(const IdentifierHash& id, IdentifierHash& next) const +// { +// unsigned short index = id; +// if (index < m_next_phi_wafer_vec.size()) { +// if (m_next_phi_wafer_vec[index] == NOT_VALID_HASH) return (1); +// next = m_next_phi_wafer_vec[index]; +// return (0); +// } +// return (1); +// } + +// int +// VetoNuID::get_prev_in_eta(const IdentifierHash& id, IdentifierHash& prev) const +// { +// unsigned short index = id; +// if (index < m_prev_eta_wafer_vec.size()) { +// if (m_prev_eta_wafer_vec[index] == NOT_VALID_HASH) return (1); +// prev = m_prev_eta_wafer_vec[index]; +// return (0); +// } +// return (1); +// } + +// int +// VetoNuID::get_next_in_eta(const IdentifierHash& id, IdentifierHash& next) const +// { +// unsigned short index = id; +// if (index < m_next_eta_wafer_vec.size()) { +// if (m_next_eta_wafer_vec[index] == NOT_VALID_HASH) return (1); +// next = m_next_eta_wafer_vec[index]; +// return (0); +// } +// return (1); +// } + +// int +// VetoNuID::get_other_side (const IdentifierHash& hashId, IdentifierHash& other) const +// { +// if (m_dict) { +// // get max from dictionary +// Identifier id; +// IdContext wafer_context1 = wafer_context(); +// if(!get_id(hashId, id, &wafer_context1)) { +// other = side(id) ? hashId - 1 : hashId + 1; +// return (0); +// } +// } +// return (1); +// } + +int +VetoNuID::init_neighbors(void) +{ + // + // create a vector(s) to retrieve the hashes for compact ids for + // plate neighbors. + // + MsgStream log(m_msgSvc, "VetoNuID"); + + m_prev_z_plate_vec.resize(m_plate_hash_max, NOT_VALID_HASH); + m_next_z_plate_vec.resize(m_plate_hash_max, NOT_VALID_HASH); + for (unsigned int i = 0; i < m_full_plate_range.size(); i++) + { + const Range& range = m_full_plate_range[i]; + const Range::field& station_field = range[m_STATION_INDEX]; + const Range::field& plate_field = range[m_PLATE_INDEX]; + Range::const_identifier_factory first = range.factory_begin(); + Range::const_identifier_factory last = range.factory_end(); + for (; first != last; ++first) + { + const ExpandedIdentifier& exp_id = (*first); + ExpandedIdentifier::element_type previous_plate; + ExpandedIdentifier::element_type next_plate; + ExpandedIdentifier::element_type previous_station; + ExpandedIdentifier::element_type next_station; + bool pplate = plate_field.get_previous(exp_id[m_PLATE_INDEX], previous_plate); + bool nplate = plate_field.get_next (exp_id[m_PLATE_INDEX], next_plate); + bool pstation = station_field.get_previous(exp_id[m_STATION_INDEX], previous_station); + bool nstation = station_field.get_next (exp_id[m_STATION_INDEX], next_station); + + IdContext pcontext = plate_context(); + + IdentifierHash hash_id; + Identifier originalId = plate_id(exp_id[m_STATION_INDEX], + exp_id[m_PLATE_INDEX]); + + if (get_hash(originalId, hash_id, &pcontext)) + { + log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get hash, exp/compact " + << show_to_string(originalId, &pcontext) + << " " << (std::string)m_full_plate_range << endmsg; + return (1); + } + + // index for the subsequent arrays + unsigned short index = hash_id; + assert (hash_id < m_prev_z_plate_vec.size()); + assert (hash_id < m_next_z_plate_vec.size()); + + if (pplate) { + // Get previous plate hash id + ExpandedIdentifier expId = exp_id; + expId[m_PLATE_INDEX] = previous_plate; + Identifier id = plate_id(expId[m_STATION_INDEX], + expId[m_PLATE_INDEX]); + + if (get_hash(id, hash_id, &pcontext)) { + log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get previous plate hash, exp/compact " << id.getString() << " " + << endmsg; + return (1); + } + m_prev_z_plate_vec[index] = hash_id; + } + else if (pstation) + { + ExpandedIdentifier expId = exp_id; + expId[m_STATION_INDEX] = previous_station; + ExpandedIdentifier stationId; + stationId.add(expId[m_SCINT_INDEX]); + stationId.add(expId[m_VETONU_INDEX]); + stationId.add(previous_station); + Range prefix; + MultiRange stationPlateRange = m_dict->build_multirange(stationId, prefix, "plate"); + const Range::field& upstream_plate_field = range[m_PLATE_INDEX]; + if (upstream_plate_field.has_maximum()) + { + expId[m_PLATE_INDEX] = upstream_plate_field.get_maximum(); + Identifier id = plate_id(expId[m_STATION_INDEX], + expId[m_PLATE_INDEX]); + if (get_hash(id, hash_id, &pcontext)) { + log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get last plate hash from previous station, exp/compact " << id.getString() << " " + << endmsg; + return (1); + } + m_prev_z_plate_vec[index] = hash_id; + } + else + { + log << MSG::ERROR << "VetoNuID::init_neighbors - unable to get plate_max for previous station, exp/compact " << originalId.getString() << " " + << endmsg; + return (1); + } + } + + if (nplate) { + // Get next plate hash id + ExpandedIdentifier expId = exp_id; + expId[m_PLATE_INDEX] = next_plate; + Identifier id = plate_id(expId[m_STATION_INDEX], + expId[m_PLATE_INDEX]); + + if (get_hash(id, hash_id, &pcontext)) { + log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get next plate hash, exp/compact " << id.getString() << " " + << endmsg; + return (1); + } + m_next_z_plate_vec[index] = hash_id; + } + else if (nstation) + { + ExpandedIdentifier expId = exp_id; + expId[m_STATION_INDEX] = next_station; + ExpandedIdentifier stationId; + stationId.add(expId[m_SCINT_INDEX]); + stationId.add(expId[m_VETONU_INDEX]); + stationId.add(next_station); + Range prefix; + MultiRange stationPlateRange = m_dict->build_multirange(stationId, prefix, "plate"); + const Range::field& downstream_plate_field = range[m_PLATE_INDEX]; + if (downstream_plate_field.has_minimum()) + { + expId[m_PLATE_INDEX] = downstream_plate_field.get_minimum(); + Identifier id = plate_id(expId[m_STATION_INDEX], + expId[m_PLATE_INDEX]); + if (get_hash(id, hash_id, &pcontext)) { + log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get previous plate hash from next station, exp/compact " << id.getString() << " " + << endmsg; + return (1); + } + m_next_z_plate_vec[index] = hash_id; + } + else + { + log << MSG::ERROR << "VetoNuID::init_neighbors - unable to get plate_min for next station, exp/compact " << originalId.getString() << " " + << endmsg; + return (1); + } + } + + } + } + + // m_prev_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH); + // m_next_phi_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH); + // m_prev_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH); + // m_next_eta_wafer_vec.resize(m_wafer_hash_max, NOT_VALID_HASH); + + // for (unsigned int i = 0; i < m_full_wafer_range.size(); ++i) { + // const Range& range = m_full_wafer_range[i]; + // const Range::field& phi_field = range[m_PHI_MODULE_INDEX]; + // const Range::field& eta_field = range[m_ETA_MODULE_INDEX]; + // Range::const_identifier_factory first = range.factory_begin(); + // Range::const_identifier_factory last = range.factory_end(); + // for (; first != last; ++first) { + // const ExpandedIdentifier& exp_id = (*first); + // ExpandedIdentifier::element_type previous_phi; + // ExpandedIdentifier::element_type next_phi; + // ExpandedIdentifier::element_type previous_eta; + // ExpandedIdentifier::element_type next_eta; + // bool pphi = phi_field.get_previous(exp_id[m_PHI_MODULE_INDEX], previous_phi); + // bool nphi = phi_field.get_next (exp_id[m_PHI_MODULE_INDEX], next_phi); + // bool peta = eta_field.get_previous(exp_id[m_ETA_MODULE_INDEX], previous_eta); + // bool neta = eta_field.get_next (exp_id[m_ETA_MODULE_INDEX], next_eta); + + // IdContext wcontext = wafer_context(); + + // // First get primary hash id + // IdentifierHash hash_id; + // Identifier id = wafer_id(exp_id[m_BARREL_EC_INDEX], + // exp_id[m_LAYER_DISK_INDEX], + // exp_id[m_PHI_MODULE_INDEX], + // exp_id[m_ETA_MODULE_INDEX], + // exp_id[m_SIDE_INDEX]); + // if (get_hash(id, hash_id, &wcontext)) { + // log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get hash, exp/compact " + // << show_to_string(id, &wcontext) + // << " " << (std::string)m_full_wafer_range << endmsg; + // return (1); + // } + + // // index for the subsequent arrays + // unsigned short index = hash_id; + // assert (hash_id < m_prev_phi_wafer_vec.size()); + // assert (hash_id < m_next_phi_wafer_vec.size()); + // assert (hash_id < m_prev_eta_wafer_vec.size()); + // assert (hash_id < m_next_eta_wafer_vec.size()); + + // if (pphi) { + // // Get previous phi hash id + // ExpandedIdentifier expId = exp_id; + // expId[m_PHI_MODULE_INDEX] = previous_phi; + // Identifier id = wafer_id(expId[m_BARREL_EC_INDEX], + // expId[m_LAYER_DISK_INDEX], + // expId[m_PHI_MODULE_INDEX], + // expId[m_ETA_MODULE_INDEX], + // expId[m_SIDE_INDEX]); + // if (get_hash(id, hash_id, &wcontext)) { + // log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get previous phi hash, exp/compact " << id.getString() << " " + // << endmsg; + // return (1); + // } + // m_prev_phi_wafer_vec[index] = hash_id; + // } + + // if (nphi) { + // // Get next phi hash id + // ExpandedIdentifier expId = exp_id; + // expId[m_PHI_MODULE_INDEX] = next_phi; + // Identifier id = wafer_id(expId[m_BARREL_EC_INDEX], + // expId[m_LAYER_DISK_INDEX], + // expId[m_PHI_MODULE_INDEX], + // expId[m_ETA_MODULE_INDEX], + // expId[m_SIDE_INDEX]); + // if (get_hash(id, hash_id, &wcontext)) { + // log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get next phi hash, exp/compact " << id.getString() << + // " " << MSG::hex << id.getString() << MSG::dec << endmsg; + // return (1); + // } + // m_next_phi_wafer_vec[index] = hash_id; + // } + + // if (peta) { + // // Get previous eta hash id + // ExpandedIdentifier expId = exp_id; + // expId[m_ETA_MODULE_INDEX] = previous_eta; + // Identifier id = wafer_id(expId[m_BARREL_EC_INDEX], + // expId[m_LAYER_DISK_INDEX], + // expId[m_PHI_MODULE_INDEX], + // expId[m_ETA_MODULE_INDEX], + // expId[m_SIDE_INDEX]); + // if (get_hash(id, hash_id, &wcontext)) { + // log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get previous eta hash, exp/compact " << id.getString() + // << " " << std::endl; + // return (1); + // } + // m_prev_eta_wafer_vec[index] = hash_id; + // } + + // if (neta) { + // // Get next eta hash id + // ExpandedIdentifier expId = exp_id; + // expId[m_ETA_MODULE_INDEX] = next_eta; + // Identifier id = wafer_id(expId[m_BARREL_EC_INDEX], + // expId[m_LAYER_DISK_INDEX], + // expId[m_PHI_MODULE_INDEX], + // expId[m_ETA_MODULE_INDEX], + // expId[m_SIDE_INDEX]); + // if (get_hash(id, hash_id, &wcontext)) { + // log << MSG::ERROR << " VetoNuID::init_neighbors - unable to get next eta hash, exp/compact " << id.getString() + // << " " << endmsg; + // return (1); + // } + // m_next_eta_wafer_vec[index] = hash_id; + // } + + +// std::cout << " VetoNuID::init_neighbors " +// << " phi, previous, next " << id[m_PHI_MODULE_INDEX] +// << " " << pphi +// << " " << previous_phi +// << " " << nphi +// << " " << next_phi +// << " eta, previous, next " << id[m_ETA_MODULE_INDEX] +// << " " << peta +// << " " << previous_eta +// << " " << neta +// << " " << next_eta +// << " id " << (std::string)(*first) +// << std::endl; + // } + // } + return (0); +} + + + +int +VetoNuID::initLevelsFromDict() +{ + + + MsgStream log(m_msgSvc, "VetoNuID"); + if(!m_dict) { + log << MSG::ERROR << " VetoNuID::initLevelsFromDict - dictionary NOT initialized " << endmsg; + return (1); + } + + // Find out which identifier field corresponds to each level. Use + // names to find each field/leve. + + m_SCINT_INDEX = 999; + m_VETONU_INDEX = 999; + m_STATION_INDEX = 999; + m_PLATE_INDEX = 999; + m_PMT_INDEX = 999; + + // Save index to a VetoNu region for unpacking + ExpandedIdentifier id; + id << scint_field_value() << vetonu_field_value(); + if (m_dict->find_region(id, m_vetonu_region_index)) { + log << MSG::ERROR << "VetoNuID::initLevelsFromDict - unable to find vetonu region index: id, reg " + << (std::string)id << " " << m_vetonu_region_index + << endmsg; + return (1); + } + + // Find a VetoNu region + IdDictField* field = m_dict->find_field("subdet"); + if (field) { + m_SCINT_INDEX = field->m_index; + } + else { + log << MSG::ERROR << "VetoNuID::initLevelsFromDict - unable to find 'subdet' field " << endmsg; + return (1); + } + field = m_dict->find_field("part"); + if (field) { + m_VETONU_INDEX = field->m_index; + } + else { + log << MSG::ERROR << "VetoNuID::initLevelsFromDict - unable to find 'part' field " << endmsg; + return (1); + } + field = m_dict->find_field("station"); + if (field) { + m_STATION_INDEX = field->m_index; + } + else { + log << MSG::ERROR << "VetoNuID::initLevelsFromDict - unable to find 'station' field " << endmsg; + return (1); + } + field = m_dict->find_field("plate"); + if (field) { + m_PLATE_INDEX = field->m_index; + } + else { + log << MSG::ERROR<< "VetoNuID::initLevelsFromDict - unable to find 'plate' field " << endmsg; + return (1); + } + field = m_dict->find_field("pmt"); + if (field) { + m_PMT_INDEX = field->m_index; + } + else { + log << MSG::ERROR << "VetoNuID::initLevelsFromDict - unable to find 'pmt' field " << endmsg; + return (1); + } + + // Set the field implementations + + const IdDictRegion& region = *m_dict->m_regions[m_vetonu_region_index]; + + m_scint_impl = region.m_implementation[m_SCINT_INDEX]; + m_vetonu_impl = region.m_implementation[m_VETONU_INDEX]; + m_station_impl = region.m_implementation[m_STATION_INDEX]; + m_plate_impl = region.m_implementation[m_PLATE_INDEX]; + m_pmt_impl = region.m_implementation[m_PMT_INDEX]; + + if (m_msgSvc) { + log << MSG::DEBUG << "decode index and bit fields for each level: " << endmsg; + log << MSG::DEBUG << "scint " << m_scint_impl.show_to_string() << endmsg; + log << MSG::DEBUG << "vetonu " << m_vetonu_impl.show_to_string() << endmsg; + log << MSG::DEBUG << "station " << m_station_impl.show_to_string() << endmsg; + log << MSG::DEBUG << "plate " << m_plate_impl.show_to_string() << endmsg; + log << MSG::DEBUG << "pmt " << m_pmt_impl.show_to_string() << endmsg; + } + else { + std::cout << " DEBUG decode index and bit fields for each level: " << std::endl; + std::cout << " DEBUG scint " << m_scint_impl.show_to_string() << std::endl; + std::cout << " DEBUG vetonu " << m_vetonu_impl.show_to_string() << std::endl; + std::cout << " DEBUG station " << m_station_impl.show_to_string() << std::endl; + std::cout << " DEBUG plate " << m_plate_impl.show_to_string() << std::endl; + std::cout << " DEBUG pmt " << m_pmt_impl.show_to_string() << std::endl; + } + + std::cout << "scint " << m_scint_impl.decode_index() << " " + << (std::string)m_scint_impl.ored_field() << " " + << std::hex << m_scint_impl.mask() << " " + << m_scint_impl.zeroing_mask() << " " + << std::dec << m_scint_impl.shift() << " " + << m_scint_impl.bits() << " " + << m_scint_impl.bits_offset() + << std::endl; + std::cout << "vetonu" << m_vetonu_impl.decode_index() << " " + << (std::string)m_vetonu_impl.ored_field() << " " + << std::hex << m_vetonu_impl.mask() << " " + << m_vetonu_impl.zeroing_mask() << " " + << std::dec << m_vetonu_impl.shift() << " " + << m_vetonu_impl.bits() << " " + << m_vetonu_impl.bits_offset() + << std::endl; + std::cout << "station"<< m_station_impl.decode_index() << " " + << (std::string)m_station_impl.ored_field() << " " + << std::hex << m_station_impl.mask() << " " + << m_station_impl.zeroing_mask() << " " + << std::dec << m_station_impl.shift() << " " + << m_station_impl.bits() << " " + << m_station_impl.bits_offset() + << std::endl; + std::cout << "plate" << m_plate_impl.decode_index() << " " + << (std::string)m_plate_impl.ored_field() << " " + << std::hex << m_plate_impl.mask() << " " + << m_plate_impl.zeroing_mask() << " " + << std::dec << m_plate_impl.shift() << " " + << m_plate_impl.bits() << " " + << m_plate_impl.bits_offset() + << std::endl; + std::cout << "pmt" << m_pmt_impl.decode_index() << " " + << (std::string)m_pmt_impl.ored_field() << " " + << std::hex << m_pmt_impl.mask() << " " + << m_pmt_impl.zeroing_mask() << " " + << std::dec << m_pmt_impl.shift() << " " + << m_pmt_impl.bits() << " " + << m_pmt_impl.bits_offset() + << std::endl; + + return (0); +} + +VetoNuID::size_type +VetoNuID::plate_hash_max (void) const +{ + return m_plate_hash_max; +} + +VetoNuID::size_type +VetoNuID::pmt_hash_max (void) const +{ + return m_pmt_hash_max; +} + +VetoNuID::const_id_iterator VetoNuID::plate_begin (void) const +{ + return (m_plate_vec.begin()); +} + +VetoNuID::const_id_iterator VetoNuID::plate_end (void) const +{ + return (m_plate_vec.end()); +} + +VetoNuID::const_expanded_id_iterator VetoNuID::pmt_begin (void) const +{ + return (m_full_pmt_range.factory_begin()); +} + +VetoNuID::const_expanded_id_iterator VetoNuID::pmt_end (void) const +{ + return (m_full_pmt_range.factory_end()); +} + +// From hash get Identifier +int +VetoNuID::get_id (const IdentifierHash& hash_id, + Identifier& id, + const IdContext* context) const +{ + + int result = 1; + id.clear(); + + size_t begin = (context) ? context->begin_index(): 0; + // cannot get hash if end is 0: + size_t end = (context) ? context->end_index() : 0; + if (0 == begin) { + // No hashes yet for ids with prefixes + if (m_PLATE_INDEX == end) { + if (hash_id < (unsigned int)(m_plate_vec.end() - m_plate_vec.begin())) { + id = m_plate_vec[hash_id]; + result = 0; + } + } + else if (m_PMT_INDEX == end) { + // Do not know how to calculate strip id from hash yet!! + std::cout << "Do not know how to calculate pmt id from hash yet!!" << std::endl; + } + } + return (result); +} + +void +VetoNuID::get_expanded_id (const Identifier& id, + ExpandedIdentifier& exp_id, + const IdContext* context) const +{ + exp_id.clear(); + exp_id << scint_field_value() + << vetonu_field_value() + << station(id) + << plate(id); + if(!context || context->end_index() == m_PMT_INDEX) + { + exp_id << pmt(id); + } +} + +int +VetoNuID::get_hash (const Identifier& id, + IdentifierHash& hash_id, + const IdContext* context) const +{ + + // Get the hash code from either a vec (for plate) or calculate + // it (pmts). For the former, we convert to compact and call + // get_hash again. For the latter, we calculate the hash from the + // Identifier. + + int result = 1; + hash_id = 0; + size_t begin = (context) ? context->begin_index(): 0; + size_t end = (context) ? context->end_index() : 0; + if (0 == begin) { + // No hashes yet for ids with prefixes + if (m_PLATE_INDEX == end) { + hash_id = plate_hash(id); + if (hash_id.is_valid()) result = 0; + } + else if (context && context->end_index() == m_PMT_INDEX) { + // Must calculate for strip hash + ExpandedIdentifier new_id; + get_expanded_id(id, new_id); + hash_id = m_full_pmt_range.cardinalityUpTo(new_id); + result = 0; + } + } + return (result); +} + + +void +VetoNuID::test_plate_packing (void) const +{ + MsgStream log(m_msgSvc, "VetoNuID"); + + if (m_dict) { + + int nids = 0; + int nerr = 0; + IdContext context = plate_context(); + const_id_iterator first = m_plate_vec.begin(); + const_id_iterator last = m_plate_vec.end(); + for (; first != last; ++first, ++nids) { + Identifier id = (*first); + ExpandedIdentifier exp_id; + get_expanded_id(id, exp_id, &context); + Identifier new_id = plate_id(exp_id[m_STATION_INDEX], + exp_id[m_PLATE_INDEX]); + if (id != new_id) { + log << MSG::ERROR << "VetoNuID::test_plate_packing: new and old compacts not equal. New/old/expanded ids " + << MSG::hex << show_to_string(id) << " " << show_to_string(new_id) << " " << MSG::dec + << (std::string)exp_id << endmsg; + nerr++; + continue; + } + // check station id + if (!exp_id[m_PLATE_INDEX]) { + + Identifier new_id1 = station_id(exp_id[m_STATION_INDEX]); + if (id != new_id1) { + log << MSG::ERROR << "VetoNuID::test_plate_packing: new and old station ids not equal. New/old/expanded ids " + << MSG::hex << show_to_string(id) << " " << show_to_string(new_id1) << " " << MSG::dec + << (std::string)exp_id << endmsg; + nerr++; + continue; + } + } + } + + if (m_msgSvc) { + log << MSG::DEBUG << "VetoNuID::test_plate_packing: tested plate and station ids. nids, errors " + << nids << " " << nerr << endmsg; + } + else { + std::cout << " DEBUG VetoNuID::test_plate_packing: tested plate and station ids. nids, errors " + << nids << " " << nerr << std::endl; + } + + nids = 0; + context = pmt_context(); + const_expanded_id_iterator first_vetonu = pmt_begin(); + const_expanded_id_iterator last_vetonu = pmt_end(); + for (; first_vetonu != last_vetonu; ++first_vetonu, ++nids) { + // if (nids%10000 != 1) continue; + const ExpandedIdentifier& exp_id = *first_vetonu; + ExpandedIdentifier new_exp_id; + + Identifier id = plate_id(exp_id[m_STATION_INDEX], + exp_id[m_PLATE_INDEX]); + get_expanded_id(id, new_exp_id, &context); + if (exp_id[0] != new_exp_id[0] || + exp_id[1] != new_exp_id[1] || + exp_id[2] != new_exp_id[2] || + exp_id[3] != new_exp_id[3]) + { + log << MSG::ERROR << "VetoNuID::test_plate_packing: new and old ids not equal. New/old/compact ids " + << (std::string)new_exp_id << " " << (std::string)exp_id + << " " << show_to_string(id) << endmsg; + continue; + } + + Identifier pmtid ; + Identifier pmtid1 ; + pmtid = pmt_id ( + exp_id[m_STATION_INDEX], + exp_id[m_PLATE_INDEX], + exp_id[m_PMT_INDEX]); + + pmtid1 = pmt_id ( + station(pmtid), + plate(pmtid), + pmt(pmtid)); + + if (pmtid != pmtid1) { + log << MSG::ERROR << "VetoNuID::test_plate_packing: new and old pixel ids not equal. New/old ids " + << " " << show_to_string(pmtid1) << " " + << show_to_string(pmtid) << endmsg; + } + } + + if (m_msgSvc) { + log << MSG::DEBUG << "VetoNuID::test_plate_packing: Successful tested " + << nids << " ids. " + << endmsg; + } + else { + std::cout << " DEBUG VetoNuID::test_plate_packing: Successful tested " + << nids << " ids. " + << std::endl; + } + } + else { + log << MSG::ERROR << "VetoNuID::test_plate_packing: Unable to test plate packing - no dictionary has been defined. " + << endmsg; + } +} + diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h index 2f1e7c0a95be335fcc8e349159d9f6b4b4efe213..6711c085aff1e6b7386f3680b04bb06b9dc65659 100644 --- a/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h +++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/ScintDetectorElement.h @@ -156,6 +156,7 @@ namespace ScintDD { bool isVeto() const; bool isTrigger() const; bool isPreshower() const; + bool isVetoNu() const; // Identifier <-> pmt @@ -458,6 +459,7 @@ namespace ScintDD { bool m_isVeto; bool m_isTrigger; bool m_isPreshower; + bool m_isVetoNu; // // Cached values. diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/VetoNuDetectorManager.h b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/VetoNuDetectorManager.h new file mode 100644 index 0000000000000000000000000000000000000000..86d34b84c94bc6f7ef4087a57696afa0be7ce3b3 --- /dev/null +++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/ScintReadoutGeometry/VetoNuDetectorManager.h @@ -0,0 +1,163 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// VetoNuDetectorManager.h +/////////////////////////////////////////////////////////////////// +// (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +#ifndef SCINTREADOUTGEOMETRY_VETONUDETECTORMANAGER_H +#define SCINTREADOUTGEOMETRY_VETONUDETECTORMANAGER_H + +#include "GeoPrimitives/GeoPrimitives.h" + +#include "GeoModelKernel/GeoVPhysVol.h" + +#include "ScintReadoutGeometry/ScintDetectorManager.h" +#include "ScintReadoutGeometry/ScintDetectorElementCollection.h" +#include "ScintReadoutGeometry/ScintDD_Defs.h" + +#include "ScintIdentifier/VetoNuID.h" + +class StoreGateSvc; +class Identifier; +class IdentifierHash; +class GeoAlignableTransform; +class GeoVFullPhysVol; +class GeoVPhysVol; +class GeoVAlignmentStore; +class CondAttrListCollection; + +namespace ScintDD { + + class ScintDetectorElement; + class ExtendedAlignableTransform; + class VetoNuDetectorDesign; + + /** @class VetoNuDetectorManager + + Dedicated detector manager extending the functionality of the ScintDetectorManager + with dedicated VetoNu information, access. + + @author: Grant Gorfine + - modified and maintained by Nick Styles & Andreas Salzburger + - modified for FASER by D. Casper + */ + + class VetoNuDetectorManager : public ScintDetectorManager { + + public: + + // Constructor + VetoNuDetectorManager( StoreGateSvc* detStore ); + + // Destructor + virtual ~VetoNuDetectorManager(); + + /** Access Raw Geometry */ + virtual unsigned int getNumTreeTops() const override; + virtual PVConstLink getTreeTop(unsigned int i) const override; + /** Add tree top */ + void addTreeTop(PVLink); + + + // + // Access Readout Elements + // + + /** access to individual elements via Identifier */ + virtual ScintDetectorElement * getDetectorElement(const Identifier &id) const override; + + /** access to individual elements via IdentifierHash */ + virtual ScintDetectorElement * getDetectorElement(const IdentifierHash &idHash) const override; + + /** access to individual elements via module numbering schema */ + ScintDetectorElement * getDetectorElement(int station, int plate) const; + + /** access to whole collectiom via iterators */ + virtual const ScintDetectorElementCollection * getDetectorElementCollection() const override; + virtual ScintDetectorElementCollection::const_iterator getDetectorElementBegin() const override; + virtual ScintDetectorElementCollection::const_iterator getDetectorElementEnd() const override; + + /** Add elememts during construction */ + virtual void addDetectorElement(ScintDetectorElement * element) override; + + /** Add alignable transforms. No access to these, they will be changed by manager: */ + virtual void addAlignableTransform (int level, + const Identifier &id, + GeoAlignableTransform *xf, + const GeoVFullPhysVol * child); + + /** As above but does a dynamic_cast to GeoVFullPhysVol */ + virtual void addAlignableTransform (int level, + const Identifier &id, + GeoAlignableTransform *xf, + const GeoVPhysVol * child); + + /** Initialize the neighbours. This can only be done when all elements are built. */ + virtual void initNeighbours() override; + + /** Check identifier is for this detector */ + virtual bool identifierBelongs(const Identifier & id) const override; + + /** Access to module design, casts to VetoNuDetectorDesign */ + const ScintDetectorDesign * getVetoNuDesign() const; + + /** Process new global DB folders for L1 and L2 **/ + virtual + bool processGlobalAlignment(const std::string &, int level, FrameType frame, + const CondAttrListCollection* obj, + GeoVAlignmentStore* alignStore) const override; + + // comply with ScintDetectorManager interface + bool processSpecialAlignment(const std::string & key, + ScintDD::AlignFolderType alignfolder) const override; + + bool processSpecialAlignment(const std::string& key, + const CondAttrListCollection* obj=nullptr, + GeoVAlignmentStore* alignStore=nullptr) const override; + + + private: + /** implements the main alignment update for delta transforms in different frames, + it translates into the LocalDelta or GlobalDelta function of ScintDetectorManager + */ + virtual bool setAlignableTransformDelta(int level, + const Identifier & id, + const Amg::Transform3D & delta, + FrameType frame, + GeoVAlignmentStore* alignStore) const override; + + /** Prevent copy and assignment */ + const VetoNuDetectorManager & operator=(const VetoNuDetectorManager &right); + VetoNuDetectorManager(const VetoNuDetectorManager &right); + + virtual const VetoNuID* getIdHelper() const override; + + // Private member data + std::vector<PVLink> m_volume; + ScintDetectorElementCollection m_elementCollection; + typedef std::map<Identifier, ExtendedAlignableTransform *> AlignableTransformMap; + std::vector< AlignableTransformMap > m_higherAlignableTransforms; + std::vector< ExtendedAlignableTransform *> m_alignableTransforms; + const VetoNuID* m_idHelper; + + /** This variable switches the how the local alignment corrections are applied + If true they will be calcualted on top of all of other corrections but in the default reference frame + If false they will be calcualted on top of all of other corrections but in the globally aligned reference frame + */ + bool m_isLogical; + + + }; + +} // namespace ScintDD + +#ifndef GAUDI_NEUTRAL +#include "AthenaKernel/CLASS_DEF.h" +CLASS_DEF(ScintDD::VetoNuDetectorManager, 238247911, 1) +#endif + +#endif // SCINTREADOUTGEOMETRY_VETONIDETECTORMANAGER_H diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx index 3b4a0c4812177549e28af5e39cae2a4ed2d92e91..e06fa94894bf323189fad6f786d9e1daf6b57da1 100644 --- a/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx +++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/ScintDetectorElement.cxx @@ -14,6 +14,7 @@ #include "ScintIdentifier/VetoID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/PreshowerID.h" +#include "ScintIdentifier/VetoNuID.h" #include "GeoModelKernel/GeoVFullPhysVol.h" #include "GeoModelFaserUtilities/GeoAlignmentStore.h" @@ -93,13 +94,14 @@ ScintDetectorElement::commonConstructor() m_isVeto = getIdHelper()->is_veto(m_id); m_isTrigger = getIdHelper()->is_trigger(m_id); m_isPreshower = getIdHelper()->is_preshower(m_id); - if (!m_isVeto && !m_isTrigger && !m_isPreshower) + m_isVetoNu = getIdHelper()->is_vetonu(m_id); + if (!m_isVeto && !m_isTrigger && !m_isPreshower && !m_isVetoNu) { - if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id is not for veto, trigger or preshower" << endmsg; + if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id is not for veto, trigger, preshower or vetonu" << endmsg; } - else if ((m_isVeto && m_isTrigger) || (m_isVeto && m_isPreshower) || (m_isTrigger && m_isPreshower)) + else if ((m_isVeto && m_isTrigger) || (m_isVeto && m_isPreshower) || (m_isTrigger && m_isPreshower) || (m_isVetoNu && (m_isVeto || m_isTrigger || m_isPreshower))) { - if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id belongs to more than one of veto, trigger or preshower" << endmsg; + if (msgLvl(MSG::WARNING)) msg(MSG::WARNING) << "Element id belongs to more than one of veto, trigger, preshower or vetonu" << endmsg; } // Set IdHash. @@ -118,6 +120,11 @@ ScintDetectorElement::commonConstructor() const PreshowerID* preshowerId = dynamic_cast<const PreshowerID* >(getIdHelper()); m_idHash = preshowerId->plate_hash(m_id); } + else if (isVetoNu()) + { + const VetoNuID* vetoNuId = dynamic_cast<const VetoNuID* >(getIdHelper()); + m_idHash = vetoNuId->plate_hash(m_id); + } if (!m_idHash.is_valid()) throw std::runtime_error("ScintDetectorElement: Unable to set IdentifierHash"); @@ -599,6 +606,11 @@ bool ScintDetectorElement::isPreshower() const return m_isPreshower; } +bool ScintDetectorElement::isVetoNu() const +{ + return m_isVetoNu; +} + Trk::Surface & ScintDetectorElement::surface() { diff --git a/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/VetoNuDetectorManager.cxx b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/VetoNuDetectorManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b7990ebc33a4b0af1f4e24dcdc5acd6bfc21d611 --- /dev/null +++ b/Scintillator/ScintDetDescr/ScintReadoutGeometry/src/VetoNuDetectorManager.cxx @@ -0,0 +1,348 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" + +#include "AthenaBaseComps/AthMsgStreamMacros.h" +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "Identifier/Identifier.h" +#include "Identifier/IdentifierHash.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintReadoutGeometry/ScintDetectorElementCollection.h" +#include "ScintReadoutGeometry/ScintDetectorElement.h" +#include "ScintReadoutGeometry/ExtendedAlignableTransform.h" +#include "ScintReadoutGeometry/ScintDetectorDesign.h" +#include "StoreGate/StoreGateSvc.h" + +#include <iostream> + +namespace ScintDD { + + const int FIRST_HIGHER_LEVEL = 1; + + VetoNuDetectorManager::VetoNuDetectorManager( StoreGateSvc* detStore ) + : ScintDetectorManager(detStore, "VetoNu"), + m_idHelper(0), + m_isLogical(false) // Change to true to change the definition of local module corrections + { + // + // Initialized the Identifier helper. + // + StatusCode sc = detStore->retrieve(m_idHelper, "VetoNuID"); + if (sc.isFailure()) { + ATH_MSG_ERROR("Could not retrieve VetoNu id helper"); + } + // Initialize the collections. + if (m_idHelper) { + m_elementCollection.resize(m_idHelper->plate_hash_max()); + m_alignableTransforms.resize(m_idHelper->plate_hash_max()); + // m_moduleAlignableTransforms.resize(m_idHelper->plate_hash_max()); + } + } + + + + VetoNuDetectorManager::~VetoNuDetectorManager() + { + // Clean up + for (size_t i=0; i < m_volume.size(); i++) { + m_volume[i]->unref(); + } + + for (size_t j=0; j < m_higherAlignableTransforms.size(); j++){ + AlignableTransformMap::iterator iterMap; + for (iterMap = m_higherAlignableTransforms[j].begin(); + iterMap != m_higherAlignableTransforms[j].end(); + ++iterMap) { + delete iterMap->second; + } + } + + for (size_t k=0; k < m_alignableTransforms.size(); k++){ + delete m_alignableTransforms[k]; + } + + // for (size_t l=0; l < m_moduleAlignableTransforms.size(); l++){ + // delete m_moduleAlignableTransforms[l]; + // } + } + + unsigned int VetoNuDetectorManager::getNumTreeTops() const + { + return m_volume.size(); + } + + PVConstLink VetoNuDetectorManager::getTreeTop(unsigned int i) const + { + return m_volume[i]; + } + + void VetoNuDetectorManager::addTreeTop(PVLink vol){ + vol->ref(); + m_volume.push_back(vol); + } + + + ScintDetectorElement* VetoNuDetectorManager::getDetectorElement(const Identifier & id) const + { + // NB the id helpers implementation for getting a hash is not optimal. + // Essentially does a binary search. + // Make sure it is a wafer Id + Identifier waferId = m_idHelper->plate_id(id); + IdentifierHash idHash = m_idHelper->plate_hash(waferId); + if (idHash.is_valid()) { + return m_elementCollection[idHash]; + } else { + return 0; + } + } + + ScintDetectorElement* VetoNuDetectorManager::getDetectorElement(const IdentifierHash & idHash) const + { + return m_elementCollection[idHash]; + } + + ScintDetectorElement* VetoNuDetectorManager::getDetectorElement(int station, int plate) const + { + return getDetectorElement(m_idHelper->plate_id(station, plate)); + } + + const ScintDetectorElementCollection* VetoNuDetectorManager::getDetectorElementCollection() const + { + return &m_elementCollection; + } + + ScintDetectorElementCollection::const_iterator VetoNuDetectorManager::getDetectorElementBegin() const + { + return m_elementCollection.begin(); + } + + ScintDetectorElementCollection::const_iterator VetoNuDetectorManager::getDetectorElementEnd() const + { + return m_elementCollection.end(); + } + + + void VetoNuDetectorManager::addDetectorElement(ScintDetectorElement * element) + { + IdentifierHash idHash = element->identifyHash(); + if (idHash >= m_elementCollection.size()) + throw std::runtime_error("VetoNuDetectorManager: Error adding detector element."); + m_elementCollection[idHash] = element; + } + + void VetoNuDetectorManager::initNeighbours() + { + ScintDetectorElementCollection::iterator iter; + + // Loop over all elements and set the neighbours + for (iter = m_elementCollection.begin(); iter != m_elementCollection.end(); ++iter){ + + ScintDetectorElement * element = *iter; + if (element) { + + IdentifierHash idHash = element->identifyHash(); + IdentifierHash idHashOther; + + int result; + // If no neighbour, result != 0 in which case we leave neighbour as null + result = m_idHelper->get_next_in_z(idHash, idHashOther); + if (result==0) element->setNextInZ(m_elementCollection[idHashOther]); + + result = m_idHelper->get_prev_in_z(idHash, idHashOther); + if (result==0) element->setPrevInZ(m_elementCollection[idHashOther]); + } + } + } + + const VetoNuID* VetoNuDetectorManager::getIdHelper() const + { + return m_idHelper; + } + + + bool VetoNuDetectorManager::setAlignableTransformDelta(int level, + const Identifier & id, + const Amg::Transform3D & delta, + FrameType frame, + GeoVAlignmentStore* alignStore) const + { + + if (level == 0) { // 0 - At the element level + + // We retrieve it via a hashId. + IdentifierHash idHash = m_idHelper->plate_hash(id); + if (!idHash.is_valid()) return false; + + if (frame == ScintDD::global) { // global shift + // Its a global transform + return setAlignableTransformGlobalDelta(m_alignableTransforms[idHash], delta, alignStore); + + } else if (frame == ScintDD::local) { // local shift + + ScintDetectorElement * element = m_elementCollection[idHash]; + if (!element) return false; + + + // Its a local transform + //See header file for definition of m_isLogical + if( m_isLogical ){ + //Ensure cache is up to date and use the alignment corrected local to global transform + element->setCache(); + return setAlignableTransformLocalDelta(m_alignableTransforms[idHash], element->transform(), delta, alignStore); + } else + //Use default local to global transform + return setAlignableTransformLocalDelta(m_alignableTransforms[idHash], element->defTransform(), delta, alignStore); + + } else { + // other not supported + ATH_MSG_WARNING("Frames other than global or local are not supported."); + return false; + } + } else { // higher level + if (frame != ScintDD::global) { + ATH_MSG_WARNING("Non global shift at higher levels is not supported."); + return false; + } + + int index = level - FIRST_HIGHER_LEVEL; // level 0 is treated separately. + if (index >= static_cast<int>(m_higherAlignableTransforms.size())) return false; + + // We retrieve it from a map. + AlignableTransformMap::const_iterator iter; + iter = m_higherAlignableTransforms[index].find(id); + if (iter == m_higherAlignableTransforms[index].end()) return false; + + // Its a global transform + return setAlignableTransformGlobalDelta(iter->second, delta, alignStore); + } + } + + void VetoNuDetectorManager::addAlignableTransform (int level, + const Identifier & id, + GeoAlignableTransform *transform, + const GeoVPhysVol * child) + { + if (m_idHelper) { + + const GeoVFullPhysVol * childFPV = dynamic_cast<const GeoVFullPhysVol *>(child); + if (!childFPV) { + ATH_MSG_ERROR("Child of alignable transform is not a full physical volume"); + } else { + addAlignableTransform (level, id, transform, childFPV); + } + } + } + + void VetoNuDetectorManager::addAlignableTransform (int level, + const Identifier & id, + GeoAlignableTransform *transform, + const GeoVFullPhysVol * child) + { + if (m_idHelper) { + if (level == 0) { + // Element + IdentifierHash idHash = m_idHelper->plate_hash(id); + if (idHash.is_valid()) { + m_alignableTransforms[idHash]= new ExtendedAlignableTransform(transform, child); + } + } else { + // Higher levels are saved in a map. NB level=0 is treated above. + int index = level - FIRST_HIGHER_LEVEL; // level 0 is treated separately. + if (index >= static_cast<int>(m_higherAlignableTransforms.size())) m_higherAlignableTransforms.resize(index+1); + m_higherAlignableTransforms[index][id] = new ExtendedAlignableTransform(transform, child); + } + } + } + + bool + VetoNuDetectorManager::identifierBelongs(const Identifier & id) const + { + return getIdHelper()->is_vetonu(id); + } + + + const ScintDetectorDesign* VetoNuDetectorManager::getVetoNuDesign() const + { + return dynamic_cast<const ScintDetectorDesign *>(getDesign()); + } + + // New global alignment folders + bool VetoNuDetectorManager::processGlobalAlignment(const std::string & key, int level, FrameType frame, + const CondAttrListCollection* obj, GeoVAlignmentStore* alignStore) const + { + ATH_MSG_INFO("Processing new global alignment containers with key " << key << " in the " << frame << " frame at level "); + + const CondAttrListCollection* atrlistcol=obj; + if(atrlistcol==nullptr and m_detStore->retrieve(atrlistcol,key)!=StatusCode::SUCCESS) { + ATH_MSG_INFO("Cannot find new global align Container for key " + << key << " - no new global alignment "); + return false; + } + + bool alignmentChange = false; + Identifier ident=Identifier(); + + // loop over objects in collection + for (CondAttrListCollection::const_iterator citr=atrlistcol->begin(); citr!=atrlistcol->end();++citr) { + const coral::AttributeList& atrlist=citr->second; + // SCT manager, therefore ignore all that is not a SCT Identifier + // if (atrlist["det"].data<int>()!=2) continue; + ATH_MSG_FATAL("Using invalid alignment data for VetoNu detector (correct treatment not yet implemented"); + ident = getIdHelper()->plate_id(atrlist["station"].data<int>(), + atrlist["plate"].data<int>()); // The last is the module side which is at this ident-level always the 0-side + + // construct new transform + // Order of rotations is defined as around z, then y, then x. + Amg::Translation3D newtranslation(atrlist["Tx"].data<float>(),atrlist["Ty"].data<float>(),atrlist["Tz"].data<float>()); + Amg::Transform3D newtrans = newtranslation * Amg::RotationMatrix3D::Identity(); + newtrans *= Amg::AngleAxis3D(atrlist["Rz"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,0.,1.)); + newtrans *= Amg::AngleAxis3D(atrlist["Ry"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,1.,0.)); + newtrans *= Amg::AngleAxis3D(atrlist["Rx"].data<float>()*CLHEP::mrad, Amg::Vector3D(1.,0.,0.)); + + ATH_MSG_DEBUG("New global DB -- channel: " << citr->first + << " ,det: " << atrlist["det"].data<int>() + << " ,bec: " << atrlist["bec"].data<int>() + << " ,layer: " << atrlist["layer"].data<int>() + << " ,ring: " << atrlist["ring"].data<int>() + << " ,sector: " << atrlist["sector"].data<int>() + << " ,Tx: " << atrlist["Tx"].data<float>() + << " ,Ty: " << atrlist["Ty"].data<float>() + << " ,Tz: " << atrlist["Tz"].data<float>() + << " ,Rx: " << atrlist["Rx"].data<float>() + << " ,Ry: " << atrlist["Ry"].data<float>() + << " ,Rz: " << atrlist["Rz"].data<float>()); + + // Set the new transform; Will replace existing one with updated transform + bool status = setAlignableTransformDelta(level, + ident, + newtrans, + frame, + alignStore); + + if (!status) { + ATH_MSG_DEBUG("Cannot set AlignableTransform for identifier." + << getIdHelper()->show_to_string(ident) + << " at level " << level << " for new global DB "); + } + + alignmentChange = (alignmentChange || status); + } + return alignmentChange; + } + +bool VetoNuDetectorManager::processSpecialAlignment( + const std::string &, ScintDD::AlignFolderType) const { + return false; +} + +bool VetoNuDetectorManager::processSpecialAlignment(const std::string& /*key*/, + const CondAttrListCollection* /*obj*/, + GeoVAlignmentStore* /*alignStore*/) const { + return false; + +} + +} // namespace ScintDD diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/CMakeLists.txt b/Scintillator/ScintDetDescr/VetoNuGeoModel/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..404a64a14c4deecf4fd9f51908c5800e0129cd28 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/CMakeLists.txt @@ -0,0 +1,29 @@ +################################################################################ +# Package: VetoNuGeoModel +################################################################################ + +# Declare the package name: +atlas_subdir( VetoNuGeoModel ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess ) +find_package( Eigen ) +find_package( GeoModel ) + +# Component(s) in the package: +atlas_add_component( VetoNuGeoModel + src/*.cxx + src/components/*.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${CORAL_LIBRARIES} ${GEOMODEL_LIBRARIES} AthenaKernel GeoModelFaserUtilities GaudiKernel SGTools StoreGateLib SGtests AthenaPoolUtilities DetDescrConditions FaserDetDescr ScintGeoModelUtils ScintReadoutGeometry ScintIdentifier Identifier ) + +atlas_add_test( VetoNuGMConfig_test + SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/test/VetoNuGMConfig_test.py + PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + PROPERTIES TIMEOUT 300 ) + + +# Install files from the package: +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( test/*.py ) diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuDetectorTool.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuDetectorTool.h new file mode 100644 index 0000000000000000000000000000000000000000..60e4ee6ab63659996fd6b2b942e6dc64ceb03fbb --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuDetectorTool.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUDETECTORTOOL_H +#define VETONUGEOMODEL_VETONUDETECTORTOOL_H + +#include "GeoModelFaserUtilities/GeoModelTool.h" +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" + +#include "GeometryDBSvc/IGeometryDBSvc.h" +#include "GeoModelInterfaces/IGeoDbTagSvc.h" +#include "RDBAccessSvc/IRDBAccessSvc.h" + +#include "GaudiKernel/ServiceHandle.h" + +#include <string> + +namespace ScintDD { + class VetoNuDetectorManager; +} + +class VetoNuID; +// class FaserDetectorID; + +class VetoNuDetectorTool : public GeoModelTool { + +public: + // Standard Constructor + VetoNuDetectorTool(const std::string& type, const std::string& name, const IInterface* parent); + + virtual StatusCode create() override final; + virtual StatusCode clear() override final; + + // Register callback function on ConDB object + virtual StatusCode registerCallback ATLAS_NOT_THREAD_SAFE () override final; + + // Callback function itself + virtual StatusCode align(IOVSVC_CALLBACK_ARGS) override; + +private: + StringProperty m_detectorName{this, "DetectorName", "VetoNu"}; + BooleanProperty m_alignable{this, "Alignable", true}; + BooleanProperty m_useDynamicAlignFolders{this, "useDynamicAlignFolders", false}; + bool m_cosmic; + + const ScintDD::VetoNuDetectorManager* m_manager; + + VetoNuGeoModelAthenaComps m_athenaComps; + + ServiceHandle< IGeoDbTagSvc > m_geoDbTagSvc; + ServiceHandle< IRDBAccessSvc > m_rdbAccessSvc; + ServiceHandle< IGeometryDBSvc > m_geometryDBSvc; + + StringProperty m_run1Folder{this, "Run1Folder", "/Scint/Align"}; + StringProperty m_run2L1Folder{this, "Run2L1Folder", "/Scint/AlignL1/ID"}; + StringProperty m_run2L2Folder{this, "Run2L2Folder", "/Scint/AlignL2/SCT"}; + StringProperty m_run2L3Folder{this, "Run2L3Folder", "/Scint/AlignL3"}; +}; + +#endif // VETOGEOMODEL_VETODETECTORTOOL_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuGeoModelAthenaComps.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuGeoModelAthenaComps.h new file mode 100644 index 0000000000000000000000000000000000000000..c873da9365eade697769bbcc116d05bfd1b9ee45 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/VetoNuGeoModel/VetoNuGeoModelAthenaComps.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuGeoModelAthenaComps_H +#define VetoNuGeoModel_VetoNuGeoModelAthenaComps_H 1 + +#include "ScintGeoModelUtils/ScintDDAthenaComps.h" + +class VetoNuID; + +/// Class to hold various Athena components +// template <class ID_HELPER> +class VetoNuGeoModelAthenaComps : public ScintDD::AthenaComps { + +public: + + VetoNuGeoModelAthenaComps(); + + void setIdHelper(const VetoNuID* idHelper); + + const VetoNuID* getIdHelper() const; + +private: + const VetoNuID* m_idHelper; + +}; + +#endif // VetoNuGeoModel_VetoNuGeoModelAthenaComps_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/python/VetoNuGeoModelConfig.py b/Scintillator/ScintDetDescr/VetoNuGeoModel/python/VetoNuGeoModelConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..9f55fbad90243aa8ba56ba4044a99ca085a1a811 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/python/VetoNuGeoModelConfig.py @@ -0,0 +1,20 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +from AthenaConfiguration.ComponentFactory import CompFactory +# from IOVDbSvc.IOVDbSvcConfig import addFoldersSplitOnline + +def VetoNuGeometryCfg( flags ): + from FaserGeoModel.GeoModelConfig import GeoModelCfg + acc = GeoModelCfg( flags ) + geoModelSvc = acc.getPrimary() + + GeometryDBSvc=CompFactory.GeometryDBSvc + acc.addService(GeometryDBSvc("ScintGeometryDBSvc")) + + VetoNuDetectorTool = CompFactory.VetoNuDetectorTool + vetoNuDetectorTool = VetoNuDetectorTool() + + vetoNuDetectorTool.useDynamicAlignFolders = flags.GeoModel.Align.Dynamic + geoModelSvc.DetectorTools += [ vetoNuDetectorTool ] + + return acc diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..711a8dfd097f349dddc59d33a00dc955090bcd2c --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.cxx @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuComponentFactory.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <sstream> +#include <string> + +using ScintDD::VetoNuDetectorManager; + +const double VetoNuComponentFactory::s_epsilon = 1.0e-6 * Gaudi::Units::mm; + +VetoNuComponentFactory::VetoNuComponentFactory(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials) + : m_detectorManager(detectorManager), + m_geometryManager(geometryManager), + m_materials(materials), + m_name(name) +{} + +VetoNuComponentFactory::~VetoNuComponentFactory() +{} + +std::string +VetoNuComponentFactory::intToString(int i) const +{ + std::ostringstream str; + str << i; + return str.str(); +} + +double +VetoNuComponentFactory::epsilon() const +{ + return s_epsilon; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..340f896f9b111f7b620194b7ded5943c72523899 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuComponentFactory.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUCOMPONENTFACTORY_H +#define VETONUGEOMODEL_VETONUCOMPONENTFACTORY_H + +#include "VetoNuIdentifier.h" +#include <string> + +namespace ScintDD{class VetoNuDetectorManager;} +class VetoNuGeometryManager; +class VetoNuMaterialManager; + +class GeoLogVol; +class GeoVPhysVol; + + +class VetoNuComponentFactory +{ + +public: + VetoNuComponentFactory(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials); + + const std::string & getName() const {return m_name;} + + // utility function to covert int to string + std::string intToString(int i) const; + +protected: + ScintDD::VetoNuDetectorManager* m_detectorManager; + const VetoNuGeometryManager* m_geometryManager; + VetoNuMaterialManager* m_materials; + + double epsilon() const; + virtual ~VetoNuComponentFactory(); + +private: + std::string m_name; + static const double s_epsilon; + +}; + + +class VetoNuSharedComponentFactory : public VetoNuComponentFactory +{ + +public: + VetoNuSharedComponentFactory(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials=nullptr) : + VetoNuComponentFactory(name, detectorManager, geometryManager, materials), + m_physVolume(nullptr) + {}; + + GeoVPhysVol * getVolume() {return m_physVolume;} + +protected: + GeoVPhysVol * m_physVolume; + virtual GeoVPhysVol * build() = 0; + +}; + +class VetoNuUniqueComponentFactory : public VetoNuComponentFactory +{ + +public: + VetoNuUniqueComponentFactory(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials=nullptr) : + VetoNuComponentFactory(name, detectorManager, geometryManager, materials), + m_logVolume{nullptr} + {}; + + virtual GeoVPhysVol * build(VetoNuIdentifier id) = 0; + +protected: + const GeoLogVol * m_logVolume; + + virtual const GeoLogVol * preBuild() = 0; + +}; + +#endif // VETOGEOMODEL_VETOCOMPONENTFACTORY_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..58c19908bda3299b05f846b04c24439d01d499ec --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.cxx @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuDataBase.h" + +#include "RDBAccessSvc/IRDBAccessSvc.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "RDBAccessSvc/IRDBRecord.h" + +#include "GeoModelInterfaces/IGeoDbTagSvc.h" +#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h" + +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" + +#include <iostream> + +VetoNuDataBase::VetoNuDataBase(const VetoNuGeoModelAthenaComps * athenaComps) +{ + m_athenaComps = athenaComps; + + IGeoDbTagSvc * geoDbTag = m_athenaComps->geoDbTagSvc(); + + // Get version tag and node for VetoNu + DecodeFaserVersionKey versionKey(geoDbTag,"VetoNu"); + std::string versionTag = versionKey.tag(); + std::string versionNode = versionKey.node(); + + // Get version tag and node for Scintillator. + DecodeFaserVersionKey scintVersionKey(geoDbTag,"Scintillator"); + + // Access the RDB + IRDBAccessSvc* rdbSvc = m_athenaComps->rdbAccessSvc(); + + // VetoNu version tag + m_vetoVersionTag = rdbSvc->getChildTag("VetoNu", versionKey.tag(), versionKey.node(), "FASERDD"); + + +///////////////////////////////////////////////////////// +// +// Gets the structures +// +///////////////////////////////////////////////////////// + + msg(MSG::INFO) << "Retrieving Record Sets from database ..." << endmsg; + msg(MSG::DEBUG) << " Using version tag: " << versionTag << endmsg; + msg(MSG::DEBUG) << " at node: " << versionNode << endmsg; + msg(MSG::DEBUG) << " VetoNu Version: " << m_vetoVersionTag << endmsg; + + // ATLS - not sure I use it. + // General atlas parameters + + // + // VetoNu General + // + + // VetoNu TopLevel + m_topLevel = rdbSvc->getRecordsetPtr("VetoNuTopLevel", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuTopLevel Fetched" << endmsg; + + // Weight Table + m_weightTable = rdbSvc->getRecordsetPtr("VetoNuWeights", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuWeights Fetched" << endmsg; + + // Extra Scaling Table. This is used for extra material studies. For nominal material the table should be empty. + // NB this is at InnerDetector level node. + m_scalingTable = rdbSvc->getRecordsetPtr("VetoNuMatScaling", scintVersionKey.tag(), scintVersionKey.node(), "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuMatScaling Fetched" << endmsg; + +// // Default conditions +// m_conditions = rdbSvc->getRecordsetPtr("VetoNuConditions", versionTag, versionNode, "FASERDD"); +// msg(MSG::DEBUG) << "Table VetoNuConditions Fetched" << endmsg; + + m_stationGeneral = rdbSvc->getRecordsetPtr("VetoNuStationGeneral", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuStationGeneral Fetched" << endmsg; + + m_plateGeneral = rdbSvc->getRecordsetPtr("VetoNuPlateGeneral", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuPlateGeneral Fetched" << endmsg; + + m_radiatorGeneral = rdbSvc->getRecordsetPtr("VetoNuRadiatorGeneral", versionTag, versionNode, "FASERDD"); + msg(MSG::DEBUG) << "Table VetoNuRadiatorGeneral Fetched" << endmsg; + + +} + +const VetoNuGeoModelAthenaComps* VetoNuDataBase::athenaComps() const { return m_athenaComps; } + +IRDBRecordset_ptr VetoNuDataBase::weightTable() const {return m_weightTable;} + +IRDBRecordset_ptr VetoNuDataBase::scalingTable() const {return m_scalingTable;} + +// //const IRDBRecord* VetoNuDataBase::atls() const {return *m_atls)[0];} +IRDBRecordset_ptr VetoNuDataBase::topLevelTable() const {return m_topLevel;} + +// IRDBRecordset_ptr VetoNuDataBase::conditionsTable() const {return m_conditions;} +// const IRDBRecord* VetoNuDataBase::conditions() const {return (*m_conditions)[0];} + +const IRDBRecord* VetoNuDataBase::stationGeneral() const {return (*m_stationGeneral)[0];} +const IRDBRecord* VetoNuDataBase::plateGeneral() const {return (*m_plateGeneral)[0];} +const IRDBRecord* VetoNuDataBase::radiatorGeneral() const {return (*m_radiatorGeneral)[0];} + +const std::string & VetoNuDataBase::versionTag() const { + return m_vetoVersionTag; +} + +MsgStream& VetoNuDataBase::msg (MSG::Level lvl) const +{ + return m_athenaComps->msg(lvl); +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.h new file mode 100644 index 0000000000000000000000000000000000000000..1028ed0198798fabf12c64604f9b25ddc355a427 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDataBase.h @@ -0,0 +1,155 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuDataBase_H +#define VetoNuGeoModel_VetoNuDataBase_H + +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" +#include <string> + +#include "RDBAccessSvc/IRDBAccessSvc.h" +class IRDBRecord; + + +class VetoNuDataBase +{ + + +public: + + VetoNuDataBase(const VetoNuGeoModelAthenaComps* athenaComps); + + const VetoNuGeoModelAthenaComps* athenaComps() const; + + IRDBRecordset_ptr weightTable() const; + IRDBRecordset_ptr scalingTable() const; + IRDBRecordset_ptr topLevelTable() const; + +// IRDBRecordset_ptr conditionsTable() const; +// const IRDBRecord* conditions() const; + +// const IRDBRecord* brlSensor() const; +// const IRDBRecord* brlModule() const; + +// const IRDBRecord* brlSki() const; +// const IRDBRecord* brlSkiZ(int i) const; +// int brlSkiZSize() const; +// const IRDBRecord* brlLayer(int i) const; +// const IRDBRecord* brlServices() const; +// const IRDBRecord* brlServPerLayer(int i) const; +// const IRDBRecord* brlThermalShield() const; + const IRDBRecord* stationGeneral() const; + const IRDBRecord* plateGeneral() const; + const IRDBRecord* radiatorGeneral() const; +// const IRDBRecord* brlFSI() const; +// int brlFSISize() const; +// const IRDBRecord* brlFSILocation(int i) const; + +// const IRDBRecord* fwdSensor(int i) const; +// const IRDBRecord* fwdHybrid() const; +// const IRDBRecord* fwdSpine(int i) const; +// const IRDBRecord* fwdModule(int i) const; +// int fwdModuleSize() const; +// IRDBRecordset_ptr fwdModuleConnectorTable() const; +// const IRDBRecord* fwdModuleConnector() const; + +// const IRDBRecord* fwdRing(int i) const; +// int fwdRingSize() const; +// const IRDBRecord* fwdWheel(int i) const; +// const IRDBRecord* fwdWheelRingMap(int i) const; +// int fwdWheelRingMapSize() const; +// const IRDBRecord* fwdDiscSupport() const; +// const IRDBRecord* fwdPatchPanelLoc(int i) const; +// int fwdPatchPanelLocSize() const; +// const IRDBRecord* fwdPatchPanel(int i) const; +// int fwdPatchPanelSize() const; +// const IRDBRecord* fwdPPConnector() const; +// int fwdPPConnectorSize() const; +// const IRDBRecord* fwdPPCooling() const; +// int fwdPPCoolingSize() const; +// const IRDBRecord* fwdCoolingBlock(int i) const; +// const IRDBRecord* fwdRingServices(int i) const; +// const IRDBRecord* fwdServices() const; +// const IRDBRecord* fwdFSILocation(int i) const; +// int fwdFSILocationSize() const; +// const IRDBRecord* fwdFSIType(int i) const; +// int fwdFSITypeSize() const; +// const IRDBRecord* fwdFSI(int i) const; +// int fwdFSISize() const; +// const IRDBRecord* fwdThermalShield(int i) const; +// int fwdThermalShieldSize() const; +// const IRDBRecord* fwdGeneral() const; +// IRDBRecordset_ptr fwdOptoHarnessTable() const; +// const IRDBRecord* fwdOptoHarness(int i) const; +// IRDBRecordset_ptr fwdDiscFixationTable() const; +// const IRDBRecord* fwdDiscFixation() const; +// const IRDBRecord* fwdCylServ(int i) const; +// int fwdCylServSize() const; +// const IRDBRecord* fwdCylServLoc(int i) const; +// int fwdCylServLocSize() const; + + // Return the VetoNu version tag. + const std::string & versionTag() const; + + MsgStream& msg (MSG::Level lvl) const; + +private: + + VetoNuDataBase(const VetoNuDataBase &); + VetoNuDataBase& operator= (const VetoNuDataBase &); + +private: + + const VetoNuGeoModelAthenaComps* m_athenaComps; + + std::string m_vetoVersionTag; + + IRDBRecordset_ptr m_weightTable; + IRDBRecordset_ptr m_scalingTable; + IRDBRecordset_ptr m_topLevel; + IRDBRecordset_ptr m_conditions; + +// IRDBRecordset_ptr m_brlSensor; +// IRDBRecordset_ptr m_brlModule; +// IRDBRecordset_ptr m_brlSki; +// IRDBRecordset_ptr m_brlSkiZ; +// IRDBRecordset_ptr m_brlLayer; +// IRDBRecordset_ptr m_brlServices; +// IRDBRecordset_ptr m_brlServPerLayer; +// IRDBRecordset_ptr m_brlThermalShield; + IRDBRecordset_ptr m_stationGeneral; + IRDBRecordset_ptr m_plateGeneral; + IRDBRecordset_ptr m_radiatorGeneral; +// IRDBRecordset_ptr m_brlFSI; +// IRDBRecordset_ptr m_brlFSILocation; +// IRDBRecordset_ptr m_fwdSensor; +// IRDBRecordset_ptr m_fwdHybrid; +// IRDBRecordset_ptr m_fwdSpine; +// IRDBRecordset_ptr m_fwdModule; +// IRDBRecordset_ptr m_fwdModuleConnector; +// IRDBRecordset_ptr m_fwdRing; +// IRDBRecordset_ptr m_fwdWheel; +// IRDBRecordset_ptr m_fwdWheelRingMap; +// IRDBRecordset_ptr m_fwdDiscSupport; +// IRDBRecordset_ptr m_fwdPatchPanelLoc; +// IRDBRecordset_ptr m_fwdPatchPanel; +// IRDBRecordset_ptr m_fwdPPConnector; +// IRDBRecordset_ptr m_fwdPPCooling; +// IRDBRecordset_ptr m_fwdCoolingBlock; +// IRDBRecordset_ptr m_fwdRingServices; +// IRDBRecordset_ptr m_fwdServices; +// IRDBRecordset_ptr m_fwdFSILocation; +// IRDBRecordset_ptr m_fwdFSIType; +// IRDBRecordset_ptr m_fwdFSI; +// IRDBRecordset_ptr m_fwdThermalShield; +// IRDBRecordset_ptr m_fwdGeneral; +// IRDBRecordset_ptr m_fwdOptoHarness; +// IRDBRecordset_ptr m_fwdDiscFixation; +// IRDBRecordset_ptr m_fwdCylServ; +// IRDBRecordset_ptr m_fwdCylServLoc; + + +}; + +#endif //VetoNuGeoModel_VetoNuDataBase_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2ac00cd600b65c83b8b483dc27b43b10da9e4cb6 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.cxx @@ -0,0 +1,279 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// +// VetoNuDetectorFactory: This is the top level node +// + + +#include "VetoNuDetectorFactory.h" + +#include "VetoNuDataBase.h" +#include "VetoNuIdentifier.h" +#include "VetoNuGeometryManager.h" +#include "VetoNuMaterialManager.h" +#include "VetoNuGeneralParameters.h" +#include "ScintReadoutGeometry/Version.h" +#include "ScintReadoutGeometry/ScintCommonItems.h" +#include "ScintReadoutGeometry/ScintDD_Defs.h" +#include "ScintReadoutGeometry/ScintDetectorDesign.h" + +#include "VetoNuStation.h" +#include "VetoNuRadiator.h" +#include "VetoNuPlate.h" +#include "VetoNuDataBase.h" +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" + +// +// GeoModel include files: +// +#include "GeoModelKernel/GeoMaterial.h" +#include "GeoModelKernel/GeoTube.h" +#include "GeoModelKernel/GeoLogVol.h" +#include "GeoModelKernel/GeoNameTag.h" +#include "GeoModelKernel/GeoIdentifierTag.h" +#include "GeoModelKernel/GeoPhysVol.h" +#include "GeoModelKernel/GeoVPhysVol.h" +#include "GeoModelKernel/GeoTransform.h" +#include "GeoModelKernel/GeoAlignableTransform.h" +#include "GeoModelKernel/GeoShape.h" +#include "GeoModelKernel/GeoShapeUnion.h" +#include "GeoModelKernel/GeoShapeShift.h" +#include "GeoModelInterfaces/StoredMaterialManager.h" +#include "GeoModelInterfaces/IGeoDbTagSvc.h" +#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h" +#include "RDBAccessSvc/IRDBAccessSvc.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "RDBAccessSvc/IRDBRecord.h" +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "DetDescrConditions/AlignableTransformContainer.h" +# +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/ISvcLocator.h" + +#include "GeoModelKernel/GeoDefinitions.h" +#include "GaudiKernel/SystemOfUnits.h" + + + +#include <iostream> +#include <iomanip> +#include <string> + +using ScintDD::VetoNuDetectorManager; +using ScintDD::ScintCommonItems; + +VetoNuDetectorFactory::VetoNuDetectorFactory(const VetoNuGeoModelAthenaComps * athenaComps, + const VetoNuOptions & options) + : ScintDD::DetectorFactoryBase(athenaComps), + m_useDynamicAlignFolders(false) +{ + + // Create the detector manager + m_detectorManager = new VetoNuDetectorManager(detStore()); + msg(MSG::DEBUG) << "Created VetoNuDetectorManager" << endmsg; + + // Create the database + m_db = new VetoNuDataBase{athenaComps}; + msg(MSG::DEBUG) << "Created VetoNuDataBase" << endmsg; + + // Create the material manager + m_materials = new VetoNuMaterialManager{m_db}; + msg(MSG::DEBUG) << "Created VetoNuMaterialManager" << endmsg; + + // Create the geometry manager. + m_geometryManager = new VetoNuGeometryManager{m_db}; + msg(MSG::DEBUG) << "Created VetoNuGeometryManager" << endmsg; + m_geometryManager->setOptions(options); + msg(MSG::DEBUG) << "Set options on VetoNuGeometryManager" << endmsg; + + m_useDynamicAlignFolders = options.dynamicAlignFolders(); + + // Set Version information + // Get the geometry tag + DecodeFaserVersionKey versionKey(geoDbTagSvc(),"VetoNu"); + IRDBRecordset_ptr switchSet + = rdbAccessSvc()->getRecordsetPtr("VetoNuSwitches", versionKey.tag(), versionKey.node(),"FASERDD"); + const IRDBRecord *switches = (*switchSet)[0]; + msg(MSG::DEBUG) << "Retrieved VetoNuSwitches" << endmsg; + + std::string layout = "Final"; + std::string description; + if (!switches->isFieldNull("LAYOUT")) { + layout = switches->getString("LAYOUT"); + } + if (!switches->isFieldNull("DESCRIPTION")) { + description = switches->getString("DESCRIPTION"); + } + + std::string versionTag = rdbAccessSvc()->getChildTag("VetoNu", versionKey.tag(), versionKey.node(),"FASERDD"); + std::string versionName = switches->getString("VERSIONNAME"); + int versionMajorNumber = 1; + int versionMinorNumber = 0; + int versionPatchNumber = 0; + ScintDD::Version version(versionTag, + versionName, + layout, + description, + versionMajorNumber, + versionMinorNumber, + versionPatchNumber); + m_detectorManager->setVersion(version); +} + + +VetoNuDetectorFactory::~VetoNuDetectorFactory() +{ + // NB the detector manager (m_detectorManager)is stored in the detector store by the + // Tool and so we don't delete it. + delete m_db; + delete m_materials; + delete m_geometryManager; +} + +void VetoNuDetectorFactory::create(GeoPhysVol *world) +{ + + msg(MSG::INFO) << "Building VetoNu Detector." << endmsg; + msg(MSG::INFO) << " " << m_detectorManager->getVersion().fullDescription() << endmsg; + + // Change precision. + int oldPrecision = std::cout.precision(6); + + // The tree tops get added to world. We name it "indet" though. + GeoPhysVol *scint = world; + + const VetoNuGeneralParameters * vetoGeneral = m_geometryManager->generalParameters(); + + GeoTrf::Transform3D vetoTransform = vetoGeneral->partTransform("VetoNu"); + + std::string stationA_Label = "StationA"; + // std::string stationB_Label = "StationB"; + // std::string radiator_Label = "Radiator"; + + bool stationA_Present = vetoGeneral->partPresent(stationA_Label); + // bool stationB_Present = vetoGeneral->partPresent(stationB_Label); + // bool radiator_Present = vetoGeneral->partPresent(radiator_Label); + // + // Plate is the same for all stations + // + VetoNuPlate plate("Plate", m_detectorManager, m_geometryManager, m_materials); + msg(MSG::DEBUG) << "Created VetoNu plate with dimensions (" << plate.thickness() << "," << plate.width() << "," << plate.length() << ")" << endmsg; + // + // Station A + // + if (stationA_Present) + { + msg(MSG::DEBUG) << "Building the VetoNu Station A." << endmsg; + m_detectorManager->numerology().addStation(0); + + // Create the station + VetoNuStation stationA("VetoNuStationA", &plate, m_detectorManager, m_geometryManager, m_materials); + VetoNuIdentifier id{m_geometryManager->athenaComps()->getIdHelper()}; + id.setStation(0); + GeoVPhysVol* stationA_PV = stationA.build(id); + GeoAlignableTransform* stationA_Transform = new GeoAlignableTransform(vetoTransform * vetoGeneral->partTransform(stationA_Label)); + + GeoNameTag* topLevelNameTag = new GeoNameTag("VetoNu"); + scint->add(topLevelNameTag); + scint->add(new GeoIdentifierTag(0)); + scint->add(stationA_Transform); + scint->add(stationA_PV); + m_detectorManager->addTreeTop(stationA_PV); + + // Store alignable transform for station (level = 1) + m_detectorManager->addAlignableTransform(1, id.getPlateId(), stationA_Transform, stationA_PV); + } + + // // + // // Station B + // // + // if (stationB_Present) + // { + // msg(MSG::DEBUG) << "Building the VetoNu Station B." << endmsg; + // m_detectorManager->numerology().addStation(1); + + // // Create the station + // VetoNuStation stationB("VetoNuStationB", &plate, m_detectorManager, m_geometryManager, m_materials); + // VetoNuIdentifier id{m_geometryManager->athenaComps()->getIdHelper()}; + // id.setStation(1); + // GeoVPhysVol* stationB_PV = stationB.build(id); + // GeoAlignableTransform* stationB_Transform = new GeoAlignableTransform(vetoTransform * vetoGeneral->partTransform(stationB_Label)); + + // GeoNameTag* topLevelNameTag = new GeoNameTag("VetoNu"); + // scint->add(topLevelNameTag); + // scint->add(new GeoIdentifierTag(0)); + // scint->add(stationB_Transform); + // scint->add(stationB_PV); + // m_detectorManager->addTreeTop(stationB_PV); + + // // Store alignable transform for station (level = 1) + // m_detectorManager->addAlignableTransform(1, id.getPlateId(), stationB_Transform, stationB_PV); + // } + + // // Passive radiator + // if (radiator_Present) + // { + // msg(MSG::DEBUG) << "Building the VetoNu Radiator." << endmsg; + + // // Create the radiator + // VetoNuRadiator radiator("VetoNuRadiator", m_detectorManager, m_geometryManager, m_materials); + // GeoAlignableTransform* radiator_Transform = new GeoAlignableTransform(vetoTransform * vetoGeneral->partTransform(radiator_Label)); + + // GeoNameTag* topLevelNameTag = new GeoNameTag("VetoNu"); + // scint->add(topLevelNameTag); + // scint->add(new GeoIdentifierTag(0)); + // scint->add(radiator_Transform); + // scint->add(radiator.getVolume()); + // m_detectorManager->addTreeTop(radiator.getVolume()); + + // } + + + // Set the neighbours + m_detectorManager->initNeighbours(); + + // Set number of pmts in numerology. + const ScintDD::ScintDetectorDesign* design = m_detectorManager->getVetoNuDesign(); + if (design != nullptr) + { + m_detectorManager->numerology().setNumPmtsPerPlate(m_detectorManager->getVetoNuDesign()->cells()); + } + else + { + m_detectorManager->numerology().setNumPmtsPerPlate(0); + } + + + // Register the keys and the level corresponding to the key + // and whether it expects a global or local shift. + // level 0: sensor, level 1: module, level 2, layer/disc, level 3: whole barrel/enccap + + + if (!m_useDynamicAlignFolders){ + + m_detectorManager->addAlignFolderType(ScintDD::static_run1); + // m_detectorManager->addFolder("/Scint/Align"); + } + else { + m_detectorManager->addAlignFolderType(ScintDD::timedependent_run2); + // m_detectorManager->addGlobalFolder("/Scint/AlignL1/Scint"); + // m_detectorManager->addGlobalFolder("/Scint/AlignL2/VetoNu"); + // m_detectorManager->addChannel("/Scint/AlignL1/Scint",3,ScintDD::global); + // m_detectorManager->addChannel("/Scint/AlignL2/VetoNu",2,ScintDD::global); + // m_detectorManager->addFolder("/Scint/AlignL3"); + } + + // Return precision to its original value + std::cout.precision(oldPrecision); + +} + + +const VetoNuDetectorManager * VetoNuDetectorFactory::getDetectorManager() const +{ + return m_detectorManager; +} + + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..f9cc9e793dbd1a1cd4b088d79f5d3d30f81a0d1c --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorFactory.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUDETECTORFACTORY_H +#define VETONUGEOMODEL_VETONUDETECTORFACTORY_H + +#include "ScintGeoModelUtils/DetectorFactoryBase.h" +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" +#include "ScintReadoutGeometry/ScintDD_Defs.h" + +class GeoPhysVol; +class VetoNuDataBase; +class VetoNuGeometryManager; +class VetoNuGeoModelAthenaComps; +class VetoNuMaterialManager; +class VetoNuOptions; + +class VetoNuDetectorFactory : public ScintDD::DetectorFactoryBase +{ + + public: + // Constructor + VetoNuDetectorFactory(const VetoNuGeoModelAthenaComps * athenaComps, + const VetoNuOptions & options); + + // Destructor + virtual ~VetoNuDetectorFactory(); + + // Creation of geometry: + virtual void create(GeoPhysVol *world); + + // Access to the results: + virtual const ScintDD::VetoNuDetectorManager * getDetectorManager() const; + + private: + // Copy and assignments operations illegal and so are made private + VetoNuDetectorFactory(const VetoNuDetectorFactory &right); + const VetoNuDetectorFactory & operator=(const VetoNuDetectorFactory &right); + + ScintDD::VetoNuDetectorManager *m_detectorManager; + VetoNuGeometryManager *m_geometryManager; + VetoNuDataBase* m_db; + VetoNuMaterialManager* m_materials; + bool m_useDynamicAlignFolders; + +}; + +#endif + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorTool.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9b74df9592c7c1e4226163a36a06cd0e4a872962 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuDetectorTool.cxx @@ -0,0 +1,249 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuGeoModel/VetoNuDetectorTool.h" + +#include "VetoNuDetectorFactory.h" +#include "VetoNuDataBase.h" +// #include "VetoNuMaterialManager.h" +#include "VetoNuOptions.h" + +// temporary +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" +#include "ScintIdentifier/VetoNuID.h" +#include "DetDescrConditions/AlignableTransformContainer.h" + +#include "GeoModelFaserUtilities/GeoModelExperiment.h" +#include "GeoModelFaserUtilities/DecodeFaserVersionKey.h" +#include "StoreGate/DataHandle.h" +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" + +#include "AthenaKernel/ClassID_traits.h" +#include "SGTools/DataProxy.h" + +using ScintDD::VetoNuDetectorManager; +using ScintDD::ScintDetectorManager; + +// +// Constructor +// +VetoNuDetectorTool::VetoNuDetectorTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : GeoModelTool(type, name, parent), + m_cosmic{false}, + m_manager{nullptr}, + m_athenaComps{ }, + m_geoDbTagSvc{"GeoDbTagSvc", name}, + m_rdbAccessSvc{"RDBAccessSvc", name}, + m_geometryDBSvc{"ScintGeometryDBSvc", name} +{ + // Get parameter values from jobOptions file + declareProperty("GeoDbTagSvc", m_geoDbTagSvc); + declareProperty("RDBAccessSvc", m_rdbAccessSvc); + declareProperty("GeometryDBSvc", m_geometryDBSvc); +} + +// +// Create the Geometry via the factory corresponding to this tool +// + +StatusCode +VetoNuDetectorTool::create() +{ + // Get the detector configuration. + ATH_CHECK(m_geoDbTagSvc.retrieve()); + + DecodeFaserVersionKey versionKey{&*m_geoDbTagSvc, "VetoNu"}; + // Issue error if AUTO. + if (versionKey.tag() == "AUTO") { + ATH_MSG_ERROR("AUTO Faser version. Please select a version."); + } + ATH_MSG_INFO("Building VetoNu with Version Tag: " << versionKey.tag() << " at Node: " << versionKey.node()); + + ATH_CHECK(m_rdbAccessSvc.retrieve()); + // Print the VetoNu version tag: + std::string vetoVersionTag{m_rdbAccessSvc->getChildTag("VetoNu", versionKey.tag(), versionKey.node(), "FASERDD")}; + ATH_MSG_INFO("VetoNu Version: " << vetoVersionTag); + // Check if version is empty. If so, then the VetoNu cannot be built. This may or may not be intentional. We + // just issue an INFO message. + if (vetoVersionTag.empty()) { + ATH_MSG_INFO("No VetoNu Version. VetoNu will not be built."); + } else { + std::string versionName; + if (versionKey.custom()) { + ATH_MSG_WARNING("VetoNuDetectorTool: Detector Information coming from a custom configuration!!"); + } else { + ATH_MSG_DEBUG("VetoNuDetectorTool: Detector Information coming from the database and job options IGNORED."); + ATH_MSG_DEBUG("Keys for VetoNu Switches are " << versionKey.tag() << " " << versionKey.node()); + + IRDBRecordset_ptr switchSet{m_rdbAccessSvc->getRecordsetPtr("VetoNuSwitches", versionKey.tag(), versionKey.node(), "FASERDD")}; + const IRDBRecord* switches{(*switchSet)[0]}; + m_detectorName.setValue(switches->getString("DETECTORNAME")); + + if (not switches->isFieldNull("COSMICLAYOUT")) + { + m_cosmic = switches->getInt("COSMICLAYOUT"); + } + if (not switches->isFieldNull("VERSIONNAME")) + { + versionName = switches->getString("VERSIONNAME"); + } + } + + ATH_MSG_DEBUG("Creating the VetoNu"); + ATH_MSG_DEBUG("VetoNu Geometry Options: "); + ATH_MSG_DEBUG(" Alignable: " << (m_alignable.value() ? "true" : "false")); + ATH_MSG_DEBUG(" CosmicLayout: " << (m_cosmic ? "true" : "false")); + ATH_MSG_DEBUG(" VersionName: " << versionName); + + VetoNuOptions options; + options.setAlignable(m_alignable.value()); + options.setDynamicAlignFolders(m_useDynamicAlignFolders.value()); + m_manager = nullptr; + + // + // Locate the top level experiment node + // + GeoModelExperiment* theExpt{nullptr}; + ATH_CHECK(detStore()->retrieve(theExpt, "FASER")); + + // Retrieve the Geometry DB Interface + ATH_CHECK(m_geometryDBSvc.retrieve()); + + // Pass athena services to factory, etc + m_athenaComps.setDetStore(detStore().operator->()); + m_athenaComps.setGeoDbTagSvc(&*m_geoDbTagSvc); + m_athenaComps.setGeometryDBSvc(&*m_geometryDBSvc); + m_athenaComps.setRDBAccessSvc(&*m_rdbAccessSvc); + const VetoNuID* idHelper{nullptr}; + ATH_CHECK(detStore()->retrieve(idHelper, "VetoNuID")); + m_athenaComps.setIdHelper(idHelper); + idHelper->test_plate_packing(); + // + // This strange way of casting is to avoid an + // utterly brain damaged compiler warning. + // + GeoPhysVol* world{&*theExpt->getPhysVol()}; + if (world != nullptr) ATH_MSG_INFO("Retrieved World PhysVol"); + + VetoNuDetectorFactory theVetoNu{&m_athenaComps, options}; + ATH_MSG_INFO("Created instance of detector factory"); + theVetoNu.create(world); + ATH_MSG_INFO("Called create methon on factory"); + m_manager = theVetoNu.getDetectorManager(); + ATH_MSG_INFO("Attempted to retrieve detector manager"); + + if (m_manager==nullptr) { + ATH_MSG_FATAL("VetoNuDetectorManager not created"); + return StatusCode::FAILURE; + } + + // Get the manager from the factory and store it in the detector store. + // m_detector is non constant so I can not set it to a const pointer. + // m_detector = theSCT.getDetectorManager(); + + ATH_MSG_DEBUG("Registering VetoNuDetectorManager. "); + ATH_CHECK(detStore()->record(m_manager, m_manager->getName())); + theExpt->addManager(m_manager); + + // Create a symLink to the ScintDetectorManager base class + const ScintDetectorManager* scintDetManager{m_manager}; + ATH_CHECK(detStore()->symLink(m_manager, scintDetManager)); + } + + return StatusCode::SUCCESS; +} + +StatusCode +VetoNuDetectorTool::clear() +{ + ATH_MSG_WARNING("Called untested VetoNuDetectorTool::clear()"); + SG::DataProxy* proxy{detStore()->proxy(ClassID_traits<VetoNuDetectorManager>::ID(), m_manager->getName())}; + if (proxy) { + proxy->reset(); + m_manager = nullptr; + } + return StatusCode::SUCCESS; +} + +StatusCode +VetoNuDetectorTool::registerCallback() +{ + StatusCode sc{StatusCode::FAILURE}; + if (m_alignable.value()) { + ATH_MSG_WARNING("Called untested VetoNuDetectorTool::registerCallback()"); + if (m_useDynamicAlignFolders.value()) { + + if (detStore()->contains<CondAttrListCollection>(m_run2L1Folder.value())) { + ATH_MSG_DEBUG("Registering callback on global Container with folder " << m_run2L1Folder.value()); + const DataHandle<CondAttrListCollection> calc; + ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), calc, m_run2L1Folder.value())); + sc = StatusCode::SUCCESS; + } else { + ATH_MSG_WARNING("Unable to register callback on global Container with folder " << m_run2L1Folder.value()); + return StatusCode::FAILURE; + } + + if (detStore()->contains<CondAttrListCollection>(m_run2L2Folder.value())) { + ATH_MSG_DEBUG("Registering callback on global Container with folder " << m_run2L2Folder.value()); + const DataHandle<CondAttrListCollection> calc; + ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), calc, m_run2L2Folder.value())); + sc = StatusCode::SUCCESS; + } else { + ATH_MSG_WARNING("Unable to register callback on global Container with folder " << m_run2L2Folder.value()); + return StatusCode::FAILURE; + } + + if (detStore()->contains<AlignableTransformContainer>(m_run2L3Folder.value())) { + ATH_MSG_DEBUG("Registering callback on AlignableTransformContainer with folder " << m_run2L3Folder.value()); + const DataHandle<AlignableTransformContainer> atc; + ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), atc, m_run2L3Folder.value())); + sc = StatusCode::SUCCESS; + } else { + ATH_MSG_WARNING("Unable to register callback on AlignableTransformContainer with folder " << m_run2L3Folder.value()); + return StatusCode::FAILURE; + } + + } else { + + if (detStore()->contains<AlignableTransformContainer>(m_run1Folder.value())) { + ATH_MSG_DEBUG("Registering callback on AlignableTransformContainer with folder " << m_run1Folder.value()); + const DataHandle<AlignableTransformContainer> atc; + ATH_CHECK(detStore()->regFcn(&IGeoModelTool::align, dynamic_cast<IGeoModelTool*>(this), atc, m_run1Folder.value())); + sc = StatusCode::SUCCESS; + } else { + ATH_MSG_WARNING("Unable to register callback on AlignableTransformContainer with folder " + << m_run1Folder.value() << ", Alignment disabled (only if no Run2 scheme is loaded)!"); + return StatusCode::FAILURE; + } + } + } else { + ATH_MSG_INFO("Alignment disabled. No callback registered"); + // We return failure otherwise it will try and register + // a GeoModelSvc callback associated with this callback. + return StatusCode::FAILURE; + } + return sc; +} + +StatusCode +VetoNuDetectorTool::align(IOVSVC_CALLBACK_ARGS_P(I, keys)) +{ + ATH_MSG_WARNING("Called untested VetoNuDetectorTool::align()"); + void* i = &I; + void* k = &keys; + if (i == nullptr && k == nullptr) return StatusCode::SUCCESS; // suppress stupid warning + if (m_manager==nullptr) { + ATH_MSG_FATAL("Manager does not exist"); + return StatusCode::FAILURE; + } + if (m_alignable.value()) { + return m_manager->align(I, keys); + } else { + ATH_MSG_DEBUG("Alignment disabled. No alignments applied"); + return StatusCode::SUCCESS; + } +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2e88fe60692993cd96c766032a9a396e8fb65416 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.cxx @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuGeneralParameters.h" +#include "VetoNuDataBase.h" +#include "RDBAccessSvc/IRDBRecord.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "GaudiKernel/SystemOfUnits.h" +#include "GeoModelKernel/GeoDefinitions.h" +#include "ScintGeoModelUtils/TopLevelPlacements.h" + +const double VetoNuSAFETY = 0.01 * Gaudi::Units::mm; // Used in some places to make envelopes slightly larger to ensure + // no overlaps due to rounding errors. + + +VetoNuGeneralParameters::VetoNuGeneralParameters(VetoNuDataBase* rdb) +{ + m_rdb = rdb; + m_placements = new TopLevelPlacements(m_rdb->topLevelTable()); +} + + +VetoNuGeneralParameters::~VetoNuGeneralParameters() +{ + delete m_placements; +} + + +const GeoTrf::Transform3D & +VetoNuGeneralParameters::partTransform(const std::string & partName) const +{ + return m_placements->transform(partName); +} + + +bool +VetoNuGeneralParameters::partPresent(const std::string & partName) const +{ + return m_placements->present(partName); +} + + + +// +// General +// +double +VetoNuGeneralParameters::safety() const +{ + return VetoNuSAFETY; +} + +// Default Conditions. Values should be come form conditions data base. These values provide +// default vlaues if nothing from the conditions database is provided. + + +// double +// VetoNuGeneralParameters::temperature() const +// { +// if (m_rdb->conditionsTable()->size() == 0) { +// return 266.15 * Gaudi::Units::kelvin; // -7 C +// } +// return (m_rdb->conditions()->getDouble("TEMPERATURE") + 273.15) * Gaudi::Units::kelvin; +// } + + +// double +// SCT_GeneralParameters::biasVoltage() const +// { +// if (m_rdb->conditionsTable()->size() == 0) { +// return 100 * Gaudi::Units::volt; +// } +// return m_rdb->conditions()->getDouble("BIASVOLT") * Gaudi::Units::volt; +// } + +// double +// SCT_GeneralParameters::depletionVoltage() const +// { +// if (m_rdb->conditionsTable()->size() == 0) { +// return 20 * Gaudi::Units::volt; +// } +// return m_rdb->conditions()->getDouble("DEPLETIONVOLT") * Gaudi::Units::volt; +// } + + + + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..d8a6d55788bf3ea6347204ecd8980f79f157854d --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeneralParameters.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuGeneralParameters_H +#define VetoNuGeoModel_VetoNuGeneralParameters_H + +#include "GeoModelKernel/GeoDefinitions.h" + +#include <map> +#include <string> + +class VetoNuDataBase; +class TopLevelPlacements; + +class VetoNuGeneralParameters { + +public: + + VetoNuGeneralParameters(VetoNuDataBase* rdb); + ~VetoNuGeneralParameters(); + //Explicitly disallow copy, assignment to appease coverity + VetoNuGeneralParameters(const VetoNuGeneralParameters &) = delete; + VetoNuGeneralParameters & operator=(const VetoNuGeneralParameters &) = delete; + + // General + double safety() const; + + //Default conditions. +// double temperature() const; +// double biasVoltage() const; +// double depletionVoltage() const; + + const GeoTrf::Transform3D & partTransform(const std::string & partName) const; + bool partPresent(const std::string & partName) const; + +private: + + VetoNuDataBase * m_rdb; + TopLevelPlacements * m_placements; + +}; + + +#endif // SCT_GeoModel_SCT_GeneralParameters_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeoModelAthenaComps.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeoModelAthenaComps.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ad8256acbb791c752d6cf80272104e4f76944b98 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeoModelAthenaComps.cxx @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" + +VetoNuGeoModelAthenaComps::VetoNuGeoModelAthenaComps() + : ScintDD::AthenaComps("VetoNuGeoModel"), + m_idHelper(0) +{} + +void +VetoNuGeoModelAthenaComps::setIdHelper(const VetoNuID* idHelper) +{ + m_idHelper = idHelper; +} + +const VetoNuID* +VetoNuGeoModelAthenaComps::getIdHelper() const +{ + return m_idHelper; +} + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..df334a198a6f6c6a8c61d66863327000a2e3c71d --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.cxx @@ -0,0 +1,123 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuGeometryManager.h" + +#include "ScintGeoModelUtils/DistortedMaterialManager.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintReadoutGeometry/ScintCommonItems.h" +#include "VetoNuStationParameters.h" +#include "VetoNuPlateParameters.h" +#include "VetoNuRadiatorParameters.h" +#include "VetoNuDataBase.h" +#include "VetoNuGeneralParameters.h" +#include "VetoNuGeoModel/VetoNuGeoModelAthenaComps.h" + +VetoNuGeometryManager::VetoNuGeometryManager(VetoNuDataBase* rdb) + : m_athenaComps{rdb->athenaComps()}, + m_rdb{rdb} +{ + // This class uses reference counting. Should not be delete'd in destructor. + m_commonItems = new ScintDD::ScintCommonItems(m_athenaComps->getIdHelper()); + + m_stationParameters = std::make_unique<VetoNuStationParameters>(m_rdb); + m_plateParameters = std::make_unique<VetoNuPlateParameters>(m_rdb); + m_radiatorParameters = std::make_unique<VetoNuRadiatorParameters>(m_rdb); + m_generalParameters = std::make_unique<VetoNuGeneralParameters>(m_rdb); + m_distortedMatManager = std::make_unique<ScintDD::DistortedMaterialManager>(); +} + +VetoNuGeometryManager::~VetoNuGeometryManager() +{ +} + +// +// Access to run time options. +// +const VetoNuOptions & +VetoNuGeometryManager::options() const +{ + return m_options; +} + +void +VetoNuGeometryManager::setOptions(const VetoNuOptions & options) +{ + m_options = options; +} + +const VetoNuGeoModelAthenaComps * +VetoNuGeometryManager::athenaComps() const +{ + return m_athenaComps; +} + +// +// ScintCommonItems which are passed to ScintDetectorElements. +// + +const ScintDD::ScintCommonItems * +VetoNuGeometryManager::commonItems() const +{ + return m_commonItems; +} + +const VetoNuStationParameters * +VetoNuGeometryManager::stationParameters() const +{ + return m_stationParameters.get(); +} + +const VetoNuPlateParameters * +VetoNuGeometryManager::plateParameters() const +{ + return m_plateParameters.get(); +} + +const VetoNuRadiatorParameters * +VetoNuGeometryManager::radiatorParameters() const +{ + return m_radiatorParameters.get(); +} + + +const VetoNuGeneralParameters * +VetoNuGeometryManager::generalParameters() const +{ + return m_generalParameters.get(); +} + +const ScintDD::DistortedMaterialManager * +VetoNuGeometryManager::distortedMatManager() const +{ + return m_distortedMatManager.get(); +} + +VetoNuGeometryManager& +VetoNuGeometryManager::operator=(const VetoNuGeometryManager& right) { + if (this != &right) { + m_options = right.m_options; + m_athenaComps = right.m_athenaComps; + m_commonItems = right.m_commonItems; + m_rdb = right.m_rdb; + m_stationParameters.reset(new VetoNuStationParameters(m_rdb)); + m_plateParameters.reset(new VetoNuPlateParameters(m_rdb)); + m_radiatorParameters.reset(new VetoNuRadiatorParameters(m_rdb)); + m_generalParameters.reset(new VetoNuGeneralParameters(m_rdb)); + m_distortedMatManager.reset(new ScintDD::DistortedMaterialManager()); + } + return *this; +} + +VetoNuGeometryManager::VetoNuGeometryManager(const VetoNuGeometryManager& right) { + m_options = right.m_options; + m_athenaComps = right.m_athenaComps; + m_commonItems = right.m_commonItems; + m_rdb = right.m_rdb; + m_stationParameters.reset(new VetoNuStationParameters(m_rdb)); + m_plateParameters.reset(new VetoNuPlateParameters(m_rdb)); + m_radiatorParameters.reset(new VetoNuRadiatorParameters(m_rdb)); + m_generalParameters.reset(new VetoNuGeneralParameters(m_rdb)); + m_distortedMatManager.reset(new ScintDD::DistortedMaterialManager()); +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.h new file mode 100644 index 0000000000000000000000000000000000000000..0fa5eff1bc628cf691df5ee05269832b5aa62eb4 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuGeometryManager.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuGeometryManager_H +#define VetoNuGeoModel_VetoNuGeometryManager_H + +#include "VetoNuOptions.h" + +#include <memory> + +namespace ScintDD { + class ScintCommonItems; + class DistortedMaterialManager; +} + +class VetoNuStationParameters; +class VetoNuPlateParameters; +class VetoNuRadiatorParameters; +class VetoNuDataBase; +class VetoNuGeneralParameters; +class VetoNuGeoModelAthenaComps; + +class VetoNuGeometryManager { + +public: + + // Constructor + VetoNuGeometryManager(VetoNuDataBase* rdb); + + // Destructor + ~VetoNuGeometryManager(); + + // Access to run time options + const VetoNuOptions & options() const; + void setOptions(const VetoNuOptions & options); + + // Access to athena components + const VetoNuGeoModelAthenaComps * athenaComps() const; + + // To be passed to detector element. + const ScintDD::ScintCommonItems * commonItems() const; + + const VetoNuStationParameters* stationParameters() const; + const VetoNuPlateParameters* plateParameters() const; + const VetoNuRadiatorParameters* radiatorParameters() const; + const VetoNuGeneralParameters* generalParameters() const; + const ScintDD::DistortedMaterialManager* distortedMatManager() const; + + VetoNuGeometryManager& operator=(const VetoNuGeometryManager& right); + VetoNuGeometryManager(const VetoNuGeometryManager& right); + +private: + + VetoNuOptions m_options; + const VetoNuGeoModelAthenaComps * m_athenaComps; + ScintDD::ScintCommonItems * m_commonItems; + VetoNuDataBase* m_rdb; + + std::unique_ptr<VetoNuStationParameters> m_stationParameters; + std::unique_ptr<VetoNuPlateParameters> m_plateParameters; + std::unique_ptr<VetoNuRadiatorParameters> m_radiatorParameters; + std::unique_ptr<VetoNuGeneralParameters> m_generalParameters; + std::unique_ptr<ScintDD::DistortedMaterialManager> m_distortedMatManager; + +}; + + +#endif // VetoNuGeoModel_VetoNuGeometryManager_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8ef8f33806fce3f29f70568fe1feeac9c623eaad --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.cxx @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuIdentifier.h" +#include "ScintIdentifier/VetoNuID.h" +#include "Identifier/Identifier.h" + +#include <cassert> +#include <iostream> + +Identifier +VetoNuIdentifier::getPlateId() +{ + assert (m_idHelper); + return m_idHelper->plate_id(m_station, m_plate); +} + +void VetoNuIdentifier::print() +{ + std::cout << "2/1/" << m_station << "/" + << m_plate << std::endl; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.h new file mode 100644 index 0000000000000000000000000000000000000000..b19425ffe01c560ad0338cd28c6d04b05131e0a2 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuIdentifier.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUIDENTIFIER_H +#define VETONUGEOMODEL_VETONUIDENTIFIER_H + +class Identifier; +class VetoNuID; + +class VetoNuIdentifier +{ +public: + + VetoNuIdentifier( const VetoNuID* idHelper, + int station = 0, + int plate = 0 ) + : m_idHelper{idHelper}, + m_station{station}, + m_plate{plate} + {}; + + + void setStation(int i) {m_station = i;} + int getStation() const {return m_station;} + + void setPlate(int i) {m_plate = i;} + int getPlate() const {return m_plate;} + + Identifier getPlateId(); + + // For debugging purposes. + void print(); + +private: + const VetoNuID* m_idHelper; + int m_station; + int m_plate; +}; + +#endif // VETOGEOMODEL_VETOIDENTIFIER_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.cxx new file mode 100644 index 0000000000000000000000000000000000000000..da71318c2526648265235b17e51297ef98f9dde5 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.cxx @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuMaterialManager.h" +#include "GeoModelKernel/GeoMaterial.h" +#include "GeoModelKernel/GeoElement.h" +#include "VetoNuDataBase.h" +#include "RDBAccessSvc/IRDBRecordset.h" +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <iostream> + +// Constructor +VetoNuMaterialManager::VetoNuMaterialManager(VetoNuDataBase* db) +{ + // Get my material manager. + ISvcLocator* svcLocator = Gaudi::svcLocator(); // from Bootstrap + StoreGateSvc* detStore; + StatusCode sc = svcLocator->service("DetectorStore", detStore ); + if (sc.isFailure()) { + std::cout << "Could not locate DetectorStore" << std::endl; + return; + } + + m_materialManager = std::make_unique<ScintMaterialManager>("VetoNuMaterialManager", db->athenaComps()); + m_materialManager->addWeightTable(db->weightTable(), "veto"); + m_materialManager->addScalingTable(db->scalingTable()); + + loadMaterials(); + + m_gasMaterial = m_materialManager->getMaterial("std::Air"); +} + +// Add materials not yet in the database +void +VetoNuMaterialManager::loadMaterials() +{ +} + +const GeoElement* +VetoNuMaterialManager::getElement(const std::string & elementName) const +{ + return m_materialManager->getElement(elementName); +} + +const GeoMaterial* +VetoNuMaterialManager::getMaterial(const std::string & materialName) const +{ + return m_materialManager->getMaterial(materialName); +} + +void +VetoNuMaterialManager::addMaterial(GeoMaterial* material) +{ + return m_materialManager->addMaterial(material); +} + +const GeoMaterial* +VetoNuMaterialManager::getMaterial(const std::string & originalMaterial, + double density, + const std::string & newName) +{ + + return m_materialManager->getMaterial(originalMaterial, density, newName); +} + +const GeoMaterial * +VetoNuMaterialManager::getMaterialForVolume(const std::string & materialName, double volume) +{ + return m_materialManager->getMaterialForVolume(materialName, volume); +} + + + +const GeoMaterial* +VetoNuMaterialManager::gasMaterial() const +{ + return m_gasMaterial; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.h new file mode 100644 index 0000000000000000000000000000000000000000..32f0ded52b1868e2b09b926d64d9bf3c6417dbff --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuMaterialManager.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUMATERIALMANAGER_H +#define VETONUMATERIALMANAGER_H + +// VetoNuMaterialManager. This provides an interface to the ScintMaterialManager which in turn +// is an interface to GeoModel Material Manager with some additional functionality. +#include "ScintGeoModelUtils/ScintMaterialManager.h" + +#include <memory> +#include <string> + +class GeoMaterial; +class GeoElement; +class ScintMaterialManager; +class VetoNuDataBase; + +class VetoNuMaterialManager +{ + +public: + + VetoNuMaterialManager(VetoNuDataBase* db); + + const GeoMaterial* getMaterial(const std::string & materialName) const; + const GeoElement* getElement(const std::string & elementName) const; + + const GeoMaterial* getMaterial(const std::string & originalMaterial, + double density, + const std::string & newName = ""); + const GeoMaterial *getMaterialForVolume(const std::string & materialName, double volume); + + // Default gas material + const GeoMaterial* gasMaterial() const; + +private: + void loadMaterials(); + void addMaterial(GeoMaterial* material); + + std::unique_ptr<ScintMaterialManager> m_materialManager; + const GeoMaterial* m_gasMaterial; + +}; + + +#endif // VETONUMATERIALMANAGER_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0c63b320f4d5e2063e5047c4fa07a0ac1ebd011c --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.cxx @@ -0,0 +1,47 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuOptions.h" + +VetoNuOptions::VetoNuOptions() + : m_alignable(true) +// , m_alignModule(true) + , m_dynAlignFolders(false) +{} + +void +VetoNuOptions::setAlignable(bool flag) +{ + m_alignable = flag; +} + +bool +VetoNuOptions::alignable() const +{ + return m_alignable; +} + +// following may eventually become useful +// +// void +// SCT_Options::setAlignAtModuleLevel(bool flag) +// { +// m_alignModule = flag; +// } + +// bool +// SCT_Options::alignAtModuleLevel() const +// { +// return m_alignModule; +// } + +void VetoNuOptions::setDynamicAlignFolders(const bool flag) +{ + m_dynAlignFolders = flag; +} + +bool VetoNuOptions::dynamicAlignFolders() const +{ + return m_dynAlignFolders; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.h new file mode 100644 index 0000000000000000000000000000000000000000..166ae9e6cb2116b3372b3d485e5b9df0f91402aa --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuOptions.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuOptions_H +#define VetoNuGeoModel_VetoNuOptions_H + +// Class for any run time options. + + +class VetoNuOptions +{ + +public: + VetoNuOptions(); + bool alignable() const; +// bool alignAtModuleLevel() const; + + void setAlignable(bool flag = true); +// void setAlignAtModuleLevel(bool flag = true); + + //dynamic alignment folders + void setDynamicAlignFolders(const bool flag = true); + bool dynamicAlignFolders() const; + +private: + + bool m_alignable; +// bool m_alignModule; + bool m_dynAlignFolders; //controls which set of alignment folders is used + +}; + + +#endif // VetoNuGeoModel_VetoNuOptions_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e14c88cbe5cb09c886752d7be8d8a57c0dfbd836 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.cxx @@ -0,0 +1,117 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuPlate.h" + +#include "VetoNuGeometryManager.h" +#include "VetoNuMaterialManager.h" + +#include "VetoNuPlateParameters.h" + +#include "GeoModelKernel/GeoBox.h" +#include "GeoModelKernel/GeoLogVol.h" +#include "GeoModelKernel/GeoFullPhysVol.h" +#include "GeoModelKernel/GeoMaterial.h" + +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" +#include "ScintReadoutGeometry/ScintDetectorDesign.h" +#include "ScintReadoutGeometry/ScintDetectorElement.h" +#include "ScintReadoutGeometry/ScintDD_Defs.h" +#include "ScintReadoutGeometry/ScintCommonItems.h" + +#include "GaudiKernel/SystemOfUnits.h" + +using namespace ScintDD; + +VetoNuPlate::VetoNuPlate(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials) + : VetoNuUniqueComponentFactory(name, detectorManager, geometryManager, materials), + m_noElementWarning{true} +{ + getParameters(); + m_logVolume = preBuild(); +} + + +void +VetoNuPlate::getParameters() +{ + + const VetoNuPlateParameters * parameters = m_geometryManager->plateParameters(); + m_material = m_materials->getMaterial(parameters->plateMaterial()); + m_thickness = parameters->plateThickness(); + m_length = parameters->plateLength(); + m_width = parameters->plateWidth(); + m_detectorManager->numerology().setNumPmtsPerPlate(parameters->platePmts()); +} + +const GeoLogVol * +VetoNuPlate::preBuild() +{ + + // Build the plate. Just a simple box. + // const GeoBox * plateShape = new GeoBox(0.5*m_thickness, 0.5*m_width, 0.5*m_length); + const GeoBox * plateShape = new GeoBox(0.5*m_width, 0.5*m_length, 0.5*m_thickness); + GeoLogVol * plateLog = new GeoLogVol(getName(), plateShape, m_material); + + // Make the scint design for this plate + makeDesign(); + + m_detectorManager->setDesign(m_design); + + return plateLog; +} + + +void +VetoNuPlate::makeDesign() +{ + //SiDetectorDesign::Axis etaAxis = SiDetectorDesign::zAxis; + //SiDetectorDesign::Axis phiAxis = SiDetectorDesign::yAxis; + //SiDetectorDesign::Axis depthAxis = SiDetectorDesign::xAxis; + + const VetoNuPlateParameters * parameters = m_geometryManager->plateParameters(); + + m_design = new ScintDetectorDesign(m_thickness, + m_length, + m_width, + parameters->platePmts()); +} + + + +GeoVPhysVol * +VetoNuPlate::build(VetoNuIdentifier id) +{ + GeoFullPhysVol * plate = new GeoFullPhysVol(m_logVolume); + + // Make detector element and add to collection + // Only do so if we have a valid id helper. + + //id.print(); // for debugging only + + const ScintCommonItems* commonItems = m_geometryManager->commonItems(); + + if (commonItems->getIdHelper()) { + + ScintDetectorElement * detElement; + + detElement = new ScintDetectorElement(id.getPlateId(), + m_design, + plate, + commonItems); + + // Add the detector element. + m_detectorManager->addDetectorElement(detElement); + + } else { + if (m_noElementWarning) { + std::cout << "WARNING!!!!: No VetoNu id helper and so no elements being produced." << std::endl; + m_noElementWarning = false; + } + } + return plate; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.h new file mode 100644 index 0000000000000000000000000000000000000000..efc8638052c8dcb8c083d63584dccf649354d7ce --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlate.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUPLATE_H +#define VETONUGEOMODEL_VETONUPLATE_H + +#include "VetoNuComponentFactory.h" + +#include <atomic> +#include <string> + +class GeoMaterial; +class GeoVPhysVol; +namespace ScintDD{class ScintDetectorDesign;} + +class VetoNuPlate: public VetoNuUniqueComponentFactory +{ +public: + VetoNuPlate(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials); + +public: + const GeoMaterial * material() const {return m_material;} + double thickness() const {return m_thickness;} + double width() const {return m_width;} + double length() const {return m_length;} + + virtual GeoVPhysVol * build(VetoNuIdentifier id); + +private: + void getParameters(); + virtual const GeoLogVol * preBuild(); + void makeDesign(); + + const GeoMaterial * m_material; + double m_thickness; + double m_width; + double m_length; + + ScintDD::ScintDetectorDesign * m_design; + + mutable std::atomic_bool m_noElementWarning; +}; + +#endif // VETOGEOMODEL_VETOPLATE_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..121df4dcbc9c60ead0099ea05b22d9de56e78809 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.cxx @@ -0,0 +1,52 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuPlateParameters.h" +#include "VetoNuGeometryManager.h" + +#include "VetoNuDataBase.h" + +#include "RDBAccessSvc/IRDBRecord.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <cmath> + + +VetoNuPlateParameters::VetoNuPlateParameters(VetoNuDataBase* rdb) +{ + m_rdb = rdb; +} + +// +// Plate General +// +int +VetoNuPlateParameters::platePmts() const +{ + return m_rdb->plateGeneral()->getInt("NUMPMTS"); +} + +double +VetoNuPlateParameters::plateWidth() const +{ + return m_rdb->plateGeneral()->getDouble("WIDTH") * Gaudi::Units::mm; +} + +double +VetoNuPlateParameters::plateLength() const +{ + return m_rdb->plateGeneral()->getDouble("LENGTH") * Gaudi::Units::mm; +} + +double +VetoNuPlateParameters::plateThickness() const +{ + return m_rdb->plateGeneral()->getDouble("THICKNESS") * Gaudi::Units::mm; +} + +std::string VetoNuPlateParameters::plateMaterial() const +{ + return m_rdb->plateGeneral()->getString("MATERIAL"); +} + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..11ebd07129db93286277420b25c532d2cf51bbce --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuPlateParameters.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuPlateParameters_H +#define VetoNuGeoModel_VetoNuPlateParameters_H + +#include <string> + +class VetoNuDataBase; + +class VetoNuPlateParameters { + +public: + + // Constructor + VetoNuPlateParameters(VetoNuDataBase* rdb); + + // Barrel General + int platePmts() const; + double plateThickness() const; + double plateWidth() const; + double plateLength() const; + std::string plateMaterial() const; + + private: + VetoNuDataBase * m_rdb; + +}; + + +#endif // VetoNuGeoModel_VetoNuPlateParameters_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..49a9fe83c78c883f968f020d38e942fcd53ffdbe --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.cxx @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuRadiator.h" + +#include "VetoNuMaterialManager.h" + +#include "VetoNuGeometryManager.h" +#include "VetoNuGeneralParameters.h" +#include "VetoNuRadiatorParameters.h" + +#include "GeoModelKernel/GeoBox.h" +#include "GeoModelKernel/GeoLogVol.h" +#include "GeoModelKernel/GeoPhysVol.h" +#include "GeoModelKernel/GeoMaterial.h" + +VetoNuRadiator::VetoNuRadiator(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials) + : VetoNuSharedComponentFactory(name, detectorManager, geometryManager, materials) +{ + getParameters(); + m_physVolume = build(); +} + +void +VetoNuRadiator::getParameters() +{ + const VetoNuRadiatorParameters * parameters = m_geometryManager->radiatorParameters(); + const VetoNuGeneralParameters* generalParameters = m_geometryManager->generalParameters(); + + m_material = m_materials->getMaterial(parameters->radiatorMaterial()); + m_safety = generalParameters->safety(); + m_thickness = parameters->radiatorThickness(); + m_width = parameters->radiatorWidth(); + m_length = parameters->radiatorLength(); +} + +GeoVPhysVol * +VetoNuRadiator::build() +{ + // Just a simple box. + const GeoBox * simpleRadiatorShape = new GeoBox(0.5*m_width, + 0.5*m_length, + 0.5*m_thickness); + + const GeoLogVol * simpleRadiatorLog = + new GeoLogVol(getName(), simpleRadiatorShape, m_material); + + GeoPhysVol * simpleRadiator = new GeoPhysVol(simpleRadiatorLog); + + return simpleRadiator; +} diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.h new file mode 100644 index 0000000000000000000000000000000000000000..5c25fcec17f21b848c1a7f9e3f41d2b396e77277 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiator.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONURADIATOR_H +#define VETONUGEOMODEL_VETONURADIATOR_H + +#include "VetoNuComponentFactory.h" + +class GeoVPhysVol; +class GeoFullPhysVol; +class GeoLogVol; +class GeoMaterial; + +class VetoNuRadiator : public VetoNuSharedComponentFactory +{ + +public: + VetoNuRadiator(const std::string & name, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials); + +public: + const GeoMaterial * material() const {return m_material;} + double thickness() const {return m_thickness;} + double width() const {return m_width;} + double length() const {return m_length;} + +private: + virtual GeoVPhysVol * build(); + void getParameters(); + + const GeoMaterial * m_material; + double m_thickness; + double m_width; + double m_length; + + double m_safety; +}; + +#endif // VETOGEOMODEL_VETORADIATOR_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..33391054eaba30e6fde505065921e3a2594cd0d2 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.cxx @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuRadiatorParameters.h" +#include "VetoNuGeometryManager.h" + +#include "VetoNuDataBase.h" + +#include "RDBAccessSvc/IRDBRecord.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <cmath> + + +VetoNuRadiatorParameters::VetoNuRadiatorParameters(VetoNuDataBase* rdb) +{ + m_rdb = rdb; +} + +// +// Radiator General +// +double +VetoNuRadiatorParameters::radiatorWidth() const +{ + return m_rdb->radiatorGeneral()->getDouble("WIDTH") * Gaudi::Units::mm; +} + +double +VetoNuRadiatorParameters::radiatorLength() const +{ + return m_rdb->radiatorGeneral()->getDouble("LENGTH") * Gaudi::Units::mm; +} + +double +VetoNuRadiatorParameters::radiatorThickness() const +{ + return m_rdb->radiatorGeneral()->getDouble("THICKNESS") * Gaudi::Units::mm; +} + +std::string VetoNuRadiatorParameters::radiatorMaterial() const +{ + return m_rdb->radiatorGeneral()->getString("MATERIAL"); +} + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..eedd316d60e0c52a5b4f0b55640a5ddfea62f7b4 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuRadiatorParameters.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuRadiatorParameters_H +#define VetoNuGeoModel_VetoNuRadiatorParameters_H + +#include <string> + +class VetoNuDataBase; + +class VetoNuRadiatorParameters { + +public: + + // Constructor + VetoNuRadiatorParameters(VetoNuDataBase* rdb); + + // Barrel General + double radiatorThickness() const; + double radiatorWidth() const; + double radiatorLength() const; + std::string radiatorMaterial() const; + + private: + VetoNuDataBase * m_rdb; + +}; + + +#endif // VetoNuGeoModel_VetoNuRadiatorParameters_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..65fb5fd7b80d4eb2af761723476d75259923af43 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.cxx @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuStation.h" + +#include "VetoNuMaterialManager.h" + +#include "VetoNuGeometryManager.h" +#include "VetoNuStationParameters.h" +#include "VetoNuGeneralParameters.h" +#include "VetoNuIdentifier.h" +#include "VetoNuPlate.h" + +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" + +#include "ScintGeoModelUtils/ExtraMaterial.h" + +#include "GeoModelKernel/GeoBox.h" +#include "GeoModelKernel/GeoLogVol.h" +#include "GeoModelKernel/GeoFullPhysVol.h" +#include "GeoModelKernel/GeoPhysVol.h" +#include "GeoModelKernel/GeoNameTag.h" +#include "GeoModelKernel/GeoIdentifierTag.h" +#include "GeoModelKernel/GeoTransform.h" +#include "GeoModelKernel/GeoAlignableTransform.h" +#include "GeoModelKernel/GeoMaterial.h" +#include "GeoModelKernel/GeoShape.h" +#include "GeoModelKernel/GeoShapeShift.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <iostream> + +VetoNuStation::VetoNuStation(const std::string & name, + VetoNuPlate* plate, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials) + : VetoNuUniqueComponentFactory(name, detectorManager, geometryManager, materials), + m_plate { plate } +{ + getParameters(); + m_logVolume = preBuild(); +} + + +void +VetoNuStation::getParameters() +{ + const VetoNuStationParameters * parameters = m_geometryManager->stationParameters(); + + m_numPlates = parameters->numPlates(); + m_platePitch = parameters->platePitch(); + + const VetoNuGeneralParameters* generalParameters = m_geometryManager->generalParameters(); + m_safety = generalParameters->safety(); + + m_width = m_plate->width() + m_safety; + m_length = m_plate->length() + m_safety; + // pitch includes thickness of one plate + m_thickness = (m_numPlates - 1) * m_platePitch + m_plate->thickness() + m_safety; + + // Set numerology + m_detectorManager->numerology().setNumPlatesPerStation(m_numPlates); +} + +const GeoLogVol * +VetoNuStation::preBuild() +{ + // Create the station volume + // Box envelope containing the station. + const GeoBox* stationEnvelopeShape = new GeoBox(0.5 * m_width, 0.5 * m_length, 0.5 * m_thickness); + GeoLogVol* stationLog = new GeoLogVol(getName(), stationEnvelopeShape, m_materials->gasMaterial()); + return stationLog; +} + +GeoVPhysVol * +VetoNuStation::build(VetoNuIdentifier id) +{ + + GeoFullPhysVol * station = new GeoFullPhysVol(m_logVolume); + + double activeDepth = m_thickness - m_safety; + double plateThickness = m_plate->thickness(); + for (int iPlate = 0; iPlate < m_numPlates; iPlate++) + { + station->add(new GeoNameTag("Plate#"+intToString(iPlate))); + station->add(new GeoIdentifierTag(iPlate)); + id.setPlate(iPlate); + GeoAlignableTransform* transform = new GeoAlignableTransform(GeoTrf::Translate3D(0.0, + 0.0, + (plateThickness - activeDepth)/2 + iPlate * m_platePitch)); + station->add(transform); + GeoVPhysVol* platePV = m_plate->build(id); + station->add(platePV); + m_detectorManager->addAlignableTransform(0, id.getPlateId(), transform, platePV); + } + return station; +} + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.h new file mode 100644 index 0000000000000000000000000000000000000000..50702df10006c6d767c929f68750b797c8fcae56 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStation.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VETONUGEOMODEL_VETONUSTATION_H +#define VETONUGEOMODEL_VETONUSTATION_H + +#include "VetoNuComponentFactory.h" + +class GeoVPhysVol; +class GeoFullPhysVol; +class GeoLogVol; +class VetoNuIdentifier; +class VetoNuPlate; + +class VetoNuStation : public VetoNuUniqueComponentFactory +{ + +public: + VetoNuStation(const std::string & name, + VetoNuPlate* plate, + ScintDD::VetoNuDetectorManager* detectorManager, + const VetoNuGeometryManager* geometryManager, + VetoNuMaterialManager* materials); + virtual GeoVPhysVol * build(VetoNuIdentifier id); + +public: + int numPlates() const {return m_numPlates;} + double platePitch() const {return m_platePitch;} + double thickness() const {return m_thickness;} + double width() const {return m_width;} + double length() const {return m_length;} + +private: + void getParameters(); + virtual const GeoLogVol * preBuild(); + + VetoNuPlate* m_plate; + + int m_numPlates; + double m_platePitch; + + double m_thickness; + double m_width; + double m_length; + + double m_safety; +}; + +#endif // VETONUGEOMODEL_VETONUSTATION_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9ec319eaa4377a7e5b58702f09b876d93c4752de --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.cxx @@ -0,0 +1,872 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "VetoNuStationParameters.h" +#include "VetoNuGeometryManager.h" + +#include "VetoNuDataBase.h" + +#include "RDBAccessSvc/IRDBRecord.h" +#include "GaudiKernel/SystemOfUnits.h" + +#include <cmath> + + +VetoNuStationParameters::VetoNuStationParameters(VetoNuDataBase* rdb) +{ + m_rdb = rdb; +} + + +// // +// // Barrel Ski +// // +// int +// SCT_BarrelParameters::skiFirstStagger() const +// { +// return m_rdb->brlSki()->getInt("SKIFIRSTSTAGGER"); +// } + +// double +// SCT_BarrelParameters::skiRadialSep() const +// { +// return m_rdb->brlSki()->getDouble("SKIRADIALSEP") * Gaudi::Units::mm; +// } + +// int +// SCT_BarrelParameters::modulesPerSki() const +// { +// return m_rdb->brlSkiZSize(); +// } + +// double +// SCT_BarrelParameters::skiZPosition(int index) const +// { +// return m_rdb->brlSkiZ(index)->getDouble("ZPOSITION") * Gaudi::Units::mm; +// } + +// int +// SCT_BarrelParameters::skiModuleIdentifier(int index) const +// { +// return m_rdb->brlSkiZ(index)->getInt("MODULEID"); +// } + +// // +// // Barrel Layer +// // +// double +// SCT_BarrelParameters::tilt(int iLayer) const +// { +// return m_rdb->brlLayer(iLayer)->getDouble("TILT") * Gaudi::Units::degree; +// } + +// int +// SCT_BarrelParameters::layerStereoSign(int iLayer) const +// { +// return m_rdb->brlLayer(iLayer)->getInt("STEREOSIGN"); +// } + + +// double +// SCT_BarrelParameters::radius(int iLayer) const +// { +// return m_rdb->brlLayer(iLayer)->getDouble("RADIUS") * Gaudi::Units::mm; +// } + +// int +// SCT_BarrelParameters::skisPerLayer(int iLayer) const +// { +// return m_rdb->brlLayer(iLayer)->getInt("SKISPERLAYER"); +// } + +// double +// SCT_BarrelParameters::layerBracketPhiOffset(int iLayer) const +// { +// return m_rdb->brlLayer(iLayer)->getDouble("BRACKETPHIOFFSET") * Gaudi::Units::deg; +// } + +// double +// SCT_BarrelParameters::layerPhiOfRefModule(int iLayer) const +// { +// // For backward compatibility, if field is null return (90 - tilt) +// // as ref module is horizontal in old versions. +// if (m_rdb->brlLayer(iLayer)->isFieldNull("PHIOFREFMODULE")) { +// return 90*Gaudi::Units::deg - tilt(iLayer); +// } +// return m_rdb->brlLayer(iLayer)->getDouble("PHIOFREFMODULE") * Gaudi::Units::deg; +// } + + +// // +// // Barrel Bracket +// // +// double +// SCT_BarrelParameters::bracketThickness() const +// { +// return m_rdb->brlSki()->getDouble("BRACKETTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::bracketWidth() const +// { +// return m_rdb->brlSki()->getDouble("BRACKETWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::bracketLength() const +// { +// return m_rdb->brlSki()->getDouble("BRACKETLENGTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::bracketMaterial() const +// { +// return m_rdb->brlSki()->getString("BRACKETMATERIAL"); +// } + +// // +// // Barrel Dogleg +// // +// double +// SCT_BarrelParameters::doglegThickness() const +// { +// return m_rdb->brlSki()->getDouble("DOGLEGTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::doglegWidth() const +// { +// return m_rdb->brlSki()->getDouble("DOGLEGWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::doglegLength() const +// { +// return m_rdb->brlSki()->getDouble("DOGLEGLENGTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::doglegMaterial() const +// { +// return m_rdb->brlSki()->getString("DOGLEGMATERIAL"); +// } + +// double +// SCT_BarrelParameters::doglegOffsetX() const +// { +// return m_rdb->brlSki()->getDouble("DOGLEGOFFSETX") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::doglegOffsetY() const +// { +// return m_rdb->brlSki()->getDouble("DOGLEGOFFSETY") * Gaudi::Units::mm; +// } + +// // +// // Barrel CoolingBlock +// // +// double +// SCT_BarrelParameters::coolingBlockThickness() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKTHICK") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::coolingBlockWidth() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::coolingBlockLength() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKLENGTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::coolingBlockMaterial() const +// { +// return m_rdb->brlSki()->getString("COOLINGBLOCKMATERIAL"); +// } + +// double +// SCT_BarrelParameters::coolingBlockOffsetX() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKOFFSETX") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::coolingBlockOffsetY() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKOFFSETY") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::coolingBlockOffsetZ() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGBLOCKOFFSETZ") * Gaudi::Units::mm; +// } + +// // +// // Barrel CoolingPipe +// // +// double +// SCT_BarrelParameters::coolingPipeRadius() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGPIPERADIUS") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::coolingPipeMaterial() const +// { +// return m_rdb->brlSki()->getString("COOLINGPIPEMATERIAL"); +// } + +// double +// SCT_BarrelParameters::coolingPipeOffsetX() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGPIPEOFFSETX") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::coolingPipeOffsetY() const +// { +// return m_rdb->brlSki()->getDouble("COOLINGPIPEOFFSETY") * Gaudi::Units::mm; +// } + + +// // +// // Barrel PowerTape +// // +// double +// SCT_BarrelParameters::powerTapeThickness() const +// { +// return m_rdb->brlSki()->getDouble("POWERTAPETHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::powerTapeWidth() const +// { +// return m_rdb->brlSki()->getDouble("POWERTAPEWIDTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::powerTapeMaterial() const +// { +// return m_rdb->brlSki()->getString("POWERTAPEMATERIAL"); +// } + +// double +// SCT_BarrelParameters::powerTapeStartPointOffset() const +// { +// return m_rdb->brlSki()->getDouble("POWERTAPESTARTOFFSET") * Gaudi::Units::mm; +// } + +// // +// // Barrel Harness +// // +// double +// SCT_BarrelParameters::harnessThickness() const +// { +// return m_rdb->brlSki()->getDouble("HARNESSTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::harnessWidth() const +// { +// return m_rdb->brlSki()->getDouble("HARNESSWIDTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::harnessMaterial() const +// { +// return m_rdb->brlSki()->getString("HARNESSMATERIAL"); +// } + +// // +// // Barrel SupportCyl +// // +// double +// SCT_BarrelParameters::supportCylInnerRadius(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("SUPPORTCYLINNERRAD") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::supportCylOuterRadius(int iLayer) const +// { +// return supportCylInnerRadius(iLayer) + supportCylDeltaR(iLayer); +// } + +// double +// SCT_BarrelParameters::supportCylDeltaR(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("SUPPORTCYLDELTAR") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::supportCylMaterial(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getString("SUPPORTCYLMATERIAL"); +// } + + +// // +// // Barrel Flange +// // +// double +// SCT_BarrelParameters::flangeDeltaZ(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("FLANGEDELTAZ") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::flangeDeltaR(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("FLANGEDELTAR") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::flangeMaterial(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getString("FLANGEMATERIAL"); +// } + +// // +// // Barrel Clamp +// // +// double +// SCT_BarrelParameters::clampDeltaZ(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("CLAMPDELTAZ") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::clampDeltaR(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("CLAMPDELTAR") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::clampMaterial(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getString("CLAMPMATERIAL"); +// } + +// // +// // Barrel Cooling Inlet/outlets +// // +// double +// SCT_BarrelParameters::coolingEndDeltaR(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("COOLINGENDDELTAR") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::coolingEndMaterial(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getString("COOLINGENDMATERIAL"); +// } + +// // +// // Barrel CloseOut +// // +// double +// SCT_BarrelParameters::closeOutDeltaZ(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getDouble("CLOSEOUTDELTAZ") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::closeOutMaterial(int iLayer) const +// { +// return m_rdb->brlServPerLayer(iLayer)->getString("CLOSEOUTMATERIAL"); +// } + +// // +// // Barrel InterLink and B6 bearing +// // +// double +// SCT_BarrelParameters::interLinkDeltaZ() const +// { +// return m_rdb->brlServices()->getDouble("INTERLINKDELTAZ") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::interLinkInnerRadius() const +// { +// return m_rdb->brlServices()->getDouble("INTERLINKINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::interLinkOuterRadius() const +// { +// return m_rdb->brlServices()->getDouble("INTERLINKOUTERRADIUS") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::interLinkMaterial() const +// { +// return m_rdb->brlServices()->getString("INTERLINKMATERIAL"); +// } + +// double +// SCT_BarrelParameters::interLinkDeltaPhi() const +// { +// if (m_rdb->brlServices()->isFieldNull("INTERLINKDPHI")) { +// return 360.*Gaudi::Units::deg; +// } +// return m_rdb->brlServices()->getDouble("INTERLINKDPHI") * Gaudi::Units::deg; +// } + +// double +// SCT_BarrelParameters::interLinkPhiPos() const +// { +// if (m_rdb->brlServices()->isFieldNull("INTERLINKPHIPOS")) { +// return 0.; +// } +// return m_rdb->brlServices()->getDouble("INTERLINKPHIPOS") * Gaudi::Units::deg; +// } + +// int +// SCT_BarrelParameters::interLinkNRepeat() const +// { +// if (m_rdb->brlServices()->isFieldNull("INTERLINKNREPEAT")) { +// return 1; +// } +// return m_rdb->brlServices()->getInt("INTERLINKNREPEAT"); +// } + +// double +// SCT_BarrelParameters::bearingDeltaPhi() const +// { +// if (m_rdb->brlServices()->isFieldNull("BEARINGDPHI")) { +// return 0.; +// } +// return m_rdb->brlServices()->getDouble("BEARINGDPHI") * Gaudi::Units::deg; +// } + +// double +// SCT_BarrelParameters::bearingPhiPos() const +// { +// if (m_rdb->brlServices()->isFieldNull("BEARINGPHIPOS")) { +// return 0.; +// } +// return m_rdb->brlServices()->getDouble("BEARINGPHIPOS") * Gaudi::Units::deg; +// } + +// int +// SCT_BarrelParameters::bearingNRepeat() const +// { +// if (m_rdb->brlServices()->isFieldNull("BEARINGNREPEAT")) { +// return 0; +// } +// return m_rdb->brlServices()->getInt("BEARINGNREPEAT"); +// } + +// std::string +// SCT_BarrelParameters::bearingMaterial() const +// { +// if (m_rdb->brlServices()->isFieldNull("BEARINGMATERIAL")) { +// return " "; +// } +// return m_rdb->brlServices()->getString("BEARINGMATERIAL"); +// } + +// // +// // Barrel FSI and FSI flange +// // +// bool +// SCT_BarrelParameters::includeFSI() const +// { +// if (m_rdb->brlFSISize() > 0) {return true;} +// return false; +// } + +// double +// SCT_BarrelParameters::fsiFlangeInnerRadius() const +// { +// return m_rdb->brlFSI()->getDouble("FLANGEINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiFlangeOuterRadius() const +// { +// return m_rdb->brlFSI()->getDouble("FLANGEOUTERRADIUS") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::fsiFlangeMaterial() const +// { +// return m_rdb->brlFSI()->getString("FLANGEMATERIAL"); +// } + +// double +// SCT_BarrelParameters::fsiFibreMaskDeltaR() const +// { +// return m_rdb->brlFSI()->getDouble("FIBREMASKDELTAR") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::fsiFibreMaskMaterial() const +// { +// return m_rdb->brlFSI()->getString("FIBREMASKMATERIAL"); +// } + +// double +// SCT_BarrelParameters::fsiEndJewelRadialWidth() const +// { +// return m_rdb->brlFSI()->getDouble("ENDJEWELRADIALWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiEndJewelRPhiWidth() const +// { +// return m_rdb->brlFSI()->getDouble("ENDJEWELRPHIWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiEndJewelLength() const +// { +// return m_rdb->brlFSI()->getDouble("ENDJEWELLENGTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::fsiEndJewelMaterial() const +// { +// return m_rdb->brlFSI()->getString("ENDJEWELMATERIAL"); +// } + +// int +// SCT_BarrelParameters::fsiEndJewelNRepeat(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getInt("ENDJEWELNREPEAT"); +// } + +// double +// SCT_BarrelParameters::fsiEndJewelPhi(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getDouble("ENDJEWELPHI") * Gaudi::Units::degree; +// } + +// double +// SCT_BarrelParameters::fsiEndJewelZ(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getDouble("ENDJEWELZ") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiScorpionRadialWidth() const +// { +// return m_rdb->brlFSI()->getDouble("SCORPIONRADIALWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiScorpionRPhiWidth() const +// { +// return m_rdb->brlFSI()->getDouble("SCORPIONRPHIWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::fsiScorpionLength() const +// { +// return m_rdb->brlFSI()->getDouble("SCORPIONLENGTH") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::fsiScorpionMaterial() const +// { +// return m_rdb->brlFSI()->getString("SCORPIONMATERIAL"); +// } + +// int +// SCT_BarrelParameters::fsiScorpionNRepeat(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getInt("SCORPIONNREPEAT"); +// } + +// double +// SCT_BarrelParameters::fsiScorpionPhi(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getDouble("SCORPIONPHI") * Gaudi::Units::degree; +// } + +// double +// SCT_BarrelParameters::fsiScorpionZ(int iLayer) const +// { +// return m_rdb->brlFSILocation(iLayer)->getDouble("SCORPIONZ") * Gaudi::Units::mm; +// } + + +// // +// // Barrel Cooling Spider +// // +// double +// SCT_BarrelParameters::spiderDeltaZ() const +// { +// return m_rdb->brlServices()->getDouble("SPIDERDELTAZ") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::spiderInnerRadius() const +// { +// return m_rdb->brlServices()->getDouble("SPIDERINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::spiderOuterRadius() const +// { +// return m_rdb->brlServices()->getDouble("SPIDEROUTERRADIUS") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::spiderMaterial() const +// { +// return m_rdb->brlServices()->getString("SPIDERMATERIAL"); +// } + +// // +// // Barrel Thermal Shield +// // +// double +// SCT_BarrelParameters::thermalShieldInnerRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("INNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldOuterRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("OUTERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldEndZMax() const +// { +// return m_rdb->brlThermalShield()->getDouble("ENDZMAX") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldCylTotalThickness() const +// { +// return m_rdb->brlThermalShield()->getDouble("CYLTOTALTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldCylInnerWallThickness() const +// { +// return m_rdb->brlThermalShield()->getDouble("CYLINNERWALLTHICK") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldCylOuterWallThickness() const +// { +// return m_rdb->brlThermalShield()->getDouble("CYLOUTERWALLTHICK") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldSpacerZWidth() const +// { +// return m_rdb->brlThermalShield()->getDouble("SPACERZWIDTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldFirstSpacerZMin() const +// { +// return m_rdb->brlThermalShield()->getDouble("FIRSTSPACERZMIN") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldEndCapCylThickness() const +// { +// return m_rdb->brlThermalShield()->getDouble("ENDCAPCYLTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldEndCapThickness() const +// { +// return m_rdb->brlThermalShield()->getDouble("ENDCAPTHICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldBulkheadInnerRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("BULKHEADINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldBulkheadOuterRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("BULKHEADOUTERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldEndPanelInnerRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("ENDPANELINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::thermalShieldEndPanelOuterRadius() const +// { +// return m_rdb->brlThermalShield()->getDouble("ENDPANELOUTERRADIUS") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::thermalShieldMaterialSpacer() const +// { +// return m_rdb->brlThermalShield()->getString("MATERIALSPACER"); +// } + +// std::string +// SCT_BarrelParameters::thermalShieldMaterialCyl() const +// { +// return m_rdb->brlThermalShield()->getString("MATERIALCYL"); +// } + +// std::string +// SCT_BarrelParameters::thermalShieldMaterialOuterSect() const +// { +// return m_rdb->brlThermalShield()->getString("MATERIALOUTERSECT"); +// } + +// std::string +// SCT_BarrelParameters::thermalShieldMaterialInnerSect() const +// { +// return m_rdb->brlThermalShield()->getString("MATERIALINNERSECT"); +// } + +// // +// // Barrel EMI Shield +// // +// double +// SCT_BarrelParameters::emiShieldInnerRadius() const +// { +// return m_rdb->brlServices()->getDouble("EMIINNERRADIUS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::emiShieldDeltaR() const +// { +// return m_rdb->brlServices()->getDouble("EMIDELTAR") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::emiShieldZMax() const +// { +// return m_rdb->brlServices()->getDouble("EMIZMAX") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::emiShieldMaterial() const +// { +// return m_rdb->brlServices()->getString("EMIMATERIAL"); +// } + +// double +// SCT_BarrelParameters::emiJointDeltaR() const +// { +// return m_rdb->brlServices()->getDouble("EMIJOINTDELTAR") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::emiJointRPhi() const +// { +// return m_rdb->brlServices()->getDouble("EMIJOINTRPHI") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::emiJointMaterial() const +// { +// return m_rdb->brlServices()->getString("EMIJOINTMATERIAL"); +// } + + + +// // +// // Attachment of pixel to SCT. +// // +// double +// SCT_BarrelParameters::pixelAttachmentInnerRadius() const +// { +// return m_rdb->brlServices()->getDouble("PIXELATTACHINNERRAD") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::pixelAttachmentOuterRadius() const +// { +// return m_rdb->brlServices()->getDouble("PIXELATTACHOUTERRAD") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::pixelAttachmentZMin() const +// { +// return m_rdb->brlServices()->getDouble("PIXELATTACHZMIN") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::pixelAttachmentDeltaZ() const +// { +// return m_rdb->brlServices()->getDouble("PIXELATTACHDELTAZ") * Gaudi::Units::mm; +// } + +// std::string +// SCT_BarrelParameters::pixelAttachmentMaterial() const +// { +// return m_rdb->brlServices()->getString("PIXELATTACHMATERIAL"); +// } + +// +// Barrel General +// +int +VetoNuStationParameters::numPlates() const +{ + return m_rdb->stationGeneral()->getInt("NUMPLATES"); +} + +double +VetoNuStationParameters::platePitch() const +{ + return m_rdb->stationGeneral()->getDouble("PLATEPITCH"); +} + +// double +// VetoNuStationParameters::stationWidth() const +// { +// return m_rdb->stationGeneral()->getDouble("WIDTH") * Gaudi::Units::mm; +// } + +// double +// VetoNuStationParameters::stationLength() const +// { +// return m_rdb->stationGeneral()->getDouble("LENGTH") * Gaudi::Units::mm; +// } + +// double +// VetoNuStationParameters::stationThickness() const +// { +// return m_rdb->stationGeneral()->getDouble("THICKNESS") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::cylinderLength() const +// { +// return m_rdb->brlGeneral()->getDouble("CYLINDERLENGTH") * Gaudi::Units::mm; +// } + +// double +// SCT_BarrelParameters::activeLength() const +// { +// return m_rdb->brlGeneral()->getDouble("ACTIVELENGTH") * Gaudi::Units::mm; +// } + +// bool +// SCT_BarrelParameters::isOldGeometry() const +// { +// if (m_rdb->brlGeneral()->isFieldNull("CYLINDERLENGTH")) {return true;} +// return false; +// } + diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.h b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..843b6095e29ff703ab1605e1c8eb66cdd114f635 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/VetoNuStationParameters.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef VetoNuGeoModel_VetoNuStationParameters_H +#define VetoNuGeoModel_VetoNuStationParameters_H + +#include <string> + +class VetoNuDataBase; + +class VetoNuStationParameters { + +public: + + // Constructor + VetoNuStationParameters(VetoNuDataBase* rdb); + + + // General + int numPlates() const; + double platePitch() const; + + private: + VetoNuDataBase * m_rdb; + +}; + + +#endif // VetoNuGeoModel_VetoNuStationParameters_H diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/src/components/VetoNuGeoModel_entries.cxx b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/components/VetoNuGeoModel_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cc2cd2581e8954fa96943ded066d9e6f5cb15544 --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/src/components/VetoNuGeoModel_entries.cxx @@ -0,0 +1,3 @@ +#include "VetoNuGeoModel/VetoNuDetectorTool.h" + +DECLARE_COMPONENT( VetoNuDetectorTool ) \ No newline at end of file diff --git a/Scintillator/ScintDetDescr/VetoNuGeoModel/test/VetoNuGMConfig_test.py b/Scintillator/ScintDetDescr/VetoNuGeoModel/test/VetoNuGMConfig_test.py new file mode 100644 index 0000000000000000000000000000000000000000..8a8bca5989485cfa7c046e244e966d8d00c0d85f --- /dev/null +++ b/Scintillator/ScintDetDescr/VetoNuGeoModel/test/VetoNuGMConfig_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Run tests on VetoNuGeoModel configuration + +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +if __name__ == "__main__": + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior=1 + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + from AthenaConfiguration.TestDefaults import defaultTestFiles + + ConfigFlags.Input.Files = defaultTestFiles.HITS + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.Align.Dynamic = False + ConfigFlags.lock() + + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + from VetoNuGeoModel.VetoNuGeoModelConfig import VetoNuGeometryCfg + acc = VetoNuGeometryCfg(ConfigFlags) + f=open('VetoNuGeometryCfg.pkl','wb') + acc.store(f) + f.close() diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx index 18719ef20c15237f1febd9b268e819ce2b88f5e5..0b99ec46b38a725159e9ae7f914d7df3b99b2178 100644 --- a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx +++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/ScintIdCnv_entries.cxx @@ -3,6 +3,7 @@ // #include "SiliconIDDetDescrCnv.h" // #include "TRT_IDDetDescrCnv.h" #include "VetoIDDetDescrCnv.h" +#include "VetoNuIDDetDescrCnv.h" #include "TriggerIDDetDescrCnv.h" #include "PreshowerIDDetDescrCnv.h" @@ -11,5 +12,6 @@ // DECLARE_CONVERTER(SiliconIDDetDescrCnv) // DECLARE_CONVERTER(TRT_IDDetDescrCnv) DECLARE_CONVERTER(VetoIDDetDescrCnv) +DECLARE_CONVERTER(VetoNuIDDetDescrCnv) DECLARE_CONVERTER(TriggerIDDetDescrCnv) DECLARE_CONVERTER(PreshowerIDDetDescrCnv) diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.cxx b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.cxx new file mode 100644 index 0000000000000000000000000000000000000000..82d3ab337ed23e70f62dd97bd5be675c656d7244 --- /dev/null +++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.cxx @@ -0,0 +1,239 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + Scint DetDescrCnv package + ----------------------------------------- + ***************************************************************************/ + +//<<<<<< INCLUDES >>>>>> + +#include "VetoNuIDDetDescrCnv.h" + +#include "DetDescrCnvSvc/DetDescrConverter.h" +#include "DetDescrCnvSvc/DetDescrAddress.h" +#include "GaudiKernel/MsgStream.h" +#include "StoreGate/StoreGateSvc.h" + +#include "IdDictDetDescr/IdDictManager.h" +#include "ScintIdentifier/VetoNuID.h" + + +//<<<<<< PRIVATE DEFINES >>>>>> +//<<<<<< PRIVATE CONSTANTS >>>>>> +//<<<<<< PRIVATE TYPES >>>>>> +//<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>> +//<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>> +//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> +//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> +//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>> +//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>> + +//-------------------------------------------------------------------- + +long int +VetoNuIDDetDescrCnv::repSvcType() const +{ + return (storageType()); +} + +//-------------------------------------------------------------------- + +StatusCode +VetoNuIDDetDescrCnv::initialize() +{ + // First call parent init + StatusCode sc = DetDescrConverter::initialize(); + MsgStream log(msgSvc(), "VetoNuIDDetDescrCnv"); + log << MSG::DEBUG << "in initialize" << endmsg; + + if (sc.isFailure()) { + log << MSG::ERROR << "DetDescrConverter::initialize failed" << endmsg; + return sc; + } + + // The following is an attempt to "bootstrap" the loading of a + // proxy for VetoNuID into the detector store. However, + // VetoNuIDDetDescrCnv::initialize is NOT called by the conversion + // service. So for the moment, this cannot be use. Instead the + // DetDescrCnvSvc must do the bootstrap from a parameter list. + + +// // Add Scint_DetDescrManager proxy as entry point to the detector store +// // - this is ONLY needed for the manager of each system +// sc = addToDetStore(classID(), "VetoNuID"); +// if (sc.isFailure()) { +// log << MSG::FATAL << "Unable to add proxy for VetoNuID to the Detector Store!" << endmsg; +// return StatusCode::FAILURE; +// } else {} + + return StatusCode::SUCCESS; +} + +//-------------------------------------------------------------------- + +StatusCode +VetoNuIDDetDescrCnv::finalize() +{ + MsgStream log(msgSvc(), "VetoNuIDDetDescrCnv"); + log << MSG::DEBUG << "in finalize" << endmsg; + + return StatusCode::SUCCESS; +} + +//-------------------------------------------------------------------- + +StatusCode +VetoNuIDDetDescrCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj) +{ + //StatusCode sc = StatusCode::SUCCESS; + MsgStream log(msgSvc(), "VetoNuIDDetDescrCnv"); + log << MSG::INFO << "in createObj: creating a VetoNuID helper object in the detector store" << endmsg; + + // Create a new VetoNuID + + DetDescrAddress* ddAddr; + ddAddr = dynamic_cast<DetDescrAddress*> (pAddr); + if(!ddAddr) { + log << MSG::FATAL << "Could not cast to DetDescrAddress." << endmsg; + return StatusCode::FAILURE; + } + + // Get the StoreGate key of this container. + std::string helperKey = *( ddAddr->par() ); + if ("" == helperKey) { + log << MSG::DEBUG << "No Helper key " << endmsg; + } + else { + log << MSG::DEBUG << "Helper key is " << helperKey << endmsg; + } + + + // get DetectorStore service + StoreGateSvc * detStore; + StatusCode status = serviceLocator()->service("DetectorStore", detStore); + if (status.isFailure()) { + log << MSG::FATAL << "DetectorStore service not found !" << endmsg; + return StatusCode::FAILURE; + } else {} + + // Get the dictionary manager from the detector store + const DataHandle<IdDictManager> idDictMgr; + status = detStore->retrieve(idDictMgr, "IdDict"); + if (status.isFailure()) { + log << MSG::FATAL << "Could not get IdDictManager !" << endmsg; + return StatusCode::FAILURE; + } + else { + log << MSG::DEBUG << " Found the IdDictManager. " << endmsg; + } + + // Only create new helper if it is the first pass or if there is a + // change in the the file or tag + bool initHelper = false; + + const IdDictMgr* mgr = idDictMgr->manager(); + + // Internal Scint id tag + std::string scintIDTag = mgr->tag(); + + // DoChecks flag + bool doChecks = mgr->do_checks(); + + IdDictDictionary* dict = mgr->find_dictionary("Scintillator"); + if (!dict) { + log << MSG::ERROR + << "unable to find idDict for Scintillator" + << endmsg; + return StatusCode::FAILURE; + } + + // File to be read for Scint ids + std::string scintIDFileName = dict->file_name(); + + // Tag of RDB record for Scint ids + std::string scintIdDictTag = dict->dict_tag(); + + + if (m_vetonuId) { + + // VetoNu id helper already exists - second pass. Check for a + // change + if (scintIDTag != m_scintIDTag) { + // Internal Scint id tag + initHelper = true; + log << MSG::DEBUG << " Changed internal Scint id tag: " + << scintIDTag << endmsg; + } + if (scintIDFileName != m_scintIDFileName) { + // File to be read for Scint ids + initHelper = true; + log << MSG::DEBUG << " Changed ScintFileName:" + << scintIDFileName << endmsg; + } + if (scintIdDictTag != m_scintIdDictTag) { + // Tag of RDB record for Scint ids + initHelper = true; + log << MSG::DEBUG << " Changed ScintIdDictTag: " + << scintIdDictTag + << endmsg; + } + if (doChecks != m_doChecks) { + // DoChecks flag + initHelper = true; + log << MSG::DEBUG << " Changed doChecks flag: " + << doChecks + << endmsg; + } + } + else { + // create the helper + m_vetonuId = new VetoNuID; + initHelper = true; + // add in message service for printout + m_vetonuId->setMessageSvc(msgSvc()); + } + + if (initHelper) { + if (idDictMgr->initializeHelper(*m_vetonuId)) { + log << MSG::ERROR << "Unable to initialize VetoNuID" << endmsg; + return StatusCode::FAILURE; + } + // Save state: + m_scintIDTag = scintIDTag; + m_scintIDFileName = scintIDFileName; + m_scintIdDictTag = scintIdDictTag; + m_doChecks = doChecks; + } + + // Pass a pointer to the container to the Persistency service by reference. + pObj = StoreGateSvc::asStorable(m_vetonuId); + + return StatusCode::SUCCESS; + +} + +//-------------------------------------------------------------------- + +long +VetoNuIDDetDescrCnv::storageType() +{ + return DetDescr_StorageType; +} + +//-------------------------------------------------------------------- +const CLID& +VetoNuIDDetDescrCnv::classID() { + return ClassID_traits<VetoNuID>::ID(); +} + +//-------------------------------------------------------------------- +VetoNuIDDetDescrCnv::VetoNuIDDetDescrCnv(ISvcLocator* svcloc) + : + DetDescrConverter(ClassID_traits<VetoNuID>::ID(), svcloc), + m_vetonuId(0), + m_doChecks(false) + +{} + diff --git a/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.h b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.h new file mode 100644 index 0000000000000000000000000000000000000000..784d518879aec982ebcb3a96cb73c7e8aded80c8 --- /dev/null +++ b/Scintillator/ScintDetDescrCnv/ScintIdCnv/src/VetoNuIDDetDescrCnv.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/*************************************************************************** + Scint DetDescrCnv package + ----------------------------------------- + ***************************************************************************/ + +#ifndef SCINTIDCNV_VETONUIDDETDESCRCNV_H +#define SCINTIDCNV_VETONUIDDETDESCRCNV_H + +//<<<<<< INCLUDES >>>>>> + +#include "DetDescrCnvSvc/DetDescrConverter.h" + +//<<<<<< PUBLIC DEFINES >>>>>> +//<<<<<< PUBLIC CONSTANTS >>>>>> +//<<<<<< PUBLIC TYPES >>>>>> + +class VetoNuID; + +//<<<<<< PUBLIC VARIABLES >>>>>> +//<<<<<< PUBLIC FUNCTIONS >>>>>> +//<<<<<< CLASS DECLARATIONS >>>>>> + + +/** + ** This class is a converter for the VetoNuID an IdHelper which is + ** stored in the detector store. This class derives from + ** DetDescrConverter which is a converter of the DetDescrCnvSvc. + ** + **/ + +class VetoNuIDDetDescrCnv: public DetDescrConverter { + +public: + virtual long int repSvcType() const; + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj); + + // Storage type and class ID (used by CnvFactory) + static long storageType(); + static const CLID& classID(); + + VetoNuIDDetDescrCnv(ISvcLocator* svcloc); + +private: + /// The helper - only will create it once + VetoNuID* m_vetonuId; + + /// File to be read for Scint ids + std::string m_scintIDFileName; + + /// Tag of RDB record for Scint ids + std::string m_scintIdDictTag; + + /// Internal Scint id tag + std::string m_scintIDTag; + + /// Whether or not + bool m_doChecks; + +}; + + +//<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> +//<<<<<< INLINE MEMBER FUNCTIONS >>>>>> + +#endif // SCINTIDCNV_VETONUIDDETDESCRCNV_H diff --git a/Scintillator/ScintDigiAlgs/CMakeLists.txt b/Scintillator/ScintDigiAlgs/CMakeLists.txt index 43695c5f90d96053a8b44fa3ac41c0f4c159ad99..5c1874e2502241f919efb21ade0e7c26de7369ca 100644 --- a/Scintillator/ScintDigiAlgs/CMakeLists.txt +++ b/Scintillator/ScintDigiAlgs/CMakeLists.txt @@ -9,7 +9,9 @@ atlas_subdir( ScintDigiAlgs ) atlas_add_component( ScintDigiAlgs src/*.cxx src/*.h src/components/*.cxx - LINK_LIBRARIES AthenaBaseComps Identifier StoreGateLib WaveRawEvent ScintSimEvent WaveDigiToolsLib) + LINK_LIBRARIES AthenaBaseComps Identifier ScintIdentifier + WaveformConditionsToolsLib StoreGateLib WaveRawEvent + ScintSimEvent WaveDigiToolsLib) atlas_install_python_modules( python/*.py ) diff --git a/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py b/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py index 7f2ba8530575eeb6a6c9b51779c482f84bdfc648..ddf3074618aff121e704b2214309a14952436837 100644 --- a/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py +++ b/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py @@ -5,6 +5,8 @@ from AthenaConfiguration.ComponentFactory import CompFactory from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from WaveformConditionsTools.WaveformCableMappingConfig import WaveformCableMappingCfg + # Crystallball parameter dictionary used in simulated digitized wave reconstruction. # Crystalball function Parameters estimated from Deion's slides uploaded at # https://indico.cern.ch/event/1099652/contributions/4626975/attachments/2352595/4013927/Faser-Physics-run3933-plots.pdf (20/01/2022) @@ -13,8 +15,17 @@ dict_CB_param = {} dict_CB_param["Trigger"]=dict(CB_alpha=-0.38, CB_n=25, CB_mean=815, CB_sigma=7.7, CB_norm = 500 ) dict_CB_param["Timing"]=dict(CB_alpha=-0.32, CB_n=65, CB_mean=846, CB_sigma=5.3, CB_norm = 500) # copy from Preshower; Timing was not in TestBeam dict_CB_param["Veto"]=dict(CB_alpha=-0.38, CB_n=25, CB_mean=815, CB_sigma=7.7, CB_norm = 1000) # copy from Trigger; Veto was not in TestBeam, but in sim "Veto" is the TestBeam Trigger component +dict_CB_param["VetoNu"]=dict(CB_alpha=-0.38, CB_n=25, CB_mean=815, CB_sigma=7.7, CB_norm = 1000) # copy from Trigger; Veto was not in TestBeam, but in sim "Veto" is the TestBeam Trigger component dict_CB_param["Preshower"]=dict(CB_alpha=-0.32, CB_n=65, CB_mean=846, CB_sigma=5.3, CB_norm = 500) +dict_baseline_params = { + "Trigger" : {"mean" : 15000, "rms" : 3}, + "Timing" : {"mean" : 15000, "rms" : 3}, + "Veto" : {"mean" : 15000, "rms" : 3}, + "VetoNu" : {"mean" : 15000, "rms" : 3}, + "Preshower" : {"mean" : 15000, "rms" : 3}, + } + # One stop shopping for normal FASER data def ScintWaveformDigitizationCfg(flags): """ Return all algorithms and tools for Waveform digitization """ @@ -26,8 +37,10 @@ def ScintWaveformDigitizationCfg(flags): if "TB" not in flags.GeoModel.FaserVersion: acc.merge(ScintWaveformDigiCfg(flags, "TimingWaveformDigiAlg", "Trigger")) acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto")) + acc.merge(ScintWaveformDigiCfg(flags, "VetoNuWaveformDigiAlg", "VetoNu")) acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower")) acc.merge(ScintWaveformDigitizationOutputCfg(flags)) + acc.merge(WaveformCableMappingCfg(flags)) return acc # Return configured digitization algorithm from SIM hits @@ -48,8 +61,8 @@ def ScintWaveformDigiCfg(flags, name="ScintWaveformDigiAlg", source="", **kwargs digiAlg.CB_sigma = dict_CB_param[source]["CB_sigma"] digiAlg.CB_norm = dict_CB_param[source]["CB_norm"] - digiAlg.base_mean = 15000 - digiAlg.base_rms = 3 + digiAlg.base_mean = dict_baseline_params[source]["mean"] + digiAlg.base_rms = dict_baseline_params[source]["rms"] kwargs.setdefault("WaveformDigitisationTool", tool) @@ -65,6 +78,7 @@ def ScintWaveformDigitizationOutputCfg(flags, **kwargs): ] acc.merge(OutputStreamCfg(flags, "RDO")) ostream = acc.getEventAlgo("OutputStreamRDO") - ostream.TakeItemsFromInput = True # Copies all data from input file to output + # ostream.TakeItemsFromInput = True # Copies all data from input file to output + # ostream.TakeItemsFromInput = False ostream.ItemList += ItemList return acc diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx index 91cffd93552d222b90c200cf50fa7842e2b7177a..7eb12286567c42591314592ece065136a754d43d 100644 --- a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx +++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx @@ -1,11 +1,8 @@ - #include "ScintWaveformDigiAlg.h" -#include "Identifier/Identifier.h" +#include "ScintSimEvent/ScintHitIdHelper.h" -#include <vector> #include <map> -#include <utility> ScintWaveformDigiAlg::ScintWaveformDigiAlg(const std::string& name, @@ -20,7 +17,7 @@ ScintWaveformDigiAlg::initialize() { // Initalize tools ATH_CHECK( m_digiTool.retrieve() ); - + ATH_CHECK( m_mappingTool.retrieve() ); // Set key to read waveform from ATH_CHECK( m_scintHitContainerKey.initialize() ); @@ -28,18 +25,23 @@ ScintWaveformDigiAlg::initialize() { // Set key to write container ATH_CHECK( m_waveformContainerKey.initialize() ); - // Will eventually depend on the type of detector - // TODO: Vary time at which centre it? - // TODO: Better parameters - + // Set up helpers + ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID")); + ATH_CHECK(detStore()->retrieve(m_vetoNuID, "VetoNuID")); + ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID")); + ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID")); - + // Create CB time kernel and pre-evaluate for number of samples m_kernel = new TF1("PDF", "[4] * ROOT::Math::crystalball_pdf(x, [0],[1],[2],[3])", 0, 1200); m_kernel->SetParameter(0, m_CB_alpha); m_kernel->SetParameter(1, m_CB_n); m_kernel->SetParameter(2, m_CB_sigma); m_kernel->SetParameter(3, m_CB_mean); m_kernel->SetParameter(4, m_CB_norm); + + // Pre-evaluate time kernel for each bin + m_timekernel = m_digiTool->evaluate_timekernel(m_kernel); + return StatusCode::SUCCESS; } @@ -55,11 +57,9 @@ ScintWaveformDigiAlg::finalize() { StatusCode ScintWaveformDigiAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("Executing"); + ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() << " Event: " << ctx.eventID().event_number()); - ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() - << " Event: " << ctx.eventID().event_number()); - - // Find the input HIT collection + // Find the input HITS collection SG::ReadHandle<ScintHitCollection> scintHitHandle(m_scintHitContainerKey, ctx); ATH_CHECK( scintHitHandle.isValid() ); @@ -70,16 +70,107 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const { ATH_CHECK( waveformContainerHandle.record( std::make_unique<RawWaveformContainer>()) ); ATH_MSG_DEBUG("WaveformsContainer '" << waveformContainerHandle.name() << "' initialized"); - + if (scintHitHandle->size() == 0) { ATH_MSG_DEBUG("ScintHitCollection found with zero length!"); return StatusCode::SUCCESS; } + + // Create structure to store pulse for each channel + std::map<Identifier, std::vector<uint16_t>> waveforms; + + auto first = *scintHitHandle->begin(); + if (first.isVeto()) { + waveforms = m_digiTool->create_waveform_map(m_vetoID); + } else if (first.isVetoNu()) { + waveforms = m_digiTool->create_waveform_map(m_vetoNuID); + } else if (first.isTrigger()) { + waveforms = m_digiTool->create_waveform_map(m_triggerID); + } else if (first.isPreshower()) { + waveforms = m_digiTool->create_waveform_map(m_preshowerID); + } + + // Loop over time samples + // Should really do sums first, as repeating these in the loop is a waste + for (const auto& tk : m_timekernel) { + std::map<Identifier, float> counts; + + // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel) + Identifier id; + for (const auto& hit : *scintHitHandle) { + + // Special handling for trigger scintillator + if (first.isTrigger()) { + // Hits are created per plate + // Need to split between 2 PMTs + + // Identifier from hit is plate ID + Identifier plate_id = m_triggerID->plate_id(hit.getIdentifier()); + + // Need to do something better here, but for now just fill both + id = m_triggerID->pmt_id(plate_id, 0); // ID for PMT 0 + counts[id] += tk * hit.energyLoss(); + id = m_triggerID->pmt_id(plate_id, 1); // ID for PMT 1 + counts[id] += tk * hit.energyLoss(); + + } else { + // All others have only 1 PMT + // Use detector id (not hit id) throughout + id = hit.getIdentifier(); + counts[id] += tk * hit.energyLoss(); + } + } + + // Subtract count from basleine and add result to correct waveform vector + for (const auto& c : counts) { + + unsigned int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms); + int value = baseline - c.second; + + if (value < 0) { + ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first); + value = 0; // Protect against scaling signal above baseline + } + + // Convert hit id to Identifier and store + id = c.first; + waveforms[id].push_back(value); + } + } - // Digitise the hits - CHECK( m_digiTool->digitise<ScintHitCollection>(scintHitHandle.ptr(), - waveformContainerHandle.ptr(), m_kernel, - std::pair<float, float>(m_base_mean, m_base_rms)) ); + // This is a bit of a hack to make sure all waveforms have + // at least baseline entries. Should really add this to the + // logic above + for (const auto& w : waveforms) { + if (w.second.size() > 0) continue; + + // Waveform was empty, fill with baseline + int channel = m_mappingTool->getChannelMapping(w.first); + ATH_MSG_DEBUG("Writing baseline into empty waveform in channel "<< channel); + int i = m_digiTool->nsamples(); + while(i--) { // Use while to avoid unused variable warning with for + int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms); + waveforms[w.first].push_back(baseline); + } + } + + // Loop over wavefrom vectors to make and store raw waveform + unsigned int nsamples = m_digiTool->nsamples(); + for (const auto& w : waveforms) { + RawWaveform* wfm = new RawWaveform(); + wfm->setWaveform(0, w.second); + wfm->setIdentifier(w.first); + wfm->setSamples(nsamples); + // Only save this waveform if channel mapping is valid + // This will avoid making a waveform for the missing veto counter + int channel = m_mappingTool->getChannelMapping(w.first); + if (channel < 0) { + ATH_MSG_DEBUG("Skipping waveform with unknown channel!"); + continue; + } + wfm->setChannel(channel); + waveformContainerHandle->push_back(wfm); + } ATH_MSG_DEBUG("WaveformsHitContainer " << waveformContainerHandle.name() << "' filled with "<< waveformContainerHandle->size() <<" items"); diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h index 9bf7843a1867eeffa4587a39875913ea0685d773..528325621b279bdc3f570c6e5ade93fe549b6c12 100644 --- a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h +++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h @@ -10,6 +10,7 @@ // Tool classes #include "WaveDigiTools/IWaveformDigitisationTool.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" // Handles #include "StoreGate/ReadHandleKey.h" @@ -19,12 +20,22 @@ #include "GaudiKernel/ServiceHandle.h" #include "GaudiKernel/ToolHandle.h" +//Helpers +#include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintIdentifier/TriggerID.h" +#include "ScintIdentifier/PreshowerID.h" +#include "ScintSimEvent/ScintHitIdHelper.h" +#include "Identifier/Identifier.h" + + // ROOT #include "TF1.h" // STL #include <string> +#include <vector> class ScintWaveformDigiAlg : public AthReentrantAlgorithm { @@ -50,6 +61,10 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm { ScintWaveformDigiAlg &operator=(const ScintWaveformDigiAlg&) = delete; //@} + /// + + /** @name Steerable pameters for crystal ball and baseline **/ + //@{ Gaudi::Property<double> m_CB_alpha {this, "CB_alpha", 0, "Alpha of the crystal ball function"}; Gaudi::Property<double> m_CB_n {this, "CB_n", 0, "n of the crystal ball function"}; Gaudi::Property<double> m_CB_mean {this, "CB_mean", 0, "Mean of the crystal ball function"}; @@ -58,10 +73,21 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm { Gaudi::Property<double> m_base_mean {this, "base_mean", 0, "Mean of the baseline"}; Gaudi::Property<double> m_base_rms {this, "base_rms", 0, "RMS of the baseline"}; + //@} - /// Kernel PDF - TF1* m_kernel; + /** Kernel PDF and evaluated values **/ + //@{ + TF1* m_kernel; + std::vector<float> m_timekernel; + //@} + + + /// Detector ID helpers + const VetoID* m_vetoID{nullptr}; + const VetoNuID* m_vetoNuID{nullptr}; + const TriggerID* m_triggerID{nullptr}; + const PreshowerID* m_preshowerID{nullptr}; /** * @name Digitisation tool @@ -69,6 +95,11 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm { ToolHandle<IWaveformDigitisationTool> m_digiTool {this, "WaveformDigitisationTool", "WaveformDigitisationTool"}; + /** + * @name Mapping tool + */ + ToolHandle<IWaveformCableMappingTool> m_mappingTool + {this, "WaveformCableMappingTool", "WaveformCableMappingTool"}; /** * @name Input HITS using SG::ReadHandleKey @@ -91,4 +122,5 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm { }; + #endif // SCINTDIGIALGS_SCINTDIGIALG_H diff --git a/Scintillator/ScintG4/VetoNuG4_SD/CMakeLists.txt b/Scintillator/ScintG4/VetoNuG4_SD/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb9aab190b1ea05e06536d8f0477d6909a0f8499 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/CMakeLists.txt @@ -0,0 +1,22 @@ +################################################################################ +# Package: VetoNuG4_SD +################################################################################ + +# Declare the package name: +atlas_subdir( VetoNuG4_SD ) + +# External dependencies: +find_package( CLHEP ) +find_package( Geant4 ) +find_package( XercesC ) + +# Component(s) in the package: +atlas_add_component( VetoNuG4_SD + src/*.cxx + src/components/*.cxx + INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} + LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} StoreGateLib SGtests GaudiKernel ScintSimEvent G4AtlasToolsLib FaserMCTruth ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) + diff --git a/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfig.py b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..053b12e58099026922369886fb8f4f22575733c2 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfig.py @@ -0,0 +1,22 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from ISF_Algorithms.collection_merger_helpersNew import CollectionMergerCfg + +VetoNuSensorSDTool=CompFactory.VetoNuSensorSDTool + +def getVetoNuSensorSD(ConfigFlags, name="VetoNuSensorSD", **kwargs): + + result = ComponentAccumulator() + bare_collection_name = "VetoNuHits" + mergeable_collection_suffix = "_G4" + merger_input_property = "VetoNuHits" + + acc, hits_collection_name = CollectionMergerCfg(ConfigFlags, bare_collection_name, mergeable_collection_suffix, merger_input_property) + kwargs.setdefault("LogicalVolumeNames", ["VetoNu::Plate"]) + kwargs.setdefault("OutputCollectionNames", [hits_collection_name]) + + result.merge(acc) + return result, VetoNuSensorSDTool(name, **kwargs) + diff --git a/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfigDb.py b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfigDb.py new file mode 100644 index 0000000000000000000000000000000000000000..5909581e180436c7d1505a0581c5244155993ef4 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDConfigDb.py @@ -0,0 +1,5 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +from AthenaCommon.CfgGetter import addTool + +addTool("VetoNuG4_SD.VetoNuG4_SDConfig.getVetoNuSensorSD" , "VetoNuSensorSD" ) diff --git a/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDToolConfig.py b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDToolConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..8ea87d4239aa26a87481f39918dd59f8665508c8 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/python/VetoNuG4_SDToolConfig.py @@ -0,0 +1,24 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +# from ISF_Algorithms.collection_merger_helpersNew import CollectionMergerCfg + +VetoNuSensorSDTool=CompFactory.VetoNuSensorSDTool + +def VetoNuSensorSDCfg(ConfigFlags, name="VetoNuSensorSD", **kwargs): + + result = ComponentAccumulator() + bare_collection_name = "VetoNuHits" + # mergeable_collection_suffix = "_G4" + # merger_input_property = "VetoNuHits" + + # acc, hits_collection_name = CollectionMergerCfg(ConfigFlags, bare_collection_name, mergeable_collection_suffix, merger_input_property, 'SCINT') + # kwargs.setdefault("OutputCollectionNames", [hits_collection_name]) + kwargs.setdefault("LogicalVolumeNames", ["VetoNu::Plate"]) + kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) + + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.VetoNuSensorSDTool(name, **kwargs)) + return result + diff --git a/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.cxx b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.cxx new file mode 100644 index 0000000000000000000000000000000000000000..85587985abcde4886e642fdf0ef72fe832e9160f --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.cxx @@ -0,0 +1,116 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// +// VetoNu Sensitive Detector. +// The Hits are processed here. For every hit I get the position and +// an information on the sensor in which the interaction happened +// + +// class headers +#include "VetoNuSensorSD.h" + +// athena includes +#include "FaserMCTruth/FaserTrackHelper.h" + +// Geant4 includes +#include "G4Step.hh" +#include "G4ThreeVector.hh" +#include "G4SDManager.hh" +#include "G4Geantino.hh" +#include "G4ChargedGeantino.hh" + +// CLHEP transform +#include "CLHEP/Geometry/Transform3D.h" + +#include <memory> // For make unique + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +VetoNuSensorSD::VetoNuSensorSD( const std::string& name, const std::string& hitCollectionName ) + : G4VSensitiveDetector( name ) + , m_HitColl( hitCollectionName ) +{ +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void VetoNuSensorSD::Initialize(G4HCofThisEvent *) +{ + if (!m_HitColl.isValid()) m_HitColl = std::make_unique<ScintHitCollection>(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4bool VetoNuSensorSD::ProcessHits(G4Step* aStep, G4TouchableHistory* /*ROhist*/) +{ + double edep = aStep->GetTotalEnergyDeposit(); + if(edep==0.) { + if(aStep->GetTrack()->GetDefinition()!=G4Geantino::GeantinoDefinition() && + aStep->GetTrack()->GetDefinition()!=G4ChargedGeantino::ChargedGeantinoDefinition()) + return false; + } + edep *= CLHEP::MeV; + // + // Get the Touchable History: + // + const G4TouchableHistory *myTouch = dynamic_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable()); + // + // Get the hit coordinates. Start and End Point + // + G4ThreeVector coord1 = aStep->GetPreStepPoint()->GetPosition(); + G4ThreeVector coord2 = aStep->GetPostStepPoint()->GetPosition(); + // + // Calculate the local step begin and end position. + // From a G4 FAQ: + // http://geant4-hn.slac.stanford.edu:5090/HyperNews/public/get/geometry/17/1.html + // + const G4AffineTransform transformation = myTouch->GetHistory()->GetTopTransform(); + G4ThreeVector localPosition1 = transformation.TransformPoint(coord1); + G4ThreeVector localPosition2 = transformation.TransformPoint(coord2); + // + // Get it into a vector in local coords and with the right units: + // + HepGeom::Point3D<double> lP1,lP2; + + // No funny business with coordinates like ATLAS... + lP1[2] = localPosition1[2]*CLHEP::mm; + lP1[1] = localPosition1[1]*CLHEP::mm; + lP1[0] = localPosition1[0]*CLHEP::mm; + + lP2[2] = localPosition2[2]*CLHEP::mm; + lP2[1] = localPosition2[1]*CLHEP::mm; + lP2[0] = localPosition2[0]*CLHEP::mm; + + // Now Navigate the history to know in what detector the step is: + // and finally set the ID of det element in which the hit is. + // + //G4int History; + // + // Get station and plate + // + int station = 0; + int plate = 0; + this->indexMethod(myTouch, station, plate); + // get the HepMcParticleLink from the TrackHelper + FaserTrackHelper trHelp(aStep->GetTrack()); + m_HitColl->Emplace(lP1, + lP2, + edep, + aStep->GetPreStepPoint()->GetGlobalTime(),//use the global time. i.e. the time from the beginning of the event + trHelp.GetParticleLink(), + 3,station,plate); + return true; +} + +void VetoNuSensorSD::indexMethod(const G4TouchableHistory *myTouch, + int &station, int &plate) { + + + plate = myTouch->GetVolume()->GetCopyNo(); + const std::string stationName = myTouch->GetVolume(1)->GetLogicalVolume()->GetName(); + station = (stationName == "VetoNu::VetoNuStationA" ? 0 : 1 ); + + return; +} diff --git a/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.h b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.h new file mode 100644 index 0000000000000000000000000000000000000000..478121ccd5a3c27a19ee200153bc290a872ff1b6 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSD.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/**************************************************************** + VetoNu Sensitive Detector class +****************************************************************/ + +#ifndef VETONUG4_SD_VETONUSENSORSD_H +#define VETONUG4_SD_VETONUSENSORSD_H + +// Base class +#include "G4VSensitiveDetector.hh" + +// For the hits +#include "ScintSimEvent/ScintHitCollection.h" +#include "StoreGate/WriteHandle.h" + +// G4 needed classes +class G4Step; +class G4TouchableHistory; + +class VetoNuSensorSD : public G4VSensitiveDetector +{ +public: + // Constructor + VetoNuSensorSD(const std::string& name, const std::string& hitCollectionName); + + // Destructor + ~VetoNuSensorSD() { /* If all goes well we do not own myHitColl here */ } + + // Deal with each G4 hit + G4bool ProcessHits(G4Step*, G4TouchableHistory*) override; + + // For setting up the hit collection + void Initialize(G4HCofThisEvent*) override final; + + /** Templated method to stuff a single hit into the sensitive detector class. This + could get rather tricky, but the idea is to allow fast simulations to use the very + same SD classes as the standard simulation. */ + template <class... Args> void AddHit(Args&&... args){ m_HitColl->Emplace( args... ); } + +private: + void indexMethod(const G4TouchableHistory *myTouch, int &station, int &plate); +protected: + // The hits collection + SG::WriteHandle<ScintHitCollection> m_HitColl; +}; + +#endif //VETONUG4_SD_VETONUSENSORSD_H diff --git a/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.cxx b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6f3a6f5a693e2fd25e42bf58121d79cc91de310f --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.cxx @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// VetoNu Sensitive Detector Tool. +// + +// class header +#include "VetoNuSensorSDTool.h" + +// package includes +#include "VetoNuSensorSD.h" + +// STL includes +#include <exception> + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +VetoNuSensorSDTool::VetoNuSensorSDTool(const std::string& type, const std::string& name, const IInterface* parent) + : SensitiveDetectorBase( type , name , parent ) +{ + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4VSensitiveDetector* VetoNuSensorSDTool::makeSD() const +{ + ATH_MSG_DEBUG( "Creating VetoNu SD: " << name() ); + return new VetoNuSensorSD(name(), m_outputCollectionNames[0]); +} + diff --git a/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.h b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.h new file mode 100644 index 0000000000000000000000000000000000000000..073a7cd07a136376d97e8b1361a9a4fc252a23d4 --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/src/VetoNuSensorSDTool.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/**************************************************************** + VetoNu Sensitive Detector Tool + ****************************************************************/ + +#ifndef VETONUG4_SD_VETONUSENSORSDTOOL_H +#define VETONUG4_SD_VETONUSENSORSDTOOL_H + +// Base class +#include "G4AtlasTools/SensitiveDetectorBase.h" + +// STL headers +#include <string> + +class G4VSensitiveDetector; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo..... + +class VetoNuSensorSDTool : public SensitiveDetectorBase +{ + public: + // Constructor + VetoNuSensorSDTool(const std::string& type, const std::string& name, const IInterface *parent); + + // Destructor + ~VetoNuSensorSDTool() { /* If all goes well we do not own myHitColl here */ } + +protected: + // Make me an SD! + G4VSensitiveDetector* makeSD() const override final; +}; + +#endif //VETOG4_SD_VETOSENSORSDTOOL_H diff --git a/Scintillator/ScintG4/VetoNuG4_SD/src/components/VetoNuG4_SD_entries.cxx b/Scintillator/ScintG4/VetoNuG4_SD/src/components/VetoNuG4_SD_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5ae057c14079dc0241808a300e4487ec3638d53d --- /dev/null +++ b/Scintillator/ScintG4/VetoNuG4_SD/src/components/VetoNuG4_SD_entries.cxx @@ -0,0 +1,3 @@ +#include "../VetoNuSensorSDTool.h" + +DECLARE_COMPONENT( VetoNuSensorSDTool ) diff --git a/Scintillator/ScintSimEvent/CMakeLists.txt b/Scintillator/ScintSimEvent/CMakeLists.txt index 27b63871df2aa95ea230c6be47454573a7c14d16..07224a272694548a6c39740e081059d7652a9d91 100644 --- a/Scintillator/ScintSimEvent/CMakeLists.txt +++ b/Scintillator/ScintSimEvent/CMakeLists.txt @@ -18,11 +18,11 @@ atlas_add_library( ScintSimEvent PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS} DEFINITIONS ${CLHEP_DEFINITIONS} LINK_LIBRARIES ${CLHEP_LIBRARIES} AthAllocators AthenaKernel CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests - PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ScintIdentifier ) + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ScintIdentifier Identifier) atlas_add_dictionary( ScintSimEventDict ScintSimEvent/ScintSimEventDict.h ScintSimEvent/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${GEANT4_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthAllocators CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests ScintIdentifier ScintSimEvent ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthAllocators CxxUtils GeneratorObjects HitManagement StoreGateLib SGtests ScintIdentifier ScintSimEvent Identifier) diff --git a/Scintillator/ScintSimEvent/ScintSimEvent/ScintHit.h b/Scintillator/ScintSimEvent/ScintSimEvent/ScintHit.h index 5a0a4d17282cc234c09b697cdee2c028480a2b96..864217ffb2628ff0873ae4823345b6f5e7e10621 100644 --- a/Scintillator/ScintSimEvent/ScintSimEvent/ScintHit.h +++ b/Scintillator/ScintSimEvent/ScintSimEvent/ScintHit.h @@ -16,6 +16,8 @@ #include "CLHEP/Geometry/Point3D.h" #include "GeneratorObjects/HepMcParticleLink.h" +class Identifier; + class ScintHit { /////////////////////////////////////////////////////////////////// @@ -80,8 +82,13 @@ public: // Const methods: /////////////////////////////////////////////////////////////////// + // This is the HitId, used in Geant. This is not the detector Identifier unsigned int identify() const; + // This is the detector readout Identifier (pmt Identifier) + // provided by ScintHitIdHelper::getIdentifier + Identifier getIdentifier() const; + // local start position of the energy deposit: HepGeom::Point3D<double> localStartPosition() const; @@ -106,6 +113,7 @@ public: bool isVeto() const; bool isTrigger() const; bool isPreshower() const; + bool isVetoNu() const; // Station int getStation() const; diff --git a/Scintillator/ScintSimEvent/ScintSimEvent/ScintHitIdHelper.h b/Scintillator/ScintSimEvent/ScintSimEvent/ScintHitIdHelper.h index 2874bac894b15684252de5a531081f338750c10c..a8740bf0f779f74f89f427b3b3458dbe275d4398 100644 --- a/Scintillator/ScintSimEvent/ScintSimEvent/ScintHitIdHelper.h +++ b/Scintillator/ScintSimEvent/ScintSimEvent/ScintHitIdHelper.h @@ -23,6 +23,16 @@ // This class is singleton and static method and variable are used. #include "CxxUtils/checker_macros.h" + +//Helpers +#include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/TriggerID.h" +#include "ScintIdentifier/PreshowerID.h" +#include "ScintIdentifier/VetoNuID.h" + +#include "Identifier/Identifier.h" + + ATLAS_NO_CHECK_FILE_THREAD_SAFETY; class ScintHitIdHelper : HitIdHelper { @@ -36,6 +46,7 @@ class ScintHitIdHelper : HitIdHelper { bool isVeto(const int& hid) const; bool isTrigger(const int& hid) const; bool isPreshower(const int& hid) const; + bool isVetoNu(const int& hid) const; // Barrel or Endcap int getStation(const int& hid) const; @@ -43,6 +54,9 @@ class ScintHitIdHelper : HitIdHelper { // Layer/Disk int getPlate(const int& hid) const; + // identifier + Identifier getIdentifier(const int& hid) const; + // // Info packing: int buildHitId(const int, const int, const int) const; @@ -54,6 +68,13 @@ class ScintHitIdHelper : HitIdHelper { // // Initialize the helper, only called by the constructor void Initialize(); + + /// Detector ID helpers + const VetoID* m_vetoID{nullptr}; + const TriggerID* m_triggerID{nullptr}; + const PreshowerID* m_preshowerID{nullptr}; + const VetoNuID* m_vetoNuID{nullptr}; + }; #endif // SCINTSIMEVENT_SCINTHITIDHELPER diff --git a/Scintillator/ScintSimEvent/src/ScintHit.cxx b/Scintillator/ScintSimEvent/src/ScintHit.cxx index 2ef1cfd9b1361c75183fd1e399ffa31e453604db..8c2201a133f75676c44c284c61061556048d9600 100644 --- a/Scintillator/ScintSimEvent/src/ScintHit.cxx +++ b/Scintillator/ScintSimEvent/src/ScintHit.cxx @@ -138,6 +138,14 @@ bool ScintHit::isPreshower() const { return ScintHitIdHelper::GetHelper()->isPreshower(m_ID); } +bool ScintHit::isVetoNu() const { + return ScintHitIdHelper::GetHelper()->isVetoNu(m_ID); +} + +Identifier ScintHit::getIdentifier() const { + return ScintHitIdHelper::GetHelper()->getIdentifier(m_ID); +} + HepGeom::Point3D<double> ScintHit::localStartPosition() const { return HepGeom::Point3D<double>((double) m_stX, (double) m_stY, (double) m_stZ); @@ -162,7 +170,9 @@ void ScintHit::print() const { } else if (isTrigger()) { std::cout << "*** Trigger Hit " << std::endl; } else if (isPreshower()) { - std::cout << "*** Preshower Hit " << std::endl; + std::cout << "*** Preshower Hit " << std::endl; + } else if (isVetoNu()) { + std::cout << "*** VetoNu Hit " << std::endl; } else { std::cout << "*** Unrecognized Scintillator Hit " << std::endl; } diff --git a/Scintillator/ScintSimEvent/src/ScintHitIdHelper.cxx b/Scintillator/ScintSimEvent/src/ScintHitIdHelper.cxx index cacdb5d720bfdc7759188481346899d48069d856..52b0faa99ce77f29913d1f94de525becce3d450f 100644 --- a/Scintillator/ScintSimEvent/src/ScintHitIdHelper.cxx +++ b/Scintillator/ScintSimEvent/src/ScintHitIdHelper.cxx @@ -6,7 +6,6 @@ #include "ScintSimEvent/ScintHitIdHelper.h" #include "StoreGate/StoreGateSvc.h" -#include "ScintIdentifier/VetoID.h" #include "G4Types.hh" #ifdef G4MULTITHREADED @@ -41,13 +40,15 @@ void ScintHitIdHelper::Initialize() { // determine whether hits were created with an SLHC dictionary // in which case eta module field is expanded. // Need to lock this thread-unsafe retrieval - const VetoID* pix; ServiceHandle<StoreGateSvc> detStore ("DetectorStore", "ScitHitIdHelper"); if (detStore.retrieve().isSuccess()) { - if (detStore->retrieve(pix, "VetoID").isFailure()) { pix = 0; } + if (detStore->retrieve(m_vetoID, "VetoID").isFailure()) { m_vetoID = 0; } + if (detStore->retrieve(m_vetoNuID, "VetoNuID").isFailure()) { m_vetoNuID = 0; } + if (detStore->retrieve(m_triggerID, "TriggerID").isFailure()) { m_triggerID = 0; } + if (detStore->retrieve(m_preshowerID, "PreshowerID").isFailure()) { m_preshowerID = 0; } } - InitializeField("VetoTriggerPreshower", 0, 2); + InitializeField("VetoTriggerPreshower", 0, 3); InitializeField("Station", -2, 2); InitializeField("Plate", 0, 4); } @@ -61,6 +62,13 @@ bool ScintHitIdHelper::isVeto(const int& hid) const else return false; } +bool ScintHitIdHelper::isVetoNu(const int& hid) const +{ + int ps = this->GetFieldValue("VetoTriggerPreshower", hid); + if ( ps == 3 ) return true; + else return false; +} + bool ScintHitIdHelper::isTrigger(const int& hid) const { int ps = this->GetFieldValue("VetoTriggerPreshower", hid); @@ -87,6 +95,22 @@ int ScintHitIdHelper::getPlate(const int& hid) const return this->GetFieldValue("Plate", hid); } + +// identifier +Identifier ScintHitIdHelper::getIdentifier(const int& hid) const +{ + if (isVeto(hid)) { + return m_vetoID->pmt_id(getStation(hid), getPlate(hid), 0); + } else if (isTrigger(hid)) { + return m_triggerID->pmt_id(getStation(hid), getPlate(hid), 0); + } else if (isPreshower(hid)) { + return m_preshowerID->pmt_id(getStation(hid), getPlate(hid), 0); + } else if (isVetoNu(hid)) { + return m_vetoNuID->pmt_id(getStation(hid), getPlate(hid), 0); + } + return Identifier(); +} + // // Info packing: int ScintHitIdHelper::buildHitId(const int veto_trigger_preshower, diff --git a/Simulation/G4Faser/G4FaserAlg/CMakeLists.txt b/Simulation/G4Faser/G4FaserAlg/CMakeLists.txt index dbd7917dbf989e1db8456a1ec6e929b7886d715d..35042d814e913677a0ddf4d643e792a75b362f2d 100644 --- a/Simulation/G4Faser/G4FaserAlg/CMakeLists.txt +++ b/Simulation/G4Faser/G4FaserAlg/CMakeLists.txt @@ -32,7 +32,7 @@ atlas_add_test( G4FaserAlgConfig_TestFaser PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) atlas_add_test( G4FaserAlgConfig_TestFaserNu - SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/test/G4FaserAlgConfigNew_Test.py GeoModel.FaserVersion="'FASERNU-02'" IOVDb.GlobalTag="'OFLCOND-FASER-02'" Output.HITSFileName='faserNu.HITS.pool.root' + SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/test/G4FaserAlgConfigNew_Test.py GeoModel.FaserVersion="'FASERNU-03'" IOVDb.GlobalTag="'OFLCOND-FASER-02'" Output.HITSFileName='faserNu.HITS.pool.root' PROPERTIES TIMEOUT 300 PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py b/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py index 82c35779d0225b979cf8d04c2f3b20bd17f5f930..e4b9721c03c8d697e101de48f9e279022051d7fb 100644 --- a/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py +++ b/Simulation/G4Faser/G4FaserAlg/python/G4FaserAlgConfigNew.py @@ -125,6 +125,9 @@ def G4FaserAlgOutputCfg(ConfigFlags): if ConfigFlags.Detector.EnableVeto: ItemList += ["ScintHitCollection#VetoHits"] + if ConfigFlags.Detector.EnableVetoNu: + ItemList += ["ScintHitCollection#VetoNuHits"] + if ConfigFlags.Detector.EnableTrigger: ItemList += ["ScintHitCollection#TriggerHits"] diff --git a/Simulation/G4Faser/G4FaserAlg/test/G4FaserAlgConfigNew_Test.py b/Simulation/G4Faser/G4FaserAlg/test/G4FaserAlgConfigNew_Test.py old mode 100644 new mode 100755 index 709797ae28bec863f565eba2aa662d8bcefc0e2e..998b40c286837a3436e6fc714f4977b355ccdd9d --- a/Simulation/G4Faser/G4FaserAlg/test/G4FaserAlgConfigNew_Test.py +++ b/Simulation/G4Faser/G4FaserAlg/test/G4FaserAlgConfigNew_Test.py @@ -12,7 +12,7 @@ if __name__ == '__main__': # Set up logging and config behaviour # from AthenaCommon.Logging import log - from AthenaCommon.Constants import DEBUG + from AthenaCommon.Constants import DEBUG, VERBOSE from AthenaCommon.Configurable import Configurable log.setLevel(DEBUG) Configurable.configurableRun3Behavior = 1 @@ -43,8 +43,12 @@ if __name__ == '__main__': ConfigFlags.Sim.ReleaseGeoModel = False ConfigFlags.Sim.IncludeParentsInG4Event = True # Controls whether BeamTruthEvent is written to output HITS file ConfigFlags.addFlag("Sim.Gun",{"Generator" : "SingleParticle"}) # Property bag for particle gun keyword:argument pairs + ConfigFlags.addFlag("Sim.Beam.xangle", 0) # Potential beam crossing angles + ConfigFlags.addFlag("Sim.Beam.yangle", 0) + ConfigFlags.addFlag("Sim.Beam.xshift", 0) # Potential beam shift + ConfigFlags.addFlag("Sim.Beam.yshift", 0) - ConfigFlags.GeoModel.FaserVersion = "FASERNU-02" # Geometry set-up + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Geometry set-up ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # To avoid autoconfig ConfigFlags.GeoModel.Align.Dynamic = False @@ -53,6 +57,23 @@ if __name__ == '__main__': # import sys ConfigFlags.fillFromArgs(sys.argv[1:]) + + doShiftLOS = (ConfigFlags.Sim.Beam.xangle or ConfigFlags.Sim.Beam.yangle or + ConfigFlags.Sim.Beam.xshift or ConfigFlags.Sim.Beam.yshift) + +# from math import atan +# from AthenaCommon.SystemOfUnits import GeV, TeV, cm, m +# from AthenaCommon.PhysicalConstants import pi +# import ParticleGun as PG +# ConfigFlags.Sim.Gun = {"Generator" : "SingleParticle", "pid" : 11, "energy" : PG.LogSampler(10*GeV, 1*TeV), "theta" : +# PG.GaussianSampler(0, atan((10*cm)/(7*m)), oneside = True), "phi" : [0, 2*pi], "mass" : 0.511, "radius" : -10*cm, "randomSeed" : 12345} + + if doShiftLOS: + pgConfig = ConfigFlags.Sim.Gun + pgConfig["McEventKey"] = "BeamTruthEvent_ATLASCoord" + ConfigFlags.Sim.Gun = pgConfig + + # # By being a little clever, we can steer the geometry setup from the command line using GeoModel.FaserVersion # @@ -63,6 +84,8 @@ if __name__ == '__main__': detectors += ['Trigger', 'Dipole'] if ConfigFlags.GeoModel.FaserVersion.count("FASERNU") > 0 : detectors += ['Emulsion'] + if ConfigFlags.GeoModel.FaserVersion.count("FASERNU-03") > 0: + detectors += ['VetoNu', 'Trench'] # # Setup detector flags # @@ -82,11 +105,34 @@ if __name__ == '__main__': # if ConfigFlags.Input.Files and ConfigFlags.Input.Files != ["_CALYPSO_GENERIC_INPUTFILE_NAME_"] : print("Input.Files = ",ConfigFlags.Input.Files) + +# +# If so, and only one file that ends in .events or .hepmc read as HepMC +# + if len(ConfigFlags.Input.Files) == 1 and (ConfigFlags.Input.Files[0].endswith(".events") or ConfigFlags.Input.Files[0].endswith(".hepmc")): + + from HEPMCReader.HepMCReaderConfig import HepMCReaderCfg + + if doShiftLOS: + cfg.merge(HepMCReaderCfg(ConfigFlags, McEventKey = "BeamTruthEvent_ATLASCoord")) + else: + cfg.merge(HepMCReaderCfg(ConfigFlags)) + + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + cfg.merge(McEventSelectorCfg(ConfigFlags)) + # -# If so, set up to read it +# Else, set up to read it as a pool.root file # - from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg - cfg.merge(PoolReadCfg(ConfigFlags)) + else: + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + cfg.merge(PoolReadCfg(ConfigFlags)) + + if doShiftLOS: + from SGComps.AddressRemappingConfig import InputOverwriteCfg + # Rename old truth collection to add ATLAS coord to can still use BeamTruthEvent for the one in FASER Coords + cfg.merge(InputOverwriteCfg("McEventCollection", "BeamTruthEvent", "McEventCollection", "BeamTruthEvent_ATLASCoord")) + # # If not, configure the particle gun as requested, or using defaults # @@ -96,18 +142,35 @@ if __name__ == '__main__': # from FaserParticleGun.FaserParticleGunConfig import FaserParticleGunCfg cfg.merge(FaserParticleGunCfg(ConfigFlags)) + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg cfg.merge(McEventSelectorCfg(ConfigFlags)) + # # Output file # from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg cfg.merge(PoolWriteCfg(ConfigFlags)) + +# +# Shift LOS +# + + if doShiftLOS: + + import McParticleEvent.Pythonizations + from GeneratorUtils.ShiftLOSConfig import ShiftLOSCfg + cfg.merge(ShiftLOSCfg(ConfigFlags, + xcross = ConfigFlags.Sim.Beam.xangle, ycross = ConfigFlags.Sim.Beam.yangle, + xshift = ConfigFlags.Sim.Beam.xshift, yshift = ConfigFlags.Sim.Beam.yshift)) + # # Add the G4FaserAlg # from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg cfg.merge(G4FaserAlgCfg(ConfigFlags)) + + #cfg.getEventAlgo("OutputStreamHITS").ItemList += ["McEventCollection#BeamTruthEvent_ATLASCoord"] # # Dump config # @@ -124,6 +187,8 @@ if __name__ == '__main__': # # Execute and finish # + #cfg.foreach_component("*").OutputLevel = VERBOSE + sc = cfg.run() b = time.time() diff --git a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py index f4bb4333d7b62b77b377663d9181e30e64b9f2f8..8f01d6b15fca1ff7a591132160aed2a2e31ff283 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py @@ -50,6 +50,9 @@ def ScintSensitiveDetectorListCfg(ConfigFlags): if ConfigFlags.Detector.EnableVeto: from VetoG4_SD.VetoG4_SDToolConfig import VetoSensorSDCfg tools += [ result.popToolsAndMerge(VetoSensorSDCfg(ConfigFlags)) ] + if ConfigFlags.Detector.EnableVetoNu: + from VetoNuG4_SD.VetoNuG4_SDToolConfig import VetoNuSensorSDCfg + tools += [ result.popToolsAndMerge(VetoNuSensorSDCfg(ConfigFlags)) ] if ConfigFlags.Detector.EnableTrigger: from TriggerG4_SD.TriggerG4_SDToolConfig import TriggerSensorSDCfg tools += [ result.popToolsAndMerge(TriggerSensorSDCfg(ConfigFlags)) ] diff --git a/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py index 33d34f728c6e0b0d7f6b451b5e81464ecf9c5f5b..4f4de1b8984b40d2cb5a8ed10f2239ff63d20e06 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4FieldConfigNew.py @@ -54,7 +54,7 @@ def BasicDetectorConstantFieldManagerToolCfg(ConfigFlags, name='BasicDetectorCon # def EmulsionFieldManagerToolCfg(ConfigFlags, name='EmulsionFieldManager', **kwargs): - kwargs.setdefault("LogicalVolumes", ['Emulsion::Emulsion']) + kwargs.setdefault("LogicalVolumes", ['Emulsion::EmulsionStationA']) #kwargs.setdefault('DeltaChord', 0.00001) kwargs.setdefault('DeltaIntersection', 0.00001) kwargs.setdefault('DeltaOneStep', 0.0001) @@ -63,7 +63,16 @@ def EmulsionFieldManagerToolCfg(ConfigFlags, name='EmulsionFieldManager', **kwar return BasicDetectorFieldManagerToolCfg(ConfigFlags, name, **kwargs) def VetoFieldManagerToolCfg(ConfigFlags, name='VetoFieldManager', **kwargs): - kwargs.setdefault("LogicalVolumes", ['Veto::Veto']) + kwargs.setdefault("LogicalVolumes", ['Veto::VetoStationA']) + #kwargs.setdefault('DeltaChord', 0.00001) + kwargs.setdefault('DeltaIntersection', 0.00001) + kwargs.setdefault('DeltaOneStep', 0.0001) + kwargs.setdefault('MaximumEpsilonStep', 0.001) + kwargs.setdefault('MinimumEpsilonStep', 0.00001) + return BasicDetectorFieldManagerToolCfg(ConfigFlags, name, **kwargs) + +def VetoNuFieldManagerToolCfg(ConfigFlags, name='VetoNuFieldManager', **kwargs): + kwargs.setdefault("LogicalVolumes", ['VetoNu::VetoNuStationA']) #kwargs.setdefault('DeltaChord', 0.00001) kwargs.setdefault('DeltaIntersection', 0.00001) kwargs.setdefault('DeltaOneStep', 0.0001) @@ -119,3 +128,12 @@ def EcalFieldManagerToolCfg(ConfigFlags, name='EcalFieldManager', **kwargs): kwargs.setdefault('MinimumEpsilonStep', 0.00001) return BasicDetectorFieldManagerToolCfg(ConfigFlags, name, **kwargs) +def TrenchFieldManagerToolCfg(ConfigFlags, name='TrenchFieldManager', **kwargs): + kwargs.setdefault("LogicalVolumes", ['Trench::Trench']) + #kwargs.setdefault('DeltaChord', 0.00001) + kwargs.setdefault('DeltaIntersection', 0.00001) + kwargs.setdefault('DeltaOneStep', 0.0001) + kwargs.setdefault('MaximumEpsilonStep', 0.001) + kwargs.setdefault('MinimumEpsilonStep', 0.00001) + return BasicDetectorFieldManagerToolCfg(ConfigFlags, name, **kwargs) + diff --git a/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py b/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py index 064cde911986868ace4708e37374a17e20a6de16..4e6f59490a97baee0020453bb9572fab2b090fbc 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py @@ -7,21 +7,23 @@ from AthenaConfiguration.ComponentFactory import CompFactory from AthenaCommon import Logging #the physics region tools -from G4FaserTools.G4PhysicsRegionConfigNew import NeutrinoPhysicsRegionToolCfg, TrackerPhysicsRegionToolCfg, ScintillatorPhysicsRegionToolCfg, EcalPhysicsRegionToolCfg +from G4FaserTools.G4PhysicsRegionConfigNew import NeutrinoPhysicsRegionToolCfg, TrackerPhysicsRegionToolCfg, ScintillatorPhysicsRegionToolCfg, EcalPhysicsRegionToolCfg, CavernPhysicsRegionToolCfg #the field config tools -from G4FaserTools.G4FieldConfigNew import FASERFieldManagerToolCfg, EmulsionFieldManagerToolCfg, VetoFieldManagerToolCfg, TriggerFieldManagerToolCfg, PreshowerFieldManagerToolCfg, TrackerFieldManagerToolCfg, DipoleFieldManagerToolCfg, EcalFieldManagerToolCfg +from G4FaserTools.G4FieldConfigNew import FASERFieldManagerToolCfg, EmulsionFieldManagerToolCfg, VetoFieldManagerToolCfg, VetoNuFieldManagerToolCfg, TriggerFieldManagerToolCfg, PreshowerFieldManagerToolCfg, TrackerFieldManagerToolCfg, DipoleFieldManagerToolCfg, EcalFieldManagerToolCfg, TrenchFieldManagerToolCfg from G4FaserTools.G4FaserToolsConfigNew import SensitiveDetectorMasterToolCfg GeoDetectorTool=CompFactory.GeoDetectorTool from EmulsionGeoModel.EmulsionGeoModelConfig import EmulsionGeometryCfg from VetoGeoModel.VetoGeoModelConfig import VetoGeometryCfg +from VetoNuGeoModel.VetoNuGeoModelConfig import VetoNuGeometryCfg from TriggerGeoModel.TriggerGeoModelConfig import TriggerGeometryCfg from PreshowerGeoModel.PreshowerGeoModelConfig import PreshowerGeometryCfg from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg from DipoleGeoModel.DipoleGeoModelConfig import DipoleGeometryCfg from EcalGeoModel.EcalGeoModelConfig import EcalGeometryCfg +from FaserGeoModel.TrenchGMConfig import TrenchGeometryCfg BoxEnvelope, MaterialDescriptionTool, VoxelDensityTool, G4AtlasDetectorConstructionTool = CompFactory.getComps("BoxEnvelope", "MaterialDescriptionTool", "VoxelDensityTool", "G4AtlasDetectorConstructionTool",) @@ -59,6 +61,16 @@ def VetoGeoDetectorToolCfg(ConfigFlags, name='Veto', **kwargs): result.setPrivateTools(GeoDetectorTool(name, **kwargs)) return result +def VetoNuGeoDetectorToolCfg(ConfigFlags, name='VetoNu', **kwargs): + #set up geometry + result=VetoNuGeometryCfg(ConfigFlags) + kwargs.setdefault("DetectorName", "VetoNu") + #add the GeometryNotifierSvc + result.addService(G4GeometryNotifierSvcCfg(ConfigFlags)) + kwargs.setdefault("GeometryNotifierSvc", result.getService("G4GeometryNotifierSvc")) + result.setPrivateTools(GeoDetectorTool(name, **kwargs)) + return result + def TriggerGeoDetectorToolCfg(ConfigFlags, name='Trigger', **kwargs): #set up geometry result=TriggerGeometryCfg(ConfigFlags) @@ -109,6 +121,16 @@ def EcalGeoDetectorToolCfg(ConfigFlags, name='Ecal', **kwargs): result.setPrivateTools(GeoDetectorTool(name, **kwargs)) return result +def TrenchGeoDetectorToolCfg(ConfigFlags, name='Trench', **kwargs): + #set up geometry + result=TrenchGeometryCfg(ConfigFlags) + kwargs.setdefault("DetectorName", "Trench") + #add the GeometryNotifierSvc + result.addService(G4GeometryNotifierSvcCfg(ConfigFlags)) + kwargs.setdefault("GeometryNotifierSvc", result.getService("G4GeometryNotifierSvc")) + result.setPrivateTools(GeoDetectorTool(name, **kwargs)) + return result + def generateSubDetectorList(ConfigFlags): result = ComponentAccumulator() SubDetectorList=[] @@ -121,6 +143,10 @@ def generateSubDetectorList(ConfigFlags): toolVeto = result.popToolsAndMerge(VetoGeoDetectorToolCfg(ConfigFlags)) SubDetectorList += [ toolVeto ] + if ConfigFlags.Detector.GeometryVetoNu: + toolVetoNu = result.popToolsAndMerge(VetoNuGeoDetectorToolCfg(ConfigFlags)) + SubDetectorList += [ toolVetoNu ] + if ConfigFlags.Detector.GeometryTrigger: toolTrigger = result.popToolsAndMerge(TriggerGeoDetectorToolCfg(ConfigFlags)) SubDetectorList += [ toolTrigger ] @@ -140,6 +166,11 @@ def generateSubDetectorList(ConfigFlags): if ConfigFlags.Detector.GeometryEcal: toolEcal = result.popToolsAndMerge(EcalGeoDetectorToolCfg(ConfigFlags)) SubDetectorList += [ toolEcal ] + + if ConfigFlags.Detector.GeometryTrench: + toolTrench = result.popToolsAndMerge(TrenchGeoDetectorToolCfg(ConfigFlags)) + SubDetectorList += [ toolTrench ] + result.setPrivateTools(SubDetectorList) return result @@ -196,6 +227,9 @@ def getFASER_RegionCreatorList(ConfigFlags): if ConfigFlags.Detector.GeometryFaserCalo: regionCreatorList += [EcalPhysicsRegionToolCfg(ConfigFlags)] + + if ConfigFlags.Detector.GeometryFaserCavern: + regionCreatorList += [CavernPhysicsRegionToolCfg(ConfigFlags)] return regionCreatorList @@ -217,6 +251,11 @@ def FASER_FieldMgrListCfg(ConfigFlags): tool = result.popToolsAndMerge(acc) fieldMgrList += [tool] + if ConfigFlags.Detector.GeometryVetoNu: + acc = VetoNuFieldManagerToolCfg(ConfigFlags) + tool = result.popToolsAndMerge(acc) + fieldMgrList += [tool] + if ConfigFlags.Detector.GeometryTrigger: acc = TriggerFieldManagerToolCfg(ConfigFlags) tool = result.popToolsAndMerge(acc) @@ -242,6 +281,12 @@ def FASER_FieldMgrListCfg(ConfigFlags): tool = result.popToolsAndMerge(acc) fieldMgrList += [tool] + if ConfigFlags.Detector.GeometryTrench: + acc = TrenchFieldManagerToolCfg(ConfigFlags) + tool = result.popToolsAndMerge(acc) + fieldMgrList += [tool] + + result.setPrivateTools(fieldMgrList) return result diff --git a/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py index 040853dc2f46d08f0a92843d8b2f0dfef945ef11..42016881857b3de6bd2aee6c3f682419b52fe2de 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4PhysicsRegionConfigNew.py @@ -16,7 +16,7 @@ def NeutrinoPhysicsRegionToolCfg(ConfigFlags, name="NeutrinoPhysicsRegionTool", def ScintillatorPhysicsRegionToolCfg(ConfigFlags, name='ScintillatorPhysicsRegionTool', **kwargs): kwargs.setdefault("RegionName", 'Scintillator') - volumeList = ['Veto::Plate' , 'Trigger::Plate', 'Preshower::Plate'] + volumeList = ['Veto::Plate' , 'Trigger::Plate', 'Preshower::Plate', 'VetoNu::Plate'] kwargs.setdefault("VolumeList", volumeList) kwargs.setdefault("ElectronCut", 0.05) kwargs.setdefault("PositronCut", 0.05) @@ -45,3 +45,13 @@ def EcalPhysicsRegionToolCfg(ConfigFlags, name='EcalPhysicsRegionTool', **kwargs kwargs.setdefault("PositronCut", rangeEMB) kwargs.setdefault("GammaCut", rangeEMB) return RegionCreator(name, **kwargs) + +def CavernPhysicsRegionToolCfg(ConfigFlags, name='CavernPhysicsRegionTool', **kwargs): + kwargs.setdefault("RegionName", 'Cavern') + volumeList = ['Trench::Trench'] + kwargs.setdefault("VolumeList", volumeList) + kwargs.setdefault("ElectronCut", 0.05) + kwargs.setdefault("PositronCut", 0.05) + kwargs.setdefault("GammaCut", 0.05) + return RegionCreator(name, **kwargs) + diff --git a/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py b/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py index e507545cd536d1a85889e6768330a77c5755c5c5..4bf06b76f66ba0af57e64646cebc12b18b978612 100644 --- a/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py +++ b/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py @@ -82,7 +82,8 @@ def FaserTruthServiceCfg(ConfigFlags, name="FaserISF_TruthService", **kwargs): FaserRegion.fFaserTracker, FaserRegion.fFaserDipole, FaserRegion.fFaserCalorimeter, - FaserRegion.fFaserCavern]) + FaserRegion.fFaserCavern, + FaserRegion.fFaserTrench]) #long_lived_simulators = ['LongLived', 'longLived', 'QS'] #from ISF_Config.ISF_jobProperties import ISF_Flags diff --git a/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserGeoIDSvc.cxx b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserGeoIDSvc.cxx index ed4a3370a690cd833e68a4a930fba0967df54541..18ad0de36e3548ac39c804ed92385ef4f6aef0ea 100644 --- a/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserGeoIDSvc.cxx +++ b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserGeoIDSvc.cxx @@ -123,13 +123,16 @@ FaserDetDescr::FaserRegion ISF::FaserGeoIDSvc::identifyGeoID(const Amg::Vector3D if (lvName == "Veto::Veto" || lvName == "Veto::VetoStationA" || lvName == "Trigger::Trigger" || lvName == "Trigger::TriggerStationA" || - lvName == "Preshower::Preshower" || lvName == "Preshower::PreshowerStationA") return FaserDetDescr::fFaserScintillator; + lvName == "Preshower::Preshower" || lvName == "Preshower::PreshowerStationA" || + lvName == "VetoNu::VetoNu" || lvName == "VetoNu::VetoNuStationA" ) return FaserDetDescr::fFaserScintillator; if (lvName == "Ecal::Ecal") return FaserDetDescr::fFaserCalorimeter; if (lvName == "Emulsion::Emulsion" || lvName == "Emulsion::EmulsionStationA" ) return FaserDetDescr::fFaserNeutrino; if (lvName == "Dipole::Dipole") return FaserDetDescr::fFaserDipole; + + if (lvName == "Trench::Trench") return FaserDetDescr::fFaserTrench; } // If all else fails diff --git a/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/FaserISF_Geant4Event/FaserISFG4GeoHelper.h b/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/FaserISF_Geant4Event/FaserISFG4GeoHelper.h index 8dc36356a51a161846307e0a677eaf5fa861a24b..29081a1b99180ad28fd7bcb338f2f45bb657b2b3 100644 --- a/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/FaserISF_Geant4Event/FaserISFG4GeoHelper.h +++ b/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/FaserISF_Geant4Event/FaserISFG4GeoHelper.h @@ -21,7 +21,7 @@ class FaserISFG4GeoHelper static bool checkVolumeDepth(G4LogicalVolume* logicalVol, int volLevel, int depth=0); private: - static G4LogicalVolume *s_vetoLV, *s_triggerLV, *s_preshowerLV, *s_sctLV, *s_dipoleLV, *s_ecalLV, *s_emulsionLV; + static G4LogicalVolume *s_vetoLV, *s_triggerLV, *s_preshowerLV, *s_vetonuLV, *s_sctLV, *s_dipoleLV, *s_ecalLV, *s_emulsionLV, *s_trenchLV; }; diff --git a/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/src/FaserISFG4GeoHelper.cxx b/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/src/FaserISFG4GeoHelper.cxx index 6697607742a1a4cb0cdebf08aa138ba1fca4ba6c..80942559c6c8c46cf9f0e9e7cedf78181dc9b264 100644 --- a/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/src/FaserISFG4GeoHelper.cxx +++ b/Simulation/ISF/ISF_Geant4/FaserISF_Geant4Event/src/FaserISFG4GeoHelper.cxx @@ -19,18 +19,20 @@ G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_sctLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_vetoLV = nullptr; +G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_vetonuLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_triggerLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_preshowerLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_ecalLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_dipoleLV = nullptr; G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_emulsionLV = nullptr; +G4LogicalVolume* iGeant4::FaserISFG4GeoHelper::s_trenchLV = nullptr; //________________________________________________________________________ FaserDetDescr::FaserRegion iGeant4::FaserISFG4GeoHelper::nextGeoId(const G4Step* aStep, int truthVolLevel) { - if (s_sctLV == nullptr && s_vetoLV == nullptr && s_triggerLV == nullptr && s_preshowerLV == nullptr && s_ecalLV == nullptr && s_emulsionLV == nullptr && s_dipoleLV == nullptr) // Initialize + if (s_sctLV == nullptr && s_vetoLV == nullptr && s_triggerLV == nullptr && s_preshowerLV == nullptr && s_vetonuLV == nullptr && s_ecalLV == nullptr && s_emulsionLV == nullptr && s_dipoleLV == nullptr && s_trenchLV == nullptr) // Initialize { G4LogicalVolumeStore * lvs = G4LogicalVolumeStore::GetInstance(); for (size_t i = 0; i < lvs->size(); ++i) { @@ -39,11 +41,13 @@ iGeant4::FaserISFG4GeoHelper::nextGeoId(const G4Step* aStep, int truthVolLevel) G4String thisName = thisLV->GetName(); if ( ( s_sctLV == nullptr && thisName == "SCT::Station" ) || thisName == "SCT::SCT" ) { s_sctLV = thisLV; } else if ( ( s_vetoLV == nullptr && thisName == "Veto::VetoStationA" ) || thisName == "Veto::Veto" ) { s_vetoLV = thisLV; } + else if ( ( s_vetonuLV == nullptr && thisName == "VetoNu::VetoNuStationA" ) || thisName == "VetoNu::VetoNu" ) { s_vetonuLV = thisLV; } else if ( ( s_triggerLV == nullptr && thisName == "Trigger::TriggerStationA" ) || thisName == "Trigger::Trigger" ) { s_triggerLV = thisLV; } else if ( ( s_preshowerLV == nullptr && thisName == "Preshower::PreshowerStationA" ) || thisName == "Preshower::Preshower" ) { s_preshowerLV = thisLV; } else if ( thisName == "Ecal::Ecal" ) { s_ecalLV = thisLV; } else if ( thisName == "Dipole::Dipole" ) { s_dipoleLV = thisLV; } else if ( ( s_emulsionLV == nullptr && thisName == "Emulsion::EmulsionStationA" ) || thisName == "Emulsion::Emulsion" ) { s_emulsionLV = thisLV; } + else if ( thisName == "Trench::Trench" ) { s_trenchLV = thisLV; } } const auto& worldVolume = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking()->GetWorldVolume()->GetLogicalVolume(); @@ -73,6 +77,7 @@ iGeant4::FaserISFG4GeoHelper::nextGeoId(const G4Step* aStep, int truthVolLevel) nextGeoID = FaserDetDescr::fFaserTracker; } else if ((s_vetoLV != nullptr && s_vetoLV == postStepVolume) || + (s_vetonuLV != nullptr && s_vetonuLV == postStepVolume) || (s_triggerLV != nullptr && s_triggerLV == postStepVolume) || (s_preshowerLV != nullptr && s_preshowerLV == postStepVolume)) { @@ -90,6 +95,10 @@ iGeant4::FaserISFG4GeoHelper::nextGeoId(const G4Step* aStep, int truthVolLevel) { nextGeoID = FaserDetDescr::fFaserDipole; } + else if (s_trenchLV != nullptr && s_trenchLV == postStepVolume) + { + nextGeoID = FaserDetDescr::fFaserTrench; + } else { nextGeoID = FaserDetDescr::fFaserCavern; @@ -107,11 +116,13 @@ bool iGeant4::FaserISFG4GeoHelper::checkVolumeDepth(G4LogicalVolume* lv, int vol if ( ((s_sctLV != nullptr) && (lv->GetName() == s_sctLV->GetName())) || ((s_vetoLV != nullptr) && (lv->GetName() == s_vetoLV->GetName())) || + ((s_vetonuLV != nullptr) && (lv->GetName() == s_vetonuLV->GetName())) || ((s_triggerLV != nullptr) && (lv->GetName() == s_triggerLV->GetName())) || ((s_preshowerLV != nullptr) && (lv->GetName() == s_preshowerLV->GetName())) || ((s_dipoleLV != nullptr) && (lv->GetName() == s_dipoleLV->GetName())) || ((s_ecalLV != nullptr) && (lv->GetName() == s_ecalLV->GetName())) || - ((s_emulsionLV != nullptr) && (lv->GetName() == s_emulsionLV->GetName())) ) { + ((s_emulsionLV != nullptr) && (lv->GetName() == s_emulsionLV->GetName())) || + ((s_trenchLV != nullptr) && (lv->GetName() == s_trenchLV->GetName())) ) { if(depth!=volLevel) { G4ExceptionDescription description; description << "Volume " << lv->GetName() << " at depth " << depth << " instead of depth " << volLevel; diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt index b19cee24e9260527698b0040339c7560a97feb49..1450b0a07133ff3ea8a5517244cbdb9a54b0262a 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt @@ -19,6 +19,8 @@ atlas_add_component ( FaserSCT_ConditionsTools atlas_add_library( FaserSCT_ConditionsToolsLib + FaserSCT_ConditionsTools/*.h + src/*.h src/*.cxx PUBLIC_HEADERS FaserSCT_ConditionsTools INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_NoisyStripTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_NoisyStripTool.h new file mode 100644 index 0000000000000000000000000000000000000000..9fcf6b9a54f891e52edcedb729a3ff8510af319a --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_NoisyStripTool.h @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS and FAsER collaborations +*/ + +#ifndef ISCT_NOISY_STRIP_TOOL +#define ISCT_NOISY_STRIP_TOOL + +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" +#include <vector> + + +class ISCT_NoisyStripTool: virtual public IAlgTool { +public: + virtual ~ISCT_NoisyStripTool() = default; + + DeclareInterfaceID(ISCT_NoisyStripTool, 1, 0); + + virtual std::map<std::pair<int,int>, double> getNoisyStrips(const EventContext& ctx) const = 0; + virtual std::map<std::pair<int,int>, double> getNoisyStrips(void) const = 0; +}; + +#endif // ISCT_NOISY_STRIP_TOOL diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0e2b5c444a8839e0421a073fd79b0737a89ed635 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.cxx @@ -0,0 +1,113 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +#include "FaserSCT_NoisyStripTool.h" + + +FaserSCT_NoisyStripTool::FaserSCT_NoisyStripTool (const std::string& type, + const std::string& name, const IInterface* parent) : + base_class(type, name, parent) {} + + +StatusCode FaserSCT_NoisyStripTool::initialize() { + return StatusCode::SUCCESS; +} + + +StatusCode FaserSCT_NoisyStripTool::finalize() { + return StatusCode::SUCCESS; +} + + +std::map<std::pair<int, int>, double> +FaserSCT_NoisyStripTool::getNoisyStrips(const EventContext& /*ctx*/) const { + // TODO fix hard-coded definition of noisy strip and read from NoisyPixels.xml database + std::map<std::pair<int, int>, double> noisyStrips {}; + // noisyStrips.insert({std::make_pair(10, 150), 0.25279282895176935}); + // noisyStrips.insert({std::make_pair(20, 155), 0.9950721341449819}); + // noisyStrips.insert({std::make_pair(38, 41), 1.0}); + // noisyStrips.insert({std::make_pair(48, 643), 0.6209110977322898}); + // noisyStrips.insert({std::make_pair(49, 69), 1.0}); + // noisyStrips.insert({std::make_pair(49, 508), 0.1250027872544429}); + // noisyStrips.insert({std::make_pair(49, 660), 1.0}); + // noisyStrips.insert({std::make_pair(61, 350), 0.3669587709322809}); + // noisyStrips.insert({std::make_pair(61, 351), 0.32956496532655477}); + // noisyStrips.insert({std::make_pair(64, 287), 1.0}); + // noisyStrips.insert({std::make_pair(65, 323), 0.5987691484380226}); + // noisyStrips.insert({std::make_pair(67, 147), 1.0}); + // noisyStrips.insert({std::make_pair(67, 207), 1.0}); + // noisyStrips.insert({std::make_pair(67, 346), 0.6463977523580173}); + // noisyStrips.insert({std::make_pair(83, 114), 0.9968113809173412}); + // noisyStrips.insert({std::make_pair(86, 544), 0.46609583695676415}); + // noisyStrips.insert({std::make_pair(96, 79), 1.0}); + // noisyStrips.insert({std::make_pair(96, 183), 1.0}); + // noisyStrips.insert({std::make_pair(97, 550), 1.0}); + // noisyStrips.insert({std::make_pair(100, 215), 1.0}); + // noisyStrips.insert({std::make_pair(100, 610), 1.0}); + // noisyStrips.insert({std::make_pair(130, 722), 1.0}); + // noisyStrips.insert({std::make_pair(132, 297), 0.8765803732691151}); + // noisyStrips.insert({std::make_pair(144, 597), 1.0}); + // noisyStrips.insert({std::make_pair(144, 665), 1.0}); + // noisyStrips.insert({std::make_pair(145, 9), 1.0}); + // noisyStrips.insert({std::make_pair(145, 492), 1.0}); + // noisyStrips.insert({std::make_pair(145, 566), 1.0}); + // noisyStrips.insert({std::make_pair(146, 267), 1.0}); + // noisyStrips.insert({std::make_pair(147, 393), 0.4758623765246282}); + // noisyStrips.insert({std::make_pair(147, 394), 0.5172252324570206}); + // noisyStrips.insert({std::make_pair(147, 395), 0.5058532343300556}); + // noisyStrips.insert({std::make_pair(147, 396), 0.5272816464869445}); + // noisyStrips.insert({std::make_pair(147, 397), 0.4782036702566504}); + // noisyStrips.insert({std::make_pair(147, 398), 0.5092202376970589}); + // noisyStrips.insert({std::make_pair(147, 399), 0.4811247129127924}); + // noisyStrips.insert({std::make_pair(147, 600), 1.0}); + // noisyStrips.insert({std::make_pair(151, 417), 0.6434767097018753}); + // noisyStrips.insert({std::make_pair(152, 698), 0.2651013445715433}); + // noisyStrips.insert({std::make_pair(152, 699), 0.3080250629919504}); + // noisyStrips.insert({std::make_pair(153, 396), 0.4862532610876982}); + // noisyStrips.insert({std::make_pair(153, 397), 0.44509108747519344}); + // noisyStrips.insert({std::make_pair(154, 620), 0.4075634936562089}); + // noisyStrips.insert({std::make_pair(154, 621), 0.5001449372310299}); + // noisyStrips.insert({std::make_pair(155, 146), 0.4566637679220461}); + // noisyStrips.insert({std::make_pair(155, 147), 0.4941021695988584}); + // noisyStrips.insert({std::make_pair(158, 737), 0.5486208665016612}); + // noisyStrips.insert({std::make_pair(158, 738), 0.5591901353490758}); + // noisyStrips.insert({std::make_pair(158, 739), 0.5590786451713604}); + // noisyStrips.insert({std::make_pair(160, 7), 1.0}); + // noisyStrips.insert({std::make_pair(161, 763), 1.0}); + // noisyStrips.insert({std::make_pair(164, 613), 1.0}); + // noisyStrips.insert({std::make_pair(167, 175), 1.0}); + // noisyStrips.insert({std::make_pair(170, 90), 0.48484848484848486}); + // noisyStrips.insert({std::make_pair(170, 91), 0.4570874305973644}); + // noisyStrips.insert({std::make_pair(173, 18), 1.0}); + // noisyStrips.insert({std::make_pair(173, 484), 1.0}); + // noisyStrips.insert({std::make_pair(174, 230), 1.0}); + // noisyStrips.insert({std::make_pair(174, 530), 1.0}); + // noisyStrips.insert({std::make_pair(175, 683), 1.0}); + // noisyStrips.insert({std::make_pair(176, 418), 1.0}); + // noisyStrips.insert({std::make_pair(177, 149), 1.0}); + // noisyStrips.insert({std::make_pair(177, 345), 1.0}); + // noisyStrips.insert({std::make_pair(178, 214), 1.0}); + // noisyStrips.insert({std::make_pair(178, 508), 0.5192097576203537}); + // noisyStrips.insert({std::make_pair(178, 673), 0.6028496889424042}); + // noisyStrips.insert({std::make_pair(179, 651), 0.999977701964457}); + // noisyStrips.insert({std::make_pair(182, 525), 0.5044707561263853}); + // noisyStrips.insert({std::make_pair(182, 526), 0.5083506143108792}); + // noisyStrips.insert({std::make_pair(185, 493), 0.42738644725399694}); + // noisyStrips.insert({std::make_pair(185, 494), 0.43757664949717934}); + // noisyStrips.insert({std::make_pair(187, 427), 0.9203737150757019}); + // noisyStrips.insert({std::make_pair(188, 696), 0.6201752625593685}); + // noisyStrips.insert({std::make_pair(188, 752), 1.0}); + // noisyStrips.insert({std::make_pair(189, 249), 0.1250027872544429}); + // noisyStrips.insert({std::make_pair(189, 338), 0.25925925925925924}); + // noisyStrips.insert({std::make_pair(191, 170), 1.0}); + // noisyStrips.insert({std::make_pair(191, 406), 1.0}); + return noisyStrips; +} + + +std::map<std::pair<int, int>, double> +FaserSCT_NoisyStripTool::getNoisyStrips() const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return getNoisyStrips(ctx); +} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.h new file mode 100644 index 0000000000000000000000000000000000000000..c554620885b0cf28beb5c3d93c6d6fa31377e3a4 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_NoisyStripTool.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS and CERN collaborations +*/ + +#ifndef FASERSCT_NOISY_STRIP_TOOL +#define FASERSCT_NOISY_STRIP_TOOL + +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserSCT_ConditionsTools/ISCT_NoisyStripTool.h" +#include "GaudiKernel/ICondSvc.h" +#include "GaudiKernel/EventContext.h" + + +class FaserSCT_NoisyStripTool: public extends<AthAlgTool, ISCT_NoisyStripTool> { +public: + FaserSCT_NoisyStripTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~FaserSCT_NoisyStripTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + virtual std::map<std::pair<int, int>, double> getNoisyStrips(const EventContext& ctx) const override; + virtual std::map<std::pair<int, int>, double> getNoisyStrips() const override; +}; + +#endif // FASERSCT_NOISY_STRIP_TOOL diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx index cae3df3c65e74cecd79c4729d2dc57cc8e7e4cf3..adad7ee37337a3d347bedc9c1f5b28cf731fb837 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx @@ -20,6 +20,7 @@ // #include "../SCT_StripVetoTool.h" // #include "../SCT_TdaqEnabledTool.h" #include "../FaserSCT_CableMappingTool.h" +#include "../FaserSCT_NoisyStripTool.h" // DECLARE_COMPONENT( SCT_ByteStreamErrorsTool ) // DECLARE_COMPONENT( SCT_ChargeTrappingTool ) @@ -42,4 +43,5 @@ DECLARE_COMPONENT( FaserSCT_ReadCalibChipDataTool ) DECLARE_COMPONENT( FaserSCT_SiliconConditionsTool ) // DECLARE_COMPONENT( SCT_StripVetoTool ) // DECLARE_COMPONENT( SCT_TdaqEnabledTool ) -DECLARE_COMPONENT( FaserSCT_CableMappingTool ) \ No newline at end of file +DECLARE_COMPONENT( FaserSCT_CableMappingTool ) +DECLARE_COMPONENT( FaserSCT_NoisyStripTool ) diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py b/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py index c9f267da7d9d2ba0c6bc973c3fa949b65c217ecc..f952b5766a0acf1085974f3af9332a8ac3de0462 100644 --- a/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py +++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py @@ -239,10 +239,11 @@ def FaserSCT_OutputCfg(flags): ItemList = ["FaserSCT_RDO_Container#*"] if flags.Digitization.TruthOutput: ItemList += ["TrackerSimDataCollection#*"] + ItemList += ["FaserSiHitCollection#*"] # Also write out the raw hits acc.merge(TruthDigitizationOutputCfg(flags)) acc.merge(OutputStreamCfg(flags, "RDO")) ostream = acc.getEventAlgo("OutputStreamRDO") - ostream.TakeItemsFromInput = True + #ostream.TakeItemsFromInput = True # Don't write hits to RDO by default ostream.ItemList += ItemList return acc diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx index bd6ff38f7fc46fe44c62e5ccb339744e46cad90c..87bb2437c36c0d0c4f2cbe0cbfb4f3a1270c1e1a 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx @@ -28,6 +28,7 @@ TrackerByteStreamCnv::TrackerByteStreamCnv(ISvcLocator* svcloc) , m_tool("TrackerDataDecoderTool") , m_mappingTool("FaserSCT_CableMappingTool") , m_rdpSvc("FaserROBDataProviderSvc", "TrackerByteStreamCnv") + , m_noisyStripTool("FaserSCT_NoisyStripTool") , m_detStoreSvc("StoreGateSvc/DetectorStore", "TrackerByteStreamCnv") { } @@ -48,6 +49,7 @@ StatusCode TrackerByteStreamCnv::initialize() CHECK(m_rdpSvc.retrieve()); CHECK(m_tool.retrieve()); CHECK(m_mappingTool.retrieve()); + CHECK(m_noisyStripTool.retrieve()); ATH_CHECK(m_detStoreSvc.retrieve()); ATH_CHECK(m_detStoreSvc->retrieve(m_sctID, "FaserSCT_ID")); @@ -98,10 +100,13 @@ StatusCode TrackerByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObject*& p auto mapping = m_mappingTool->getCableMapping(); ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries"); - + + auto noisyStrips = m_noisyStripTool->getNoisyStrips(); + ATH_MSG_DEBUG(noisyStrips.size() << " noisy strips"); + // Convert raw data into this container - CHECK( m_tool->convert(re, cont, key, mapping) ); + CHECK( m_tool->convert(re, cont, key, mapping, noisyStrips) ); pObj = SG::asStorable(cont); diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h index de0095b637bc99a9b0e30e2b34fba5842bcdbcf6..86262fbc244530aecac352d968a13d54d0943728 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h @@ -15,6 +15,7 @@ #include "AthenaBaseComps/AthMessaging.h" #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h" #include "FaserSCT_ConditionsTools/ISCT_CableMappingTool.h" +#include "FaserSCT_ConditionsTools/ISCT_NoisyStripTool.h" class TrackerDataDecoderTool; class IFaserROBDataProviderSvc; @@ -40,10 +41,11 @@ public: static const CLID& classID(); private: - ToolHandle<TrackerDataDecoderTool> m_tool; - ToolHandle<ISCT_CableMappingTool> m_mappingTool; ServiceHandle<IFaserROBDataProviderSvc> m_rdpSvc; ServiceHandle<StoreGateSvc> m_detStoreSvc; + ToolHandle<TrackerDataDecoderTool> m_tool; + ToolHandle<ISCT_CableMappingTool> m_mappingTool; + ToolHandle<ISCT_NoisyStripTool> m_noisyStripTool; const FaserSCT_ID* m_sctID{nullptr}; }; diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx index 9971d0292356a1e8437f5734c2703a0bac10ee2a..612978a068a931bf4a85b267537d89b626ba53e5 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx @@ -45,7 +45,7 @@ TrackerDataDecoderTool::initialize() ATH_CHECK(detStore()->retrieve(m_sctID, "FaserSCT_ID")); - auto first_wafer = m_sctID->wafer_begin(); + // auto first_wafer = m_sctID->wafer_begin(); // m_trb0Station = m_sctID->station(*first_wafer); m_sctContext = m_sctID->wafer_context(); @@ -81,7 +81,9 @@ StatusCode TrackerDataDecoderTool::convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* container, std::string key, - const std::map<int, std::pair<int, int> >& cableMapping) + const std::map<int, std::pair<int, int> >& cableMapping, + const std::map<std::pair<int, int>, double>& noisyStrips) + { ATH_MSG_DEBUG("TrackerDataDecoderTool::convert()"); @@ -231,6 +233,12 @@ TrackerDataDecoderTool::convert(const DAQFormats::EventFull* re, ATH_MSG_ERROR("Invalid strip number on side: " << stripOnSide); continue; } + // check if strip is noisy + auto it = noisyStrips.find(std::make_pair(waferHash, stripOnSide)); + if (it != noisyStrips.end() && it->second >= m_occupancyCut) { + ATH_MSG_VERBOSE("Mask wafer " << waferHash << ", strip " << stripOnSide << " with an occupancy of " << it->second); + continue; + } Identifier digitID {m_sctID->strip_id(id, stripOnSide)}; int errors{0}; int groupSize{1}; diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h index 32b42ced60b494d93661aa4f3ea8dbcbdc6ce63b..3bc337276a3f8eaba28fa51d90f7eb4f903592c7 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h @@ -31,7 +31,9 @@ class TrackerDataDecoderTool : public AthAlgTool { virtual StatusCode initialize(); virtual StatusCode finalize(); - StatusCode convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* cont, std::string key, const std::map<int, std::pair<int, int> >& cableMapping); + StatusCode convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* cont, std::string key, + const std::map<int, std::pair<int, int> >& cableMapping, + const std::map<std::pair<int, int>, double>& noisyStrips); private: const FaserSCT_ID* m_sctID{nullptr}; @@ -41,7 +43,8 @@ private: "ModuleMap", {7, 2, 5, 0, 3, 6, 1, 4}, "Mapping from online to offline module numbers" }; - + Gaudi::Property<double> m_occupancyCut {this, "OccupancyCut", 0.1, "Mask strips with an occupancy larger than the OccupancyCut"}; + // Gaudi::Property<uint32_t> m_trb0Station { this, "Trb0StationNumber", 1, "Station number for TRB #0" }; }; diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt b/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt index 4978495c385798463bd84f20276920cdde578765..e88d445536b1770103382549c17e502e4f5f8b09 100644 --- a/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt @@ -1,12 +1,9 @@ -################################################################################ -# Package: FaserSpacePoints -################################################################################ +atlas_subdir(FaserSpacePoints) -# Declare the package name: -atlas_subdir( FaserSpacePoints ) +atlas_add_component( + FaserSpacePoints + src/components/*.cxx src/*.cxx src/*.h + LINK_LIBRARIES AthenaBaseComps TrackerSimData TrackerSimEvent TrackerSpacePoint TrackerPrepRawData) -atlas_add_component( FaserSpacePoints - src/components/*.cxx src/*.cxx src/*.h - LINK_LIBRARIES AthenaBaseComps TrackerSpacePoint TrackerPrepRawData) - -atlas_install_python_modules( python/*.py ) \ No newline at end of file +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( test/*.py ) diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..7fa948ab3072fbbd11340eafb6c6c59cd92595dc --- /dev/null +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py @@ -0,0 +1,17 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def FaserSpacePointsCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + Tracker__FaserSpacePoints = CompFactory.Tracker.FaserSpacePoints + acc.addEventAlgo(Tracker__FaserSpacePoints(**kwargs)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST DATAFILE='SpacePoints.root' OPT='RECREATE'"] + acc.addService(thistSvc) + return acc diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py index 48197207d0c1b321e658b74ddb2d40d74ee244dd..78bae901d8c5319dd35ad4f101ff5cb291740395 100644 --- a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py @@ -22,7 +22,6 @@ Tracker__TruthSeededTrackFinder, THistSvc=CompFactory.getComps("Tracker::FaserSp def TruthSeededTrackFinderBasicCfg(flags, **kwargs): """Return ComponentAccumulator for TruthSeededTrackFinder""" acc = FaserSCT_GeometryCfg(flags) - kwargs.setdefault("SpacePointsSCTName", "SCT_SpacePointContainer") acc.addEventAlgo(Tracker__TruthSeededTrackFinder(**kwargs)) # attach ToolHandles return acc diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx index b9722a7c2f4318fd6d8e4cf2c76437ced6078d8e..caa4af80a79286b6bdb76e18754541f7ee498568 100644 --- a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx @@ -1,104 +1,128 @@ #include "FaserSpacePoints.h" #include "Identifier/Identifier.h" +#include "TrackerSimEvent/FaserSiHit.h" #include "TrackerSpacePoint/FaserSCT_SpacePoint.h" #include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" + namespace Tracker { - FaserSpacePoints::FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator) - : AthReentrantAlgorithm(name, pSvcLocator) { } - - StatusCode FaserSpacePoints::initialize() { - ATH_MSG_INFO(name() << "::" << __FUNCTION__); +FaserSpacePoints::FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name) {} + + +StatusCode FaserSpacePoints::initialize() { + ATH_CHECK(m_spacePointContainerKey.initialize()); + ATH_CHECK(m_siHitCollectionKey.initialize()); + ATH_CHECK(m_simDataCollectionKey.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + m_tree = new TTree("tree", "tree"); + m_tree->Branch("run", &m_run, "run/I"); + m_tree->Branch("event", &m_event, "event/I"); + m_tree->Branch("station", &m_station, "station/I"); + m_tree->Branch("layer", &m_layer, "layer/I"); + m_tree->Branch("phi", &m_phi, "phi/I"); + m_tree->Branch("eta", &m_eta, "eta/I"); + m_tree->Branch("side", &m_side, "side/I"); + m_tree->Branch("x", &m_x, "x/D"); + m_tree->Branch("y", &m_y, "y/D"); + m_tree->Branch("z", &m_z, "z/D"); + m_tree->Branch("muon_hit", &m_muon_hit, "muon_hit/B"); + m_tree->Branch("tx", &m_tx, "tx/D"); + m_tree->Branch("ty", &m_ty, "ty/D"); + m_tree->Branch("tz", &m_tz, "tz/D"); + ATH_CHECK(histSvc()->regTree("/HIST/spacePoints", m_tree)); + return StatusCode::SUCCESS; +} - if ( m_sct_spcontainer.key().empty()) { - ATH_MSG_FATAL( "SCTs selected and no name set for SCT clusters"); - return StatusCode::FAILURE; - } - ATH_CHECK( m_sct_spcontainer.initialize() ); - ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); +StatusCode FaserSpacePoints::finalize() { + return StatusCode::SUCCESS; +} - std::string filePath = m_filePath; - m_outputFile = TFile::Open(filePath.c_str(), "RECREATE"); - if (m_outputFile == nullptr) { - ATH_MSG_ERROR("Unable to open output file at " << m_filePath); - return StatusCode::FAILURE; - } - m_outputFile->cd(); +bool FaserSpacePoints::muon_hit(const TrackerSimDataCollection* simDataMap, Identifier id) const { + // check if Identifier in simDataMap + if (!simDataMap->count(id)) { + return false; + } + // check if hit originates from a muon (if the pdg code of the hit is -13) + TrackerSimData simData = simDataMap->at(id); + const std::vector<TrackerSimData::Deposit>& deposits = simData.getdeposits(); + auto it = std::find_if( + deposits.begin(), deposits.end(), [](TrackerSimData::Deposit deposit) { + return deposit.first->pdg_id() == -13; + }); + return it != deposits.end(); +} - std::string treeName = m_treeName; - m_outputTree = new TTree(treeName.c_str(), "tree"); - if (m_outputTree == nullptr) { - ATH_MSG_ERROR("Unable to create TTree"); - return StatusCode::FAILURE; - } +StatusCode FaserSpacePoints::execute(const EventContext& ctx) const { + m_run = ctx.eventID().run_number(); + m_event = ctx.eventID().event_number(); - FaserSpacePoints::initializeTree(); - return StatusCode::SUCCESS; - } + SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey, ctx}; + ATH_CHECK(spacePointContainer.isValid()); - - StatusCode FaserSpacePoints::finalize() { - ATH_MSG_INFO(name() << "::" << __FUNCTION__); - m_outputFile->cd(); - m_outputTree->Write(); - return StatusCode::SUCCESS; - } + SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_siHitCollectionKey, ctx}; + ATH_CHECK(siHitCollection.isValid()); + + SG::ReadHandle<TrackerSimDataCollection> simDataCollection {m_simDataCollectionKey, ctx}; + ATH_CHECK(simDataCollection.isValid()); - - StatusCode FaserSpacePoints::execute(const EventContext& ctx) const { - ATH_MSG_INFO(name() << "::" << __FUNCTION__); - - m_run = ctx.eventID().run_number(); - m_event = ctx.eventID().event_number(); - ATH_MSG_DEBUG("run = " << m_run); - ATH_MSG_DEBUG("event = " << m_event); - - SG::ReadHandle<FaserSCT_SpacePointContainer> sct_spcontainer( m_sct_spcontainer, ctx ); - if (!sct_spcontainer.isValid()){ - ATH_MSG_FATAL("Could not find the data object " << sct_spcontainer.name()); - return StatusCode::RECOVERABLE; + + // create map of the IdentifierHash of a SCT sensor and the true position of the corresponding hit + std::map<IdentifierHash, HepGeom::Point3D<double>> truePositions; + for (const FaserSiHit& hit: *siHitCollection) { + if ((!hit.particleLink()) || (hit.particleLink()->pdg_id() != -13)) { + continue; + } + Identifier waferId = m_idHelper->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor()); + IdentifierHash waferHash = m_idHelper->wafer_hash(waferId); + const HepGeom::Point3D<double> localPosition = hit.localStartPosition(); + const TrackerDD::SiDetectorElement* element = m_detMgr->getDetectorElement(waferId); + if (element) { + const HepGeom::Point3D<double> globalPosition = + Amg::EigenTransformToCLHEP(element->transformHit()) * localPosition; + truePositions[waferHash] = globalPosition; } + } + - m_nCollections = sct_spcontainer->size(); - ATH_MSG_DEBUG("nCollections = " << m_nCollections); - FaserSCT_SpacePointContainer::const_iterator it = sct_spcontainer->begin(); - FaserSCT_SpacePointContainer::const_iterator it_end = sct_spcontainer->end(); - - for(; it != it_end; ++it) { - const FaserSCT_SpacePointCollection* col = *it; - m_nSpacepoints = col->size(); - ATH_MSG_DEBUG("nSpacepoints = " << m_nSpacepoints); - - FaserSCT_SpacePointCollection::const_iterator it_sp = col->begin(); - FaserSCT_SpacePointCollection::const_iterator it_sp_end = col->end(); - for (; it_sp != it_sp_end; ++it_sp) { - const FaserSCT_SpacePoint* sp = *it_sp; - const auto id = sp->clusterList().first->identify(); - int station = m_idHelper->station(id); - int plane = m_idHelper->layer(id); - m_layer = (station - 1) * 3 + plane; - - Amg::Vector3D position = sp->globalPosition(); - m_x = position.x(); - m_y = position.y(); - m_z = position.z(); - - m_outputTree->Fill(); + for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) { + for (const FaserSCT_SpacePoint* spacePoint : *spacePointCollection) { + Identifier id1 = spacePoint->cluster1()->identify(); + Identifier id2 = spacePoint->cluster2()->identify(); + m_station = m_idHelper->station(id1); + m_layer = m_idHelper->layer(id1); + m_phi = m_idHelper->phi_module(id1); + m_eta = m_idHelper->eta_module(id1); + m_side = m_idHelper->side(id1); + // check if both clusters originate from a muon + m_muon_hit = (muon_hit(simDataCollection.get(), id1) && muon_hit(simDataCollection.get(), id2)); + // global reconstructed position of space point + Amg::Vector3D position = spacePoint->globalPosition(); + m_x = position.x(); + m_y = position.y(); + m_z = position.z(); + // global true position of simulated hit + IdentifierHash waferHash = spacePoint->elementIdList().first; + if (truePositions.count(waferHash)) { + auto truePosition = truePositions[waferHash]; + m_tx = truePosition.x(); + m_ty = truePosition.y(); + m_tz = truePosition.z(); + } else { + m_tx = -1; + m_ty = -1; + m_tz = -1; } + m_tree->Fill(); } - return StatusCode::SUCCESS; } + return StatusCode::SUCCESS; +} - void FaserSpacePoints::initializeTree() { - m_outputTree->Branch("run", &m_run); - m_outputTree->Branch("event", &m_event); - m_outputTree->Branch("layer", &m_layer); - m_outputTree->Branch("n_collections", &m_nCollections); - m_outputTree->Branch("n_spacepoints", &m_nSpacepoints); - m_outputTree->Branch("x", &m_x); - m_outputTree->Branch("y", &m_y); - m_outputTree->Branch("z", &m_z); - } } diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h index 28807d73e7ac7939c5b830a758846028feedb815..1cc43f65e2f1a674b692487a26421ad526b466f3 100644 --- a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h @@ -2,45 +2,70 @@ #define FASERSPACEPOINTS_H #include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" #include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" #include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "TrackerSimData/TrackerSimDataCollection.h" #include <string> #include <atomic> #include "TTree.h" #include "TFile.h" +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + namespace Tracker { - class FaserSpacePoints : public AthReentrantAlgorithm { - public: - FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator); - virtual ~FaserSpacePoints() = default; - - virtual StatusCode initialize() override; - virtual StatusCode execute(const EventContext& ctx) const override; - virtual StatusCode finalize() override; - - private: - void initializeTree(); - - mutable int m_run{0}; - mutable int m_event{0}; - mutable int m_layer{0}; - mutable int m_nCollections{0}; - mutable int m_nSpacepoints{0}; - mutable float m_x{0}; - mutable float m_y{0}; - mutable float m_z{0}; - - const FaserSCT_ID* m_idHelper{nullptr}; - SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_sct_spcontainer{this, "SpacePointsSCTName", "SCT spacepoint container"}; - - Gaudi::Property<std::string> m_filePath{this, "FilePath", "spacepoints.root", "Output root file for spacepoints"}; - Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", ""}; - - TFile* m_outputFile; - TTree* m_outputTree; - }; + +class FaserSpacePoints : public AthReentrantAlgorithm, AthHistogramming { + public: + FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~FaserSpacePoints() = default; + + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + + const ServiceHandle<ITHistSvc>& histSvc() const; + + private: + const FaserSCT_ID* m_idHelper{nullptr}; + const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr}; + bool muon_hit(const TrackerSimDataCollection* simDataMap, Identifier id) const; + ServiceHandle<ITHistSvc> m_histSvc; + + SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey { + this, "SpacePoints", "SCT_SpacePointContainer"}; + SG::ReadHandleKey<FaserSiHitCollection> m_siHitCollectionKey { + this, "FaserSiHitCollection", "SCT_Hits"}; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { + this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + + mutable TTree* m_tree; + mutable int m_run {0}; + mutable int m_event {0}; + mutable int m_station {0}; + mutable int m_layer {0}; + mutable int m_phi {0}; + mutable int m_eta {0}; + mutable int m_side {0}; + mutable double m_x {0}; + mutable double m_y {0}; + mutable double m_z {0}; + mutable bool m_muon_hit {false}; + mutable double m_tx {0}; + mutable double m_ty {0}; + mutable double m_tz {0}; +}; + +inline const ServiceHandle<ITHistSvc>& FaserSpacePoints::histSvc() const { + return m_histSvc; +} + } #endif // FASERSPACEPOINTS_H diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..a3d50f97a2127b4b33fec1c9cf50ab85218e8621 --- /dev/null +++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from FaserSpacePoints.FaserSpacePointsConfig import FaserSpacePointsCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "spacePoints.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.lock() + +# Core components +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(FaserSpacePointsCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::FaserSpacePoints").OutputLevel = DEBUG + +sc = acc.run(maxEvents=1000) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt b/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..edb6005ad67fab4e0fbb377aadee3a5fe3934235 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt @@ -0,0 +1,10 @@ +atlas_subdir(MCEvents) + +atlas_add_component( + MCEvents + src/MCEventsAlg.h + src/MCEventsAlg.cxx + src/components/MCEvents_entries.cxx + LINK_LIBRARIES AthenaBaseComps GeneratorObjects StoreGateLib TrackerIdentifier TrackerSimEvent GaudiKernel) +atlas_install_python_modules(python/*.py) +atlas_install_scripts(test/*.py) diff --git a/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py b/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..215d7a0ba1b878434beeb126931b32d832699155 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py @@ -0,0 +1,12 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def MCEventsCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + mc_events_alg = CompFactory.MCEventsAlg + acc.addEventAlgo(mc_events_alg (**kwargs)) + return acc diff --git a/Tracker/TrackerRecAlgs/MCEvents/python/__init__.py b/Tracker/TrackerRecAlgs/MCEvents/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e825850298b692e6841528cd61a897c3c3f584ff --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx @@ -0,0 +1,53 @@ +#include "MCEventsAlg.h" +#include "TrackerIdentifier/FaserSCT_ID.h" + + +MCEventsAlg::MCEventsAlg(const std::string& name, ISvcLocator* pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator) {} + + +StatusCode MCEventsAlg::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + ATH_CHECK(m_mcEventKey.initialize()); + ATH_CHECK(m_faserSiHitKey.initialize()); + + return StatusCode::SUCCESS; +} + + +StatusCode MCEventsAlg::execute(const EventContext& ctx) const { + SG::ReadHandle<FaserSiHitCollection> siHitCollection (m_faserSiHitKey, ctx); + std::map<int, std::vector<const FaserSiHit*>> particle_map {}; + ATH_CHECK(siHitCollection.isValid()); + for (const FaserSiHit& hit : *siHitCollection) { + int barcode = hit.particleLink().barcode(); + particle_map[barcode].push_back(&hit); + } + + SG::ReadHandle<McEventCollection> mcEvents (m_mcEventKey, ctx); + ATH_CHECK(mcEvents.isValid()); + for (const HepMC::GenEvent* evt : *mcEvents) { + for (const HepMC::GenParticle* p : evt->particle_range()) { + const HepMC::FourVector vertex = p->production_vertex()->position(); + const HepMC::FourVector momentum = p->momentum(); + ATH_MSG_DEBUG("pdg: " << p->pdg_id() << ", barcode: " << p->barcode()); + ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z()); + ATH_MSG_DEBUG("momentum: " << momentum.px() << ", " << momentum.py() << ", " << momentum.pz()); + auto hits = particle_map[p->barcode()]; + for (const FaserSiHit* hit : hits) { + int station = hit->getStation(); + int layer = hit->getPlane(); + int phi = hit->getRow(); + int eta = hit->getModule(); + int side = hit->getSensor(); + ATH_MSG_DEBUG(station << "/" << layer << "/" << phi << "/" << eta << "/" << side); + } + } + } + return StatusCode::SUCCESS; +} + + +StatusCode MCEventsAlg::finalize() { + return StatusCode::SUCCESS; +} diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..6b28d076f21f593e1ea0530e6148e55b22f28fd5 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h @@ -0,0 +1,26 @@ +#ifndef MCEVENTS_MCEVENTSALG_H +#define MCEVENTS_MCEVENTSALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "GeneratorObjects/McEventCollection.h" + +class FaserSCT_ID; + +class MCEventsAlg : public AthReentrantAlgorithm { +public: + MCEventsAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~MCEventsAlg() = default; + + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + +private: + const FaserSCT_ID* m_idHelper {nullptr}; + SG::ReadHandleKey<McEventCollection> m_mcEventKey { this, "McEventCollection", "BeamTruthEvent" }; + SG::ReadHandleKey<FaserSiHitCollection> m_faserSiHitKey { this, "FaserSiHitCollection", "SCT_Hits" }; +}; + + +#endif // MCEVENTS_MCEVENTSALG_H diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx b/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2fbef91d7d22c81a1d230bee04fc9a88b5a1daaa --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx @@ -0,0 +1,3 @@ +#include "../MCEventsAlg.h" + +DECLARE_COMPONENT(MCEventsAlg) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py b/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..b8e6ad587cdb132f93b7e1d57c5b958c9270fd9b --- /dev/null +++ b/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from MCEvents.MCEventsConfig import MCEventsCfg + + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +# Configure +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "MCEvents.ESD.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(MCEventsCfg(ConfigFlags)) +acc.getEventAlgo("MCEventsAlg").OutputLevel = DEBUG + +sc = acc.run(maxEvents=10) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt b/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..751e1f04a43c5f154013f81a2a74b44495df5dea --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt @@ -0,0 +1,11 @@ +atlas_subdir(MyClusters) + +atlas_add_component( + MyClusters + src/MyClustersAlg.h + src/MyClustersAlg.cxx + src/components/MyClusters_entries.cxx + LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerPrepRawData StoreGateLib GaudiKernel) + +atlas_install_python_modules(python/*.py) +atlas_install_scripts(test/*.py) diff --git a/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py b/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..64757e1a96f8dff63993a8a2275ca5cc2db0b7c2 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py @@ -0,0 +1,17 @@ +""" +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def MyClustersCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + my_clusters_alg = CompFactory.MyClustersAlg + acc.addEventAlgo(my_clusters_alg (**kwargs)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST DATAFILE='MyClusters.root' OPT='RECREATE'"] + acc.addService(thistSvc) + return acc diff --git a/Tracker/TrackerRecAlgs/MyClusters/python/__init__.py b/Tracker/TrackerRecAlgs/MyClusters/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..050e5bed4949ad32855e899196bac03f91634ba8 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx @@ -0,0 +1,70 @@ +#include "MyClustersAlg.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerIdentifier/FaserSCT_ID.h" + + +MyClustersAlg::MyClustersAlg(const std::string& name, ISvcLocator* pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name) {} + + +StatusCode MyClustersAlg::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + ATH_CHECK(m_clusterContainerKey.initialize()); + + m_tree = new TTree("tree", "tree"); + m_tree->Branch("run", &m_run, "run/I"); + m_tree->Branch("event", &m_event, "event/I"); + m_tree->Branch("station", &m_station, "station/I"); + m_tree->Branch("layer", &m_layer, "layer/I"); + m_tree->Branch("phi", &m_phi, "phi/I"); + m_tree->Branch("eta", &m_eta, "eta/I"); + m_tree->Branch("side", &m_side, "side/I"); + m_tree->Branch("x", &m_x, "x/D"); + m_tree->Branch("y", &m_y, "y/D"); + m_tree->Branch("z", &m_z, "z/D"); + m_tree->Branch("lx", &m_lx, "lx/D"); + m_tree->Branch("ly", &m_ly, "ly/D"); + ATH_CHECK(histSvc()->regTree("/HIST/clusters", m_tree)); + return StatusCode::SUCCESS; +} + + +StatusCode MyClustersAlg::execute(const EventContext& ctx) const { + m_run = ctx.eventID().run_number(); + m_event = ctx.eventID().event_number(); + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey, ctx}; + ATH_CHECK(clusterContainer.isValid()); + + for (const auto& clusterCollection : *clusterContainer) { + for (const auto& cluster : *clusterCollection) { + auto id = cluster->identify(); + m_station = m_idHelper->station(id); + m_layer = m_idHelper->layer(id); + m_eta = m_idHelper->eta_module(id); + m_phi = m_idHelper->phi_module(id); + m_side = m_idHelper->side(id); + auto localPos = cluster->localPosition(); + m_lx = localPos.x(); + m_ly = localPos.y(); + auto localCov = cluster->localCovariance(); + auto pos = cluster->globalPosition(); + m_x = pos.x(); + m_y = pos.y(); + m_z = pos.z(); + m_tree->Fill(); + ATH_MSG_DEBUG("global position\n" << pos); + ATH_MSG_DEBUG("local position\n" << localPos); + ATH_MSG_DEBUG("local covariance\n" << localCov); + } + } + return StatusCode::SUCCESS; +} + + +StatusCode MyClustersAlg::finalize() { + return StatusCode::SUCCESS; +} diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..04c6202a7e7f36a886a25d854ef31fae2e555946 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +#ifndef MYCLUSTERS_MYCLUSTERSALG_H +#define MYCLUSTERS_MYCLUSTERSALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" + +class TTree; +class FaserSCT_ID; + +class MyClustersAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + MyClustersAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~MyClustersAlg() = default; + + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + + const ServiceHandle<ITHistSvc>& histSvc() const; + +private: + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { + this, "FaserSCT_ClusterContainer", "SCT_ClusterContainer", "cluster container"}; + ServiceHandle<ITHistSvc> m_histSvc; + const FaserSCT_ID* m_idHelper {nullptr}; + mutable TTree* m_tree; + + mutable unsigned int m_run; + mutable unsigned int m_event; + mutable unsigned int m_station; + mutable unsigned int m_layer; + mutable int m_eta; + mutable int m_phi; + mutable int m_side; + mutable double m_lx; + mutable double m_ly; + mutable double m_x; + mutable double m_y; + mutable double m_z; +}; + + +inline const ServiceHandle<ITHistSvc>& MyClustersAlg::histSvc() const { + return m_histSvc; +} + + +#endif // MYCLUSTERS_MYCLUSTERSALG_H diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx b/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..93cf0f53b350ced62ddc1c00a401a082fbb68f2a --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx @@ -0,0 +1,3 @@ +#include "../MyClustersAlg.h" + +DECLARE_COMPONENT(MyClustersAlg) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py b/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..c4ae4953adbe00bf94bcb2933d20bff32fcc107b --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from MyClusters.MyClustersConfig import MyClustersCfg + + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +# Configure +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "MyClusters.ESD.root" +ConfigFlags.Output.AODFileName = "MyClsuters.AOD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(MyClustersCfg(ConfigFlags)) +acc.getEventAlgo("MyClustersAlg").OutputLevel = DEBUG + +sc = acc.run(maxEvents=10) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt b/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..72f4a7ac272d63a1060b39cb89a222fb4fc4e026 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(MyExtrapolationExample) + +atlas_add_component( + MyExtrapolationExample + src/MyExtrapolationExample.h + src/MyExtrapolationExample.cxx + src/components/MyExtrapolationExample_entries.cxx + LINK_LIBRARIES AthenaBaseComps StoreGateLib GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerIdentifier TrackerReadoutGeometry +) + +atlas_install_python_modules(python/*.py) +atlas_install_scripts(test/*.py) diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..d87ae7f5973b3f69dc4206fbb0cc5830f64344ae --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py @@ -0,0 +1,34 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +# def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# FaserActsTrackingGeometrySvc = CompFactory.FaserActsTrackingGeometrySvc +# acc.addService(FaserActsTrackingGeometrySvc(name="FaserActsTrackingGeometrySvc", **kwargs)) +# return acc + +# def FaserActsAlignmentCondAlgCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs)) +# return acc + +def MyExtrapolationExampleCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + acc.merge(MagneticFieldSvcCfg(flags)) + # acc.merge(FaserActsTrackingGeometrySvcCfg(flags)) + # acc.merge(FaserActsAlignmentCondAlgCfg(flags)) + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 1000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + + my_extrapolation_example = CompFactory.Tracker.MyExtrapolationExample(**kwargs) + my_extrapolation_example.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(my_extrapolation_example) + return acc diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/__init__.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx new file mode 100644 index 0000000000000000000000000000000000000000..aecebc372e415c6c58f1464706c6f25ea6001dc2 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx @@ -0,0 +1,114 @@ +#include "MyExtrapolationExample.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include <cmath> + + +namespace Tracker { + +MyExtrapolationExample::MyExtrapolationExample(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator) {} + +StatusCode MyExtrapolationExample::initialize() { + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_faserSiHitKey.initialize()); + ATH_CHECK(m_extrapolationTool.retrieve()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + return StatusCode::SUCCESS; +} + +StatusCode MyExtrapolationExample::execute(const EventContext &ctx) const { + const Acts::GeometryContext gctx = + m_extrapolationTool->trackingGeometryTool()->getNominalGeometryContext().context(); + + std::vector<double> z_positions {}; + SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_faserSiHitKey, ctx}; + ATH_CHECK(siHitCollection.isValid()); + for (const FaserSiHit& hit : *siHitCollection) { + if ((hit.getStation() == 1) && (hit.getPlane() == 0) && (hit.getSensor() == 0)) { + if (hit.particleLink()) { + if (std::abs(hit.particleLink()->pdg_id()) != 13) + continue; + Identifier id = m_idHelper->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor()); + const TrackerDD::SiDetectorElement* element = m_detMgr->getDetectorElement(id); + const HepGeom::Point3D<double> globalStartPosition = + Amg::EigenTransformToCLHEP(element->transformHit()) * hit.localStartPosition(); + z_positions.push_back(globalStartPosition.z()); + ATH_MSG_DEBUG("SiHit: " << globalStartPosition.x() << ", " << globalStartPosition.y() << ", " << globalStartPosition.z()); + } + } + } + + double z_mean = 0; + for (double z : z_positions) { + z_mean += z; + } + z_mean /= z_positions.size(); + + SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey, ctx}; + ATH_CHECK(mcEvents.isValid()); + if (mcEvents->size() != 1) { + ATH_MSG_ERROR("There should be exactly one event in the McEventCollection."); + return StatusCode::FAILURE; + } + + + for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) { + if ((std::abs(particle->pdg_id()) != 13)) { + continue; + } + const HepMC::FourVector& vertex = particle->production_vertex()->position(); + if (vertex.z() > 0) { + continue; + } + const HepMC::FourVector& momentum = particle->momentum(); + double phi = momentum.phi(); + double theta = momentum.theta(); + double charge = particle->pdg_id() > 0 ? -1 : 1; + double abs_momentum = momentum.rho() * m_MeV2GeV; + double qop = charge / abs_momentum; + // The coordinate system of the Acts::PlaneSurface is defined as + // T = Z = normal, U = X x T = -Y, V = T x U = x +// Acts::BoundVector pars; +// pars << -vertex.y(), vertex.x(), phi, theta, qop, vertex.t(); + Acts::BoundVector pars = Acts::BoundVector::Zero(); + pars[Acts::eBoundLoc0] = -vertex.y(); + pars[Acts::eBoundLoc1] = vertex.x(); + pars[Acts::eBoundPhi] = phi; + pars[Acts::eBoundTheta] = theta; + pars[Acts::eBoundQOverP] = qop; + pars[Acts::eBoundTime] = vertex.t(); + + auto startSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, vertex.z()), Acts::Vector3(0, 0, 1)); + auto targetSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, z_mean), Acts::Vector3(0, 0, 1)); + Acts::BoundTrackParameters startParameters( + std::move(startSurface), pars, charge); + ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z()); + ATH_MSG_DEBUG("vertex momentum: " << momentum.x() * m_MeV2GeV << ", " << momentum.y() * m_MeV2GeV << ", " << momentum.z() * m_MeV2GeV); + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters = + m_extrapolationTool->propagate(ctx, startParameters, *targetSurface); + if (targetParameters) { + Acts::Vector3 targetPosition = targetParameters->position(gctx); + Acts::Vector3 targetMomentum = targetParameters->momentum(); + ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z()); + ATH_MSG_DEBUG("origin: " << targetPosition.x() << ", " << targetPosition.y() << ", " << targetPosition.z()); + ATH_MSG_DEBUG("vertex momentum: " << momentum.x() * m_MeV2GeV << ", " << momentum.y() * m_MeV2GeV << ", " << momentum.z() * m_MeV2GeV); + ATH_MSG_DEBUG("origin momentum: " << targetMomentum.x() << ", " << targetMomentum.y() << ", " << targetMomentum.z()); + } + } + + return StatusCode::SUCCESS; +} + +StatusCode MyExtrapolationExample::finalize() { + return StatusCode::SUCCESS; +} + +} // Tracker diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h new file mode 100644 index 0000000000000000000000000000000000000000..cd5a2ed077310d3a07e5edd41787033593642c18 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h @@ -0,0 +1,42 @@ +/* +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +*/ + +#ifndef MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H +#define MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include "GeneratorObjects/McEventCollection.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; + +} +namespace Tracker { + +class MyExtrapolationExample : public AthReentrantAlgorithm { + public: + MyExtrapolationExample(const std::string& name, ISvcLocator* pSvcLocator); + + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + +private: + double m_MeV2GeV = 1e-3; + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr}; + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey { + this, "McEventCollection", "TruthEvent"}; + SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey { + this, "FaserSiHitCollection", "SCT_Hits"}; + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { + this, "ExtrapolationTool", "FaserActsExtrapolationTool"}; +}; + +} // namespace Tracker + +#endif // MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6601e0a3fe0e99d45ca137db49d8b63bb89573d1 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx @@ -0,0 +1,3 @@ +#include "../MyExtrapolationExample.h" + +DECLARE_COMPONENT(Tracker::MyExtrapolationExample) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..fe83560fa4fe694fb643bfd514cfd2d2c8df4c14 --- /dev/null +++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG, VERBOSE +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from MyExtrapolationExample.MyExtrapolationExampleConfig import MyExtrapolationExampleCfg + + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +# Configure +ConfigFlags.Input.Files = ['my.HITS.pool.root'] +ConfigFlags.Output.ESDFileName = "MyExtrapolationExample.ESD.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(MyExtrapolationExampleCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::MyExtrapolationExample").OutputLevel = VERBOSE + +sc = acc.run(maxEvents=10) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py index 5e94a1fb0e944666f4f245e8f47bc1100fcd6929..b408cb0e0d8c255833b5e51d47dafe461012a48b 100644 --- a/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/python/NoisyStripFinderConfig.py @@ -1,5 +1,5 @@ """ -Copyright (C) 2021 CERN for the benefit of the FASER collaboration + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration """ from AthenaConfiguration.ComponentFactory import CompFactory diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..b3c0697cfcef6539190aeeebf26e16b4e0d3b100 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +""" + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from NoisyStripFinder.NoisyStripFinderConfig import NoisyStripFinderCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +run = 1792 +ConfigFlags.Input.Files = [f"/home/tboeckh/Documents/data/TI12/Faser-Physics-00{run}-00000.raw"] +ConfigFlags.Output.ESDFileName = f"run00{run}-00000.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg( + ConfigFlags, + name="LevelClustering", + DataObjectName="SCT_LEVELMODE_RDOs", + ClusterToolTimingPattern="X1X")) +acc.merge(NoisyStripFinderCfg(ConfigFlags)) + +# Hack to avoid problem with our use of MC databases when isMC = False +replicaSvc = acc.getService("DBReplicaSvc") +replicaSvc.COOLSQLiteVetoPattern = "" +replicaSvc.UseCOOLSQLite = True +replicaSvc.UseCOOLFrontier = False +replicaSvc.UseGeomSQLite = True + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackCounts/python/TrackCountsConfig.py b/Tracker/TrackerRecAlgs/TrackCounts/python/TrackCountsConfig.py index 934579044bcf3cd9d731f4199ed374cda045aebf..da136d0381b211477497550e2072cae6fec029d9 100644 --- a/Tracker/TrackerRecAlgs/TrackCounts/python/TrackCountsConfig.py +++ b/Tracker/TrackerRecAlgs/TrackCounts/python/TrackCountsConfig.py @@ -1,5 +1,5 @@ """ -Copyright (C) 2021 CERN for the benefit of the FASER collaboration + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration """ from AthenaConfiguration.ComponentFactory import CompFactory diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f712d3881883fb0cdff9e8186b5b36578d48bf62 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(TrackSeedPerformanceWriter) + +atlas_add_component( + TrackSeedPerformanceWriter + src/TrackSeedPerformanceWriter.h + src/TrackSeedPerformanceWriter.cxx + src/components/TrackSeedPerformanceWriter_entries.cxx + LINK_LIBRARIES AthenaBaseComps StoreGateLib TrkTrack TrackerSimData TrackerPrepRawData TrkRIO_OnTrack TrackerRIO_OnTrack +) + +atlas_install_python_modules(python/*.py) +atlas_install_scripts(test/*.py) diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..7e064cf0c8a8247426d4f7d613d33e6b8c88626e --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py @@ -0,0 +1,30 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + + +def TrackSeedPerformanceWriterCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + kwargs.setdefault("TrackCollection", "SegmentFit") + TrackSeedPerformanceWriter = CompFactory.Tracker.TrackSeedPerformanceWriter + acc.addEventAlgo(TrackSeedPerformanceWriter(**kwargs)) + + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*" + ] + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST1 DATAFILE='TrackSeedPerformanceWriter.root' OPT='RECREATE'"] + acc.addService(thistSvc) + return acc diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/__init__.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cc0df45c1115acf86eab441652e420953aef8280 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx @@ -0,0 +1,124 @@ +#include "TrackSeedPerformanceWriter.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerIdentifier/FaserSCT_ID.h" + + +namespace Tracker { + + TrackSeedPerformanceWriter::TrackSeedPerformanceWriter(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name), m_idHelper(nullptr){} + + + StatusCode TrackSeedPerformanceWriter::initialize() { + ATH_CHECK(m_trackCollectionKey.initialize()); + ATH_CHECK(m_simDataCollectionKey.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + m_tree = new TTree("tree", "tree"); + m_tree->Branch("run", &m_run, "run/I"); + m_tree->Branch("event", &m_event, "event/I"); + m_tree->Branch("station", &m_station, "station/I"); + m_tree->Branch("chi2", &m_chi2, "chi2/D"); + m_tree->Branch("dof", &m_dof, "dof/I"); + m_tree->Branch("nHits", &m_nHits, "nHits/I"); + m_tree->Branch("x", &m_x, "x/D"); + m_tree->Branch("y", &m_y, "y/D"); + m_tree->Branch("z", &m_z, "z/D"); + m_tree->Branch("px", &m_px, "px/D"); + m_tree->Branch("py", &m_py, "py/D"); + m_tree->Branch("pz", &m_pz, "pz/D"); + // m_tree->Branch("barcode", &m_barcode, "barcode/I"); + m_tree->Branch("barcodes", &m_barcodes); + m_tree->Branch("nMajorityHits", &m_nMajorityHits, "nMajorityHits/I"); + m_tree->Branch("nMajorityParticle", &m_majorityParticle, "nMajorityParticle/I"); + // m_tree->Branch("run", &m_run); + // m_tree->Branch("event", &m_event); + // m_tree->Branch("station", &m_station); + // m_tree->Branch("barcodes", &m_barcodes); + ATH_CHECK(histSvc()->regTree("/HIST1/TrackSeedPerformance", m_tree)); + + return StatusCode::SUCCESS; + } + + + StatusCode TrackSeedPerformanceWriter::execute(const EventContext &ctx) const { + m_run = ctx.eventID().run_number(); + m_event = ctx.eventID().event_number(); + + SG::ReadHandle<TrackCollection> trackCollection{m_trackCollectionKey, ctx}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<TrackerSimDataCollection> simDataCollection {m_simDataCollectionKey, ctx}; + ATH_CHECK(simDataCollection.isValid()); + + for (const Trk::Track *track: *trackCollection) { + m_chi2 = track->fitQuality()->chiSquared(); + m_dof = track->fitQuality()->numberDoF(); + const Amg::Vector3D trackPosition = track->trackParameters()->front()->position(); + const Amg::Vector3D trackMomentum = track->trackParameters()->front()->momentum(); + m_x = trackPosition.x(); + m_y = trackPosition.y(); + m_z = trackPosition.z(); + m_px = trackMomentum.x(); + m_py = trackMomentum.y(); + m_pz = trackMomentum.z(); + m_nHits = track->measurementsOnTrack()->size(); + m_barcodes = {}; + m_hitCounts = {}; + for (const auto meas: *track->measurementsOnTrack()) { + const auto *clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack *>(meas); + if (clusterOnTrack) { + const Tracker::FaserSCT_Cluster *cluster = clusterOnTrack->prepRawData(); + Identifier id = cluster->identify(); + m_barcode = matchHit(id, simDataCollection.get()); + // fill hit map + if (m_hitCounts.count(m_barcode) > 0) { + m_hitCounts[m_barcode] += 1; + } else { + m_hitCounts[m_barcode] = 1; + } + m_barcodes.push_back(m_barcode); + m_station = m_idHelper->station(id); + } + } + + // find majority particle + m_nMajorityHits = 0; + m_majorityParticle = 0; + for (const auto& hit : m_hitCounts) { + if (hit.second > m_nMajorityHits) { + m_majorityParticle = hit.first; + m_nMajorityHits = hit.second; + } + } + m_tree->Fill(); + } + + return StatusCode::SUCCESS; + } + + + StatusCode TrackSeedPerformanceWriter::finalize() { + return StatusCode::SUCCESS; + } + + + int TrackSeedPerformanceWriter::matchHit( + Identifier id, const TrackerSimDataCollection *simDataCollection) const { + int barcode = 0; + if (simDataCollection->count(id) != 0) { + const auto& deposits = simDataCollection->find(id)->second.getdeposits(); + float highestDep = 0; + for (const TrackerSimData::Deposit &deposit : deposits) { + if (deposit.second > highestDep) { + highestDep = deposit.second; + barcode = deposit.first->barcode(); + } + } + } + return barcode; + } + +} // namespace Tracker diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..86192d77c69193ee86b41a2123e42819d27051cc --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h @@ -0,0 +1,61 @@ +#ifndef FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H +#define FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrkTrack/TrackCollection.h" +#include "TrackerSimData/TrackerSimDataCollection.h" + +class TTree; +class FaserSCT_ID; + + +namespace Tracker { + class TrackSeedPerformanceWriter : public AthReentrantAlgorithm, AthHistogramming { + public: + TrackSeedPerformanceWriter(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~TrackSeedPerformanceWriter() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle<ITHistSvc> &histSvc() const; + + private: + int matchHit(Identifier id, const TrackerSimDataCollection *simDataCollection) const; + SG::ReadHandleKey<TrackCollection> m_trackCollectionKey { + this, "TrackCollection", "SegmentFit", "Input track collection name"}; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { + this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + ServiceHandle<ITHistSvc> m_histSvc; + const FaserSCT_ID *m_idHelper; + mutable TTree *m_tree; + + mutable unsigned int m_run; + mutable unsigned int m_event; + mutable unsigned int m_station; + mutable double m_chi2; + mutable int m_dof; + mutable int m_nHits; + mutable double m_x; + mutable double m_y; + mutable double m_z; + mutable double m_px; + mutable double m_py; + mutable double m_pz; + mutable int m_barcode; + mutable int m_majorityParticle; + mutable int m_nMajorityHits; + mutable std::vector<int> m_barcodes; + mutable std::map<int, int> m_hitCounts; + }; + + + inline const ServiceHandle<ITHistSvc> &TrackSeedPerformanceWriter::histSvc() const { + return m_histSvc; + } + +} // namespace Tracker + + +#endif // FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9e569f003a45ef87af33da385a561d3b6a77c95a --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx @@ -0,0 +1,3 @@ +#include "../TrackSeedPerformanceWriter.h" + +DECLARE_COMPONENT(Tracker::TrackSeedPerformanceWriter) diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..b00b9a623561d8b7ef3b57bc0f7bca7e824699c0 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +""" +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from AthenaConfiguration.TestDefaults import defaultTestFiles +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from TrackSeedPerformanceWriter.TrackSeedPerformanceWriterConfig import TrackSeedPerformanceWriterCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "seeds.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = True +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, MaxClusters=20, TanThetaCut=0.1)) +acc.merge(TrackSeedPerformanceWriterCfg(ConfigFlags)) +#acc.getEventAlgo("Tracker::SegmentFitAlg").OutputLevel = DEBUG +acc.getEventAlgo("Tracker::TrackSeedPerformanceWriter").OutputLevel = DEBUG + +sc = acc.run(maxEvents=1000) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackerClusterFit/python/TrackerClusterFitConfig.py b/Tracker/TrackerRecAlgs/TrackerClusterFit/python/TrackerClusterFitConfig.py index 19fb699dae47f023b5a20665461f2cfe3a3510d6..61d1927154c731009a78be77a8c3b2431ae00871 100644 --- a/Tracker/TrackerRecAlgs/TrackerClusterFit/python/TrackerClusterFitConfig.py +++ b/Tracker/TrackerRecAlgs/TrackerClusterFit/python/TrackerClusterFitConfig.py @@ -1,6 +1,5 @@ """Define methods to construct configured SCT Cluster Fit tools and algorithms - -Copyright (C) 2021 CERN for the benefit of the FASER collaboration + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration """ from AthenaConfiguration.ComponentFactory import CompFactory from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg diff --git a/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..62e3b8e58115a157382c1e6b434e35ad0b4cb842 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt @@ -0,0 +1,15 @@ +atlas_subdir(TrackerData) + +atlas_add_component( + TrackerData + src/TrackerSegmentFitDataAlg.h + src/TrackerSegmentFitDataAlg.cxx + src/TrackerTruthDataAlg.h + src/TrackerTruthDataAlg.cxx + src/components/TrackerData_entries.cxx + LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent TrackerIdentifier + TrackerReadoutGeometry TrackerRIO_OnTrack TrackerPrepRawData TrkTrack +) + +atlas_install_python_modules(python/*.py) +atlas_install_scripts(test/*.py) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/TrackerData/README b/Tracker/TrackerRecAlgs/TrackerData/README new file mode 100644 index 0000000000000000000000000000000000000000..5c7cd869e46e21b3f82e68d2d55811f8d5b9b0d9 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/README @@ -0,0 +1,9 @@ +This package can be used to write out the data from simulated hits and from +tracks reconstructed with the TrackerSegmentFit algorithm. + +To write out information for the simulated hits run G4FaserAlgConfigNew_Test.py +to simulate hits and TrackerTruthDbg.py to write out the information. + +To write out information for the tracks run G4FaserAlgConfigNew_Test.py to +simulate hits, FaserSCT_DigitizationDbg.py to digitize them and +TrackerSegmentFitDbg.py to write out the information. \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..cb46c5d7a8b748375ffcdca1178b2aa8ef3bdd3e --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py @@ -0,0 +1,19 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def TrackerSegmentFitDataCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + kwargs.setdefault("TrackCollection", "SegmentFit") + TrackerSegmentFitDataAlg = CompFactory.Tracker.TrackerSegmentFitDataAlg + acc.addEventAlgo(TrackerSegmentFitDataAlg(**kwargs)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST2 DATAFILE='TrackerSegmentFitData.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..206fda5f90eebb94b06f61b2176938daee08c3b6 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py @@ -0,0 +1,19 @@ +""" +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def TrackerTruthDataCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + kwargs.setdefault("FaserSiHitCollection", "SCT_Hits") + TrackerTruthDataAlg = CompFactory.Tracker.TrackerTruthDataAlg + acc.addEventAlgo(TrackerTruthDataAlg(**kwargs)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST1 DATAFILE='TrackerTruthData.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/__init__.py b/Tracker/TrackerRecAlgs/TrackerData/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d6666a34b3ffddd84d8f215ff5f895439862504b --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx @@ -0,0 +1,107 @@ +#include "TrackerSegmentFitDataAlg.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "TrkTrack/Track.h" +#include "TrkTrack/TrackStateOnSurface.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include <TTree.h> + + +namespace Tracker { + +TrackerSegmentFitDataAlg::TrackerSegmentFitDataAlg(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name), m_detMgr(nullptr), m_idHelper(nullptr) {} + + +StatusCode TrackerSegmentFitDataAlg::initialize() { + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(m_trackCollection.initialize()); + + m_tracks = new TTree("tracks", "tracks"); + m_tracks->Branch("run_number", &m_run_number, "run_number/I"); + m_tracks->Branch("event_number", &m_event_number, "event_number/I"); + m_tracks->Branch("chi2", &m_chi2, "chi2/I"); + m_tracks->Branch("dof", &m_nDOF, "dof/I"); + m_tracks->Branch("number_clusters", &m_nClusters, "clusters/I"); + m_tracks->Branch("x", &m_track_x, "x/D"); + m_tracks->Branch("y", &m_track_y, "y/D"); + m_tracks->Branch("z", &m_track_z, "z/D"); + m_tracks->Branch("px", &m_track_px, "px/D"); + m_tracks->Branch("py", &m_track_py, "py/D"); + m_tracks->Branch("pz", &m_track_pz, "pz/D"); + ATH_CHECK(histSvc()->regTree("/HIST2/tracks", m_tracks)); + + m_hits = new TTree("hits", "hits"); + m_hits->Branch("run_number", &m_run_number, "run_number/I"); + m_hits->Branch("event_number", &m_event_number, "event_number/I"); + m_hits->Branch("station", &m_station, "station/I"); + m_hits->Branch("plane", &m_plane, "plane/I"); + m_hits->Branch("module", &m_module, "module/I"); + m_hits->Branch("row", &m_row, "row/I"); + m_hits->Branch("sensor", &m_sensor, "sensor/I"); + m_hits->Branch("x", &m_x, "x/D"); + m_hits->Branch("y", &m_y, "y/D"); + m_hits->Branch("z", &m_z, "z/D"); + ATH_CHECK(histSvc()->regTree("/HIST2/hits", m_hits)); + + return StatusCode::SUCCESS; +} + +StatusCode TrackerSegmentFitDataAlg::execute(const EventContext &ctx) const { + + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + + // Fill tree with clusters from tracker segment fit + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection, ctx}; + ATH_CHECK(trackCollection.isValid()); + + for (const Trk::Track* track : *trackCollection) { + m_chi2 = track->fitQuality()->chiSquared(); + m_nDOF = track->fitQuality()->numberDoF(); + m_nClusters = track->trackParameters()->size() - 1; + auto fitParameters = track->trackParameters()->front(); + const Amg::Vector3D fitPosition = fitParameters->position(); + const Amg::Vector3D fitMomentum = fitParameters->momentum(); + m_track_x = fitPosition.x(); + m_track_y = fitPosition.y(); + m_track_z = fitPosition.z(); + m_track_px = fitMomentum.x(); + m_track_py = fitMomentum.y(); + m_track_pz = fitMomentum.z(); + m_tracks->Fill(); + + for (const Trk::TrackStateOnSurface* trackState : *track->trackStateOnSurfaces()) { + const auto* clusterOnTrack = + dynamic_cast<const FaserSCT_ClusterOnTrack*>(trackState->measurementOnTrack()); + if (!clusterOnTrack) + continue; + const FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + Identifier id = cluster->identify(); + m_station = m_idHelper->station(id); + m_plane = m_idHelper->layer(id); + m_module = m_idHelper->eta_module(id); + m_row = m_idHelper->phi_module(id); + m_sensor = m_idHelper->side(id); + m_strip = m_idHelper->strip(id); + Amg::Vector3D position = cluster->globalPosition(); + m_x = position.x(); + m_y = position.y(); + m_z = position.z(); + m_hits->Fill(); + } + } + + return StatusCode::SUCCESS; +} + + +StatusCode TrackerSegmentFitDataAlg::finalize() { + return StatusCode::SUCCESS; +} + +} // namespace Tracker diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..08ce4dd73290eadadc12c95a24932c5e52a781ea --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2022 CERN for the benefit of the FASER collaboration +*/ + +#ifndef TRACKERDATA_TRACKERSEGMENTFITDATAALG_H +#define TRACKERDATA_TRACKERSEGMENTFITDATAALG_H + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrkTrack/TrackCollection.h" + +class TTree; +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +namespace Tracker { + +class TrackerSegmentFitDataAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + TrackerSegmentFitDataAlg(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~TrackerSegmentFitDataAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + SG::ReadHandleKey<TrackCollection> m_trackCollection {this, "TrackCollection", "SegmentFit", "Input track collection name"}; + + ServiceHandle <ITHistSvc> m_histSvc; + + const TrackerDD::SCT_DetectorManager *m_detMgr; + const FaserSCT_ID *m_idHelper; + + mutable TTree* m_tracks; + mutable TTree* m_hits; + + mutable unsigned int m_run_number; + mutable unsigned int m_event_number; + + mutable double m_chi2; + mutable unsigned int m_nDOF; + mutable unsigned int m_nClusters; + mutable double m_track_x; + mutable double m_track_y; + mutable double m_track_z; + mutable double m_track_px; + mutable double m_track_py; + mutable double m_track_pz; + + mutable unsigned int m_station; + mutable unsigned int m_plane; + mutable unsigned int m_module; + mutable unsigned int m_row; + mutable unsigned int m_sensor; + mutable unsigned int m_strip; + mutable double m_x; + mutable double m_y; + mutable double m_z; +}; + + +inline const ServiceHandle <ITHistSvc> &TrackerSegmentFitDataAlg::histSvc() const { + return m_histSvc; +} + +} // namespace Tracker + +#endif // TRACKERDATA_TRACKERSEGMENTFITDATAALG_H diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0f3c8afe610ce69417d5acb2b1b0680b7f7c5ffc --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx @@ -0,0 +1,123 @@ +#include "TrackerTruthDataAlg.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include <TTree.h> +#include <cmath> + + +namespace Tracker { + +TrackerTruthDataAlg::TrackerTruthDataAlg(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name), m_sct(nullptr), m_sID(nullptr) {} + + +StatusCode TrackerTruthDataAlg::initialize() { + ATH_CHECK(detStore()->retrieve(m_sct, "SCT")); + ATH_CHECK(detStore()->retrieve(m_sID, "FaserSCT_ID")); + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_faserSiHitKey.initialize()); + + m_hits = new TTree("hits", "hits"); + m_hits->Branch("run_number", &m_run_number, "run_number/I"); + m_hits->Branch("event_number", &m_event_number, "event_number/I"); + m_hits->Branch("station", &m_station, "station/I"); + m_hits->Branch("plane", &m_plane, "plane/I"); + m_hits->Branch("module", &m_module, "module/I"); + m_hits->Branch("row", &m_row, "row/I"); + m_hits->Branch("sensor", &m_sensor, "sensor/I"); + m_hits->Branch("pdg", &m_pdg, "pdg/I"); + m_hits->Branch("local_x", &m_local_x, "local_x/D"); + m_hits->Branch("local_y", &m_local_y, "local_y/D"); + m_hits->Branch("global_x", &m_global_x, "global_x/D"); + m_hits->Branch("global_y", &m_global_y, "global_y/D"); + m_hits->Branch("global_z", &m_global_z, "global_z/D"); + m_hits->Branch("phi", &m_phi, "phi/D"); + m_hits->Branch("theta", &m_theta, "theta/D"); + ATH_CHECK(histSvc()->regTree("/HIST1/hits", m_hits)); + + m_particles = new TTree("particles", "particles"); + m_particles->Branch("run_number", &m_run_number, "run_number/I"); + m_particles->Branch("event_number", &m_event_number, "event_number/I"); + m_particles->Branch("pdg", &m_pdg, "pdg/I"); + m_particles->Branch("x", &m_vertex_x, "x/D"); + m_particles->Branch("y", &m_vertex_y, "y/D"); + m_particles->Branch("z", &m_vertex_z, "z/D"); + m_particles->Branch("px", &m_px, "px/D"); + m_particles->Branch("py", &m_py, "py/D"); + m_particles->Branch("pz", &m_pz, "pz/D"); + ATH_CHECK(histSvc()->regTree("/HIST1/particles", m_particles)); + + return StatusCode::SUCCESS; +} + + +StatusCode TrackerTruthDataAlg::execute(const EventContext &ctx) const { + + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + + // Fill tree with simulated particles + SG::ReadHandle<McEventCollection> mcEventCollection(m_mcEventCollectionKey, ctx); + ATH_CHECK(mcEventCollection.isValid()); + for (const HepMC::GenEvent* event : *mcEventCollection) { + for (const HepMC::GenParticle* particle : event->particle_range()) { + m_pdg = particle->pdg_id(); + const auto vertex = particle->production_vertex()->position(); + m_vertex_x = vertex.x(); + m_vertex_y = vertex.y(); + m_vertex_z = vertex.z(); + const HepMC::FourVector& momentum = particle->momentum(); + m_px = momentum.x(); + m_py = momentum.y(); + m_pz = momentum.z(); + m_particles->Fill(); + } + } + + // Fill tree with simulated hits + SG::ReadHandle<FaserSiHitCollection> siHitCollection(m_faserSiHitKey, ctx); + ATH_CHECK(siHitCollection.isValid()); + for (const FaserSiHit &hit: *siHitCollection) { + if (!hit.particleLink().isValid()) + continue; + m_station = hit.getStation(); + m_plane = hit.getPlane(); + m_module = hit.getModule(); + m_row = hit.getRow(); + m_sensor = hit.getSensor(); + Identifier id = m_sID->wafer_id(m_station, m_plane, m_row, m_module, m_sensor); + const TrackerDD::SiDetectorElement *geoelement = m_sct->getDetectorElement(id); + if (!geoelement) + continue; + const auto localStartPos = hit.localStartPosition(); + const HepGeom::Point3D<double> globalStartPos = + Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localStartPos); + const auto localEndPos = hit.localEndPosition(); + const HepGeom::Point3D<double> globalEndPos = + Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localEndPos); + m_pdg = hit.particleLink()->pdg_id(); + HepGeom::Vector3D<double> v = globalEndPos - globalStartPos; + m_phi = std::atan(v.y()/v.x()); + m_theta = std::atan(std::sqrt(v.x() * v.x() + v.y() * v.y())/v.z()); + ATH_MSG_DEBUG("local pos: " << localStartPos); + ATH_MSG_DEBUG("global pos: " << globalStartPos); + m_local_x = m_sensor == 0 ? -localStartPos.y() : localStartPos.y(); + m_local_y = -localStartPos.z(); + m_global_x = globalStartPos.x(); + m_global_y = globalStartPos.y(); + m_global_z = globalStartPos.z(); + m_hits->Fill(); + } + + return StatusCode::SUCCESS; +} + + +StatusCode TrackerTruthDataAlg::finalize() { + return StatusCode::SUCCESS; +} + +} // namespace Tracker diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..6c4f51d2a6f19a44931457b3d91c94b935b0c0a2 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2022 CERN for the benefit of the FASER collaboration +*/ + +#ifndef TRACKERDATA_TRACKERTRUTHDATAALG_H +#define TRACKERDATA_TRACKERTRUTHDATAALG_H + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "GeneratorObjects/McEventCollection.h" + +class TTree; +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +namespace Tracker { + +class TrackerTruthDataAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + TrackerTruthDataAlg(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~TrackerTruthDataAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "BeamTruthEvent"}; + SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey{this, "FaserSiHitCollection", "SCT_Hits"}; + + ServiceHandle <ITHistSvc> m_histSvc; + + const TrackerDD::SCT_DetectorManager *m_sct; + const FaserSCT_ID *m_sID; + + mutable TTree *m_particles; + mutable TTree *m_hits; + + mutable unsigned int m_run_number; + mutable unsigned int m_event_number; + mutable unsigned int m_station; + mutable unsigned int m_plane; + mutable unsigned int m_module; + mutable unsigned int m_row; + mutable unsigned int m_sensor; + mutable int m_pdg; + mutable double m_local_x; + mutable double m_local_y; + mutable double m_global_x; + mutable double m_global_y; + mutable double m_global_z; + mutable double m_vertex_x; + mutable double m_vertex_y; + mutable double m_vertex_z; + mutable double m_px; + mutable double m_py; + mutable double m_pz; + mutable double m_phi; + mutable double m_theta; +}; + + +inline const ServiceHandle <ITHistSvc> &TrackerTruthDataAlg::histSvc() const { + return m_histSvc; +} + +} // namespace Tracker + +#endif // TRACKERDATA_TRACKERTRUTHDATAALG_H diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..01018d29702f995ccf656c466989a2d06a74e30a --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx @@ -0,0 +1,5 @@ +#include "../TrackerTruthDataAlg.h" +#include "../TrackerSegmentFitDataAlg.h" + +DECLARE_COMPONENT(Tracker::TrackerTruthDataAlg ) +DECLARE_COMPONENT(Tracker::TrackerSegmentFitDataAlg) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..b20d313f99654d07487651c645616b93a266789f --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +"""" +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from TrackerData.TrackerSegmentFitDataConfig import TrackerSegmentFitDataCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['/home/tboeckh/tmp/Faser-Physics-006470-00093.raw_middleStation.SPs'] +ConfigFlags.Output.ESDFileName = "TrackerSegmentFitData.ESD.pool.root" +ConfigFlags.addFlag("Output.xAODFileName", f"TrackerSegmentFitData_xAOD.root") +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASER-02" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, name="LevelClustering", DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X")) +acc.merge(SegmentFitAlgCfg(ConfigFlags, name=f"LevelFit", MaxClusters=44)) +acc.merge(TrackerSegmentFitDataCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::TrackerSegmentFitDataAlg").OutputLevel = DEBUG +itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*" + ] +acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) + +replicaSvc = acc.getService("DBReplicaSvc") +replicaSvc.COOLSQLiteVetoPattern = "" +replicaSvc.UseCOOLSQLite = True +replicaSvc.UseCOOLFrontier = False +replicaSvc.UseGeomSQLite = True + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..bac4dd4035a48d731d77cdc98af54fd649f73948 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +"""" +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from TrackerData.TrackerSegmentFitDataConfig import TrackerSegmentFitDataCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ["my.RDO.pool.root"] +ConfigFlags.Output.ESDFileName = "TrackerSegmentFitData.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data22" +ConfigFlags.Input.isMC = True +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.addFlag("Output.xAODFileName", f"TrackerSegmentFitData_xAOD.root") +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) + +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_RDOs")) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.5, MinClustersPerFit=5, TanThetaCut=0.25)) +acc.merge(TrackerSegmentFitDataCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::TrackerSegmentFitDataAlg").OutputLevel = DEBUG +itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*" + ] +acc.merge(OutputStreamCfg(ConfigFlags, "ESD", itemList)) + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..a6b366d6ba9543d4bba4f87384d25b0e9b756603 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""" +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from TrackerData.TrackerTruthDataConfig import TrackerTruthDataCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ["my.HITS.pool.root"] +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data22" +ConfigFlags.Input.isMC = True +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +# Core components +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) + +acc.merge(TrackerTruthDataCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::TrackerTruthDataAlg").OutputLevel = DEBUG + +# Execute and finish +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py index 8a620210bdcf8ef20d9d505770da6c4581e0293b..820cc73c5976089bea53e5fe2def1f87967837a9 100644 --- a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py +++ b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py @@ -65,5 +65,6 @@ def FaserSCT_OutputCfg(flags): def FaserSCT_ClusterizationCfg(flags, **kwargs): """Return ComponentAccumulator for SCT Clusterization and Output""" acc = FaserSCT_ClusterizationBasicCfg(flags, **kwargs) - acc.merge(FaserSCT_OutputCfg(flags)) + if flags.Output.doWriteESD: + acc.merge(FaserSCT_OutputCfg(flags)) return acc diff --git a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx index 6902a70138cdad5f8957f0f7e0886d36e6d8213e..e78f7a8c5b72a0ad06d4b360388b3a35f995392b 100755 --- a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx +++ b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2021 ChRN for the benefit of the ATLAS collaboration - */ + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ /*************************************************************************** ------------------- diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/python/TrackerSegmentFitConfig.py b/Tracker/TrackerRecAlgs/TrackerSegmentFit/python/TrackerSegmentFitConfig.py index 1ac1f94d55b030b729a1fc1f000142f275d127fb..f0de1582f2ccf47270203d4d1d6eb9a6bca341e9 100644 --- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/python/TrackerSegmentFitConfig.py +++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/python/TrackerSegmentFitConfig.py @@ -1,6 +1,5 @@ """Define methods to construct configured SCT Cluster Fit tools and algorithms - -Copyright (C) 2021 CERN for the benefit of the FASER collaboration +Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration """ from AthenaConfiguration.ComponentFactory import CompFactory from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx index ff163e105d51b02267ce35e3fdfe43737c5a184c..2481c6f2eeb0109ac08c55a6e133e341e6645268 100644 --- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx +++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx @@ -408,6 +408,7 @@ SegmentFitAlg::checkFit(const Tracker::SegmentFitAlg::fitInfo& seed) const return false; } if (m_tanThetaCut > 0.0 && pow(seed.fitParams(2),2.0) + pow(seed.fitParams(3), 2.0) > m_tanThetaCut * m_tanThetaCut) return false; + if (m_tanThetaXZCut > 0.0 && pow(seed.fitParams(2), 2.0) > m_tanThetaXZCut * m_tanThetaXZCut) return false; for (auto i : seed.candidates) { double z = seed.clusters[i]->cluster.globalPosition().z(); @@ -507,16 +508,19 @@ SegmentFitAlg::selectFits(const FitMap& fits) const auto content = *it; ATH_MSG_VERBOSE("clusters: " << content->clusterMask.count() << " / chi2: " << content->fitChi2) ; } - ClusterSet usedClusters { clusterInfo::nClusters }; while (info.size() > 0) { auto selected = info.front(); ATH_MSG_VERBOSE("Selected nclust = " << selected->clusterMask.count() << " with chi2 = " << selected->fitChi2); selectedFits[selected->clusterMask] = selected; - usedClusters |= selected->clusterMask; - info.remove_if([&](std::shared_ptr<fitInfo> p) {return (p->clusterMask & ~usedClusters) != p->clusterMask;}); + // remove fits for which the fraction of shared hits is larger than m_sharedFraction or the number of hits is + // smaller than m_minClustersPerFit + info.remove_if([&](std::shared_ptr<fitInfo> p) {return + ((p->clusterMask & selected->clusterMask).count() > m_sharedHitFraction * p->clusterMask.count()) + || ((selectedFits.size() >= 4) && (p->clusterMask.count() < m_minClustersPerFit)) ;} + ); } m_numberOfSelectedFits += selectedFits.size(); diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h index eb41946cd0a9094a24919eaf6824705094afa234..068e1eeab0f2280d38227fd6d3c376c0ffb49e18 100644 --- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h +++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h @@ -413,7 +413,10 @@ class SegmentFitAlg : public AthReentrantAlgorithm DoubleProperty m_waferTolerance { this, "WaferTolerance", 3 * Gaudi::Units::mm, "Wafer boundary tolerance for extrapolated fit." }; DoubleProperty m_yResidualCut { this, "ResidualCut", 3 * Gaudi::Units::mm, "Cluster y tolerance for compatibility with extrapolated fit." }; DoubleProperty m_tanThetaCut { this, "TanThetaCut", 0.0, "Maximum accepted tangent of track angle from beam axis; 0 means no cut."}; + DoubleProperty m_tanThetaXZCut { this, "TanThetaXZCut", 0.0, "Maximum accepted tangent of track angle from beam axis in x direction; 0 means no cut."}; DoubleProperty m_reducedChi2Cut { this, "ReducedChi2Cut", 10.0, "Maximum accepted chi^2 per degree of freedom for final fits; 0 means no cut." }; + DoubleProperty m_sharedHitFraction { this, "SharedHitFraction", -1., "Fraction of hits which are allowed to be shared between two fits." }; + UnsignedIntegerProperty m_minClustersPerFit { this, "MinClustersPerFit", 4, "Minimum number of clusters a fit has to have." }; mutable std::atomic<int> m_numberOfEvents{0}; mutable std::atomic<int> m_numberExcessOccupancy{0}; diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py new file mode 100644 index 0000000000000000000000000000000000000000..05d4be97bc18d8598512b8a22a79f8cdf6436af7 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +"""Test various ComponentAccumulator Digitization configuration modules + +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from AthenaConfiguration.TestDefaults import defaultTestFiles +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +#from Digitization.DigitizationParametersConfig import writeDigitizationMetadata +from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +#from MCTruthSimAlgs.RecoTimingConfig import MergeRecoTimingObjCfg + +# Set up logging and new style config +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +# Configure +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "segmentFit.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = True +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.addFlag("Output.xAODFileName", "segmentFit.xAOD.pool.root") +# ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +# Core components +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) + +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags)) +#acc.getEventAlgo("Tracker::SegmentFitAlg").OutputLevel = DEBUG + +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*" + ] +acc.merge(OutputStreamCfg(ConfigFlags, "ESD", itemList)) + +# Dump config +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = INFO +# acc.getCondAlgo("FaserSCT_AlignCondAlg").OutputLevel = VERBOSE +# acc.getCondAlgo("FaserSCT_DetectorElementCondAlg").OutputLevel = VERBOSE +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +# Execute and finish +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b52a694c458489bb341116be7568c18ffd9de8e6 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(TrackerTruth) + +atlas_add_component( + TrackerTruth + src/TrackerTruthAlg.h + src/TrackerTruthAlg.cxx + src/components/TrackerTruth_entries.cxx + LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent TrackerIdentifier TrackerReadoutGeometry +) + +atlas_install_python_modules( python/*.py ) +atlas_install_scripts( test/*.py ) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe b/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe new file mode 100644 index 0000000000000000000000000000000000000000..a763932b380cc4982774d5e409328dadea867411 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe @@ -0,0 +1,6 @@ +This package can be used to write out the truth information of particles and hits from MC generated events. +For particles the run number, event number, pdg code, vertex and momentum is written out and for hits the +run number, event number, station, plane, module, row, sensor, local position, global position and pdg code of the +corresponding particle is written out. + +To write out truth information generate MC data using the G4FaserAlgConfigNew_Test.py and run TrackerTruthDbg.py diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py b/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..92f56a8edc34c173636f16fb9162c8ab17d8850f --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py @@ -0,0 +1,19 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg + + +def TrackerTruthCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + kwargs.setdefault("FaserSiHitCollection", "SCT_Hits") + TrackerTruthAlg = CompFactory.Tracker.TrackerTruthAlg + acc.addEventAlgo(TrackerTruthAlg(**kwargs)) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST1 DATAFILE='TrackerTruth.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/python/__init__.py b/Tracker/TrackerRecAlgs/TrackerTruth/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..84249c0cc4e2bde1dd54bf7192f0fbc67295c189 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx @@ -0,0 +1,112 @@ +#include "TrackerTruthAlg.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include <TTree.h> + + +namespace Tracker { + +TrackerTruthAlg::TrackerTruthAlg(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name), m_sct(nullptr), m_sID(nullptr) {} + + +StatusCode TrackerTruthAlg::initialize() { + ATH_CHECK(detStore()->retrieve(m_sct, "SCT")); + ATH_CHECK(detStore()->retrieve(m_sID, "FaserSCT_ID")); + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_faserSiHitKey.initialize()); + + m_hits = new TTree("hits", "hits"); + m_hits->Branch("run_number", &m_run_number, "run_number/I"); + m_hits->Branch("event_number", &m_event_number, "event_number/I"); + m_hits->Branch("station", &m_station, "station/I"); + m_hits->Branch("plane", &m_plane, "plane/I"); + m_hits->Branch("module", &m_module, "module/I"); + m_hits->Branch("row", &m_row, "row/I"); + m_hits->Branch("sensor", &m_sensor, "sensor/I"); + m_hits->Branch("pdg", &m_pdg, "pdg/I"); + m_hits->Branch("local_x", &m_local_x, "local_x/D"); + m_hits->Branch("local_y", &m_local_y, "local_y/D"); + m_hits->Branch("global_x", &m_global_x, "global_x/D"); + m_hits->Branch("global_y", &m_global_y, "global_y/D"); + m_hits->Branch("global_z", &m_global_z, "global_z/D"); + ATH_CHECK(histSvc()->regTree("/HIST1/hits", m_hits)); + + m_particles = new TTree("particles", "particles"); + m_particles->Branch("run_number", &m_run_number, "run_number/I"); + m_particles->Branch("event_number", &m_event_number, "event_number/I"); + m_particles->Branch("pdg", &m_pdg, "pdg/I"); + m_particles->Branch("x", &m_vertex_x, "x/D"); + m_particles->Branch("y", &m_vertex_y, "y/D"); + m_particles->Branch("z", &m_vertex_z, "z/D"); + m_particles->Branch("px", &m_px, "px/D"); + m_particles->Branch("py", &m_px, "py/D"); + m_particles->Branch("pz", &m_px, "pz/D"); + ATH_CHECK(histSvc()->regTree("/HIST1/particles", m_particles)); + + return StatusCode::SUCCESS; +} + + +StatusCode TrackerTruthAlg::execute(const EventContext &ctx) const { + + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + + // Fill tree with simulated particles + SG::ReadHandle<McEventCollection> mcEventCollection(m_mcEventCollectionKey, ctx); + ATH_CHECK(mcEventCollection.isValid()); + for (const HepMC::GenEvent* event : *mcEventCollection) { + for (const HepMC::GenParticle* particle : event->particle_range()) { + m_pdg = particle->pdg_id(); + const auto vertex = particle->production_vertex()->position(); + m_vertex_x = vertex.x(); + m_vertex_y = vertex.y(); + m_vertex_z = vertex.z(); + const HepMC::FourVector& momentum = particle->momentum(); + m_px = momentum.x(); + m_py = momentum.y(); + m_pz = momentum.z(); + m_particles->Fill(); + } + } + + // Fill tree with simulated hits + SG::ReadHandle<FaserSiHitCollection> siHitCollection(m_faserSiHitKey, ctx); + ATH_CHECK(siHitCollection.isValid()); + for (const FaserSiHit &hit: *siHitCollection) { + if (!hit.particleLink().isValid()) + continue; + const HepGeom::Point3D<double> localStartPos = hit.localStartPosition(); + Identifier id = m_sID->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor()); + const TrackerDD::SiDetectorElement *geoelement = m_sct->getDetectorElement(id); + if (!geoelement) + continue; + const HepGeom::Point3D<double> globalStartPos = + Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localStartPos); + m_station = hit.getStation(); + m_plane = hit.getPlane(); + m_module = hit.getModule(); + m_row = hit.getRow(); + m_sensor = hit.getSensor(); + m_pdg = hit.particleLink()->pdg_id(); + m_local_x = localStartPos.x(); + m_local_y = localStartPos.y(); + m_global_x = globalStartPos.x(); + m_global_y = globalStartPos.y(); + m_global_z = globalStartPos.z(); + m_hits->Fill(); + } + + return StatusCode::SUCCESS; +} + + +StatusCode TrackerTruthAlg::finalize() { + return StatusCode::SUCCESS; +} + +} // namespace Tracker diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..7f21acc718500b5881bdb4956980fc1893c80747 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2022 CERN for the benefit of the FASER collaboration +*/ + +#ifndef TRACKERTRUTH_TRACKERTRUTHALG_H +#define TRACKERTRUTH_TRACKERTRUTHALG_H + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "GeneratorObjects/McEventCollection.h" + +class TTree; +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +namespace Tracker { + +class TrackerTruthAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + TrackerTruthAlg(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~TrackerTruthAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "BeamTruthEvent"}; + SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey{this, "FaserSiHitCollection", "SCT_Hits"}; + + ServiceHandle <ITHistSvc> m_histSvc; + + const TrackerDD::SCT_DetectorManager *m_sct; + const FaserSCT_ID *m_sID; + + mutable TTree *m_particles; + mutable TTree *m_hits; + + mutable unsigned int m_run_number; + mutable unsigned int m_event_number; + mutable unsigned int m_station; + mutable unsigned int m_plane; + mutable unsigned int m_module; + mutable unsigned int m_row; + mutable unsigned int m_sensor; + mutable int m_pdg; + mutable double m_local_x; + mutable double m_local_y; + mutable double m_global_x; + mutable double m_global_y; + mutable double m_global_z; + mutable double m_vertex_x; + mutable double m_vertex_y; + mutable double m_vertex_z; + mutable double m_px; + mutable double m_py; + mutable double m_pz; +}; + + +inline const ServiceHandle <ITHistSvc> &TrackerTruthAlg::histSvc() const { + return m_histSvc; +} + +} // namespace Tracker + +#endif diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx b/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0f49f0e7edefeccc3908ebc6822928ad08abbe7c --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx @@ -0,0 +1,3 @@ +#include "../TrackerTruthAlg.h" + +DECLARE_COMPONENT(Tracker::TrackerTruthAlg ) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py b/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..479edc81bb284720c94ef4b16196a5aa7ac0f5d3 --- /dev/null +++ b/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""" +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +import sys +from AthenaCommon.Logging import log +from AthenaCommon.Constants import DEBUG +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from TrackerTruth.TrackerTruthConfig import TrackerTruthCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ["my.HITS.pool.root"] +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data22" +ConfigFlags.Input.isMC = True +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +# Core components +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) + +acc.merge(TrackerTruthCfg(ConfigFlags)) +acc.getEventAlgo("Tracker::TrackerTruthAlg").OutputLevel = DEBUG + +# Execute and finish +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx index d23327e1c5b6c8d59bcf7e41e7a9dbf58ca164bf..f0a7b64cd20c02d0e13a5357b9fe3f05f36f6f5a 100755 --- a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx +++ b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx @@ -113,10 +113,10 @@ namespace Tracker ATH_CHECK( m_faserSiHitKey.initialize() ); ATH_CHECK( m_faserRdoKey.initialize()); ATH_CHECK( m_sctMap.initialize()); - ATH_MSG_INFO( "Using GenEvent collection with key " << m_mcEventKey.key()); - ATH_MSG_INFO( "Using Faser SiHit collection with key " << m_faserSiHitKey.key()); - ATH_MSG_INFO( "Using FaserSCT RDO Container with key " << m_faserRdoKey.key()); - ATH_MSG_INFO( "Using SCT_SDO_Map with key "<< m_sctMap.key()); + ATH_MSG_DEBUG( "Using GenEvent collection with key " << m_mcEventKey.key()); + ATH_MSG_DEBUG( "Using Faser SiHit collection with key " << m_faserSiHitKey.key()); + ATH_MSG_DEBUG( "Using FaserSCT RDO Container with key " << m_faserRdoKey.key()); + ATH_MSG_DEBUG( "Using SCT_SDO_Map with key "<< m_sctMap.key()); m_hist_n=new TH1D("sp_n","sp_n",20,0,20); m_hist_x=new TH1D("sp_x","sp_x",100,-200,200); @@ -180,7 +180,7 @@ namespace Tracker CHECK(m_thistSvc->regHist("/TruthTrackSeeds/sp/InitReso_py",m_hist_InitReso_py)); CHECK(m_thistSvc->regHist("/TruthTrackSeeds/sp/InitReso_pz",m_hist_InitReso_pz)); //!!!!!!!!!!!!!!!!!!!! - ATH_MSG_INFO( "TruthTrackSeeds::initialized" ); + ATH_MSG_DEBUG( "TruthTrackSeeds::initialized" ); return StatusCode::SUCCESS; } @@ -194,11 +194,11 @@ namespace Tracker // Handles created from handle keys behave like pointers to the corresponding container SG::ReadHandle<McEventCollection> h_mcEvents(m_mcEventKey, ctx); - ATH_MSG_INFO("Read McEventContainer with " << h_mcEvents->size() << " events"); + ATH_MSG_DEBUG("Read McEventContainer with " << h_mcEvents->size() << " events"); if (h_mcEvents->size() == 0) return StatusCode::FAILURE; SG::ReadHandle<FaserSiHitCollection> h_siHits(m_faserSiHitKey, ctx); - ATH_MSG_INFO("Read FaserSiHitCollection with " << h_siHits->size() << " hits"); + ATH_MSG_DEBUG("Read FaserSiHitCollection with " << h_siHits->size() << " hits"); SG::ReadHandle<FaserSCT_RDO_Container> h_sctRDO(m_faserRdoKey, ctx); @@ -206,7 +206,7 @@ namespace Tracker SG::WriteHandle<SpacePointForSeedCollection> seedContainer_SCT(m_seed_spcontainerKey, ctx ); ATH_CHECK( seedContainer_SCT.record( std::make_unique<SpacePointForSeedCollection>() ) ); - ATH_MSG_INFO("Created SpacePointContainer " << m_seed_spcontainerKey.key() << " N= " << m_idHelper->wafer_hash_max()); + ATH_MSG_DEBUG("Created SpacePointContainer " << m_seed_spcontainerKey.key() << " N= " << m_idHelper->wafer_hash_max()); const TrackerDD::SiDetectorElementCollection* elements = nullptr; @@ -288,12 +288,12 @@ namespace Tracker SG::ReadHandle<TrackerSimDataCollection> h_collectionMap(m_sctMap, ctx); ATH_MSG_DEBUG("map size "<<h_collectionMap->size()); //!!!!!!!!!!!!!!!!!!!! - std::cout<<"!!!!!!!!! cluster: "<<sp->clusterList().first<<std::endl; +// std::cout<<"!!!!!!!!! cluster: "<<sp->clusterList().first<<std::endl; ATH_MSG_DEBUG("!!!!!!!!! cluster: "<<sp->clusterList().first->rdoList() ); //!!!!!!!!!!!!!!!!!!!! if( h_collectionMap->count(identifier) == 0) { - ATH_MSG_INFO("no map found w/identifier "<<identifier); + ATH_MSG_DEBUG("no map found w/identifier "<<identifier); ++m_numberOfNoMap; continue; } @@ -309,14 +309,14 @@ namespace Tracker for( const auto& depositPair : deposits) { //!!!!!!!!!!!!!!!!!!!!!!!! - depositPair.first->print(std::cout); - std::cout<<"!!!!!!!!!!! pdg id = "<<depositPair.first->pdg_id()<<std::endl; +// depositPair.first->print(std::cout); +// std::cout<<"!!!!!!!!!!! pdg id = "<<depositPair.first->pdg_id()<<std::endl; if (depositPair.first->pdg_id() == -13) { - HepMC::FourVector pv = depositPair.first->production_vertex()->position(); - HepMC::FourVector ev = depositPair.first->end_vertex()->position (); + // HepMC::FourVector pv = depositPair.first->production_vertex()->position(); + // HepMC::FourVector ev = depositPair.first->end_vertex()->position (); truthmom = depositPair.first->momentum(); - std::cout<<"!!!!!!!!!!! production_vertex: ( "<<pv.x()<<", "<<pv.y()<<", "<<pv.z()<<" ) "<<std::endl; - std::cout<<"!!!!!!!!!!! end_vertex: ( "<<ev.x()<<", "<<ev.y()<<", "<<ev.z()<<" ) "<<std::endl; + // std::cout<<"!!!!!!!!!!! production_vertex: ( "<<pv.x()<<", "<<pv.y()<<", "<<pv.z()<<" ) "<<std::endl; + // std::cout<<"!!!!!!!!!!! end_vertex: ( "<<ev.x()<<", "<<ev.y()<<", "<<ev.z()<<" ) "<<std::endl; } //!!!!!!!!!!!!!!!!!!!!!!!! if( depositPair.second > highestDep) @@ -338,14 +338,14 @@ namespace Tracker for (auto daughter : primary->particles_out()) { // TODO: Check that daughter->production_vertex() and daughter->end_vertex() exist, and bracket the point you're interested in - if (daughter->barcode() % 1000000 == primary->barcode()) { - ATH_MSG_INFO(" daughter barcode: " << daughter->barcode() << " with energy " << daughter->momentum().e() << " px = " << daughter->momentum().px() << " py = " << daughter->momentum().py() << " pz = " << daughter->momentum().pz() ); - if (daughter->production_vertex() != nullptr && daughter->end_vertex() != nullptr) { - HepMC::FourVector pv = daughter->production_vertex()->position(); - HepMC::FourVector ev = daughter->end_vertex()->position (); - std::cout<<"!!!!!!!!!!! production_vertex: ( "<<pv.x()<<", "<<pv.y()<<", "<<pv.z()<<" ) "<<std::endl; - std::cout<<"!!!!!!!!!!! end_vertex: ( "<<ev.x()<<", "<<ev.y()<<", "<<ev.z()<<" ) "<<std::endl; - } + if (daughter->barcode() % 1000000 == primary->barcode()) { + ATH_MSG_DEBUG(" daughter barcode: " << daughter->barcode() << " with energy " << daughter->momentum().e() << " px = " << daughter->momentum().px() << " py = " << daughter->momentum().py() << " pz = " << daughter->momentum().pz() ); + // if (daughter->production_vertex() != nullptr && daughter->end_vertex() != nullptr) { + // HepMC::FourVector pv = daughter->production_vertex()->position(); + // HepMC::FourVector ev = daughter->end_vertex()->position (); + // std::cout<<"!!!!!!!!!!! production_vertex: ( "<<pv.x()<<", "<<pv.y()<<", "<<pv.z()<<" ) "<<std::endl; + // std::cout<<"!!!!!!!!!!! end_vertex: ( "<<ev.x()<<", "<<ev.y()<<", "<<ev.z()<<" ) "<<std::endl; + // } } } } @@ -387,8 +387,8 @@ namespace Tracker m_lp_end=hit.localEndPosition(); m_new_pos=m_lp_start+(m_lp_end-m_lp_start)*m_ran_pos; //muPos=Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_new_pos); - std::cout<<"!!!!!!!!!!! hit start pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_start)<<std::endl; - std::cout<<"!!!!!!!!!!! hit end pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_end)<<std::endl; +// std::cout<<"!!!!!!!!!!! hit start pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_start)<<std::endl; +// std::cout<<"!!!!!!!!!!! hit end pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_end)<<std::endl; } //!!!!!!!!!!!!!!!!!!!!!!!! } @@ -430,8 +430,8 @@ namespace Tracker if (istation==2 && ilayer==0) { match_N_2_0++; } if (istation==2 && ilayer==1) { match_N_2_1++; } if (istation==2 && ilayer==2) { match_N_2_2++; } - std::cout<<"!!!!!!!!!!! (station, layer) = ("<<istation<<", "<<ilayer<<") positopn = ("<<gloPos.x()<<", "<<gloPos.y()<<", "<<gloPos.z()<<") "<<std::endl; - if (std::fabs(gloPos.x())>100) std::cout<<"!!!!!!!!!!! badXXX "<<std::endl; +// std::cout<<"!!!!!!!!!!! (station, layer) = ("<<istation<<", "<<ilayer<<") positopn = ("<<gloPos.x()<<", "<<gloPos.y()<<", "<<gloPos.z()<<") "<<std::endl; +// if (std::fabs(gloPos.x())>100) std::cout<<"!!!!!!!!!!! badXXX "<<std::endl; //!!!!!!!!!!!!!!!!!!!! } ATH_MSG_VERBOSE( nReceivedSPSCT << " SpacePoints successfully added to Container !" ); @@ -441,8 +441,8 @@ namespace Tracker m_hist_n->Fill(nTruthSP); //!!!!!!!!!!!!!!!!!!!!!!!! - std::cout<<"!!!!!!!!!!! N_1_0 = "<<N_1_0<<", N_1_1 = "<<N_1_1<<", N_1_2 = "<<N_1_2<<", N_2_0 = "<<N_2_0<<", N_2_1 = "<<N_2_1<<", N_2_2 = "<<N_2_2<<std::endl; - std::cout<<"!!!!!!!!!!! match_N_1_0 = "<<match_N_1_0<<", match_N_1_1 = "<<match_N_1_1<<", match_N_1_2 = "<<match_N_1_2<<", match_N_2_0 = "<<match_N_2_0<<", match_N_2_1 = "<<match_N_2_1<<", match_N_2_2 = "<<match_N_2_2<<std::endl; +// std::cout<<"!!!!!!!!!!! N_1_0 = "<<N_1_0<<", N_1_1 = "<<N_1_1<<", N_1_2 = "<<N_1_2<<", N_2_0 = "<<N_2_0<<", N_2_1 = "<<N_2_1<<", N_2_2 = "<<N_2_2<<std::endl; +// std::cout<<"!!!!!!!!!!! match_N_1_0 = "<<match_N_1_0<<", match_N_1_1 = "<<match_N_1_1<<", match_N_1_2 = "<<match_N_1_2<<", match_N_2_0 = "<<match_N_2_0<<", match_N_2_1 = "<<match_N_2_1<<", match_N_2_2 = "<<match_N_2_2<<std::endl; if ( (N_1_0==1 && match_N_1_0==1) && (N_1_1==1 && match_N_1_1==1) && (N_1_2==1 && match_N_1_2==1) && (N_2_0==1 && match_N_2_0==1) && (N_2_1==1 && match_N_2_1==1) && (N_2_2==1 && match_N_2_2==1)) { Acts::Vector3 pos1_0(0., 0., 0.); Acts::Vector3 pos1_1(0., 0., 0.); @@ -482,12 +482,12 @@ namespace Tracker } } - std::cout<<"!!!!!!!!!!! pos1_0 = ("<<pos1_0.x()<<", "<<pos1_0.y()<<", "<<pos1_0.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos1_1 = ("<<pos1_1.x()<<", "<<pos1_1.y()<<", "<<pos1_1.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos1_2 = ("<<pos1_2.x()<<", "<<pos1_2.y()<<", "<<pos1_2.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_0 = ("<<pos2_0.x()<<", "<<pos2_0.y()<<", "<<pos2_0.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_1 = ("<<pos2_1.x()<<", "<<pos2_1.y()<<", "<<pos2_1.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_2 = ("<<pos2_2.x()<<", "<<pos2_2.y()<<", "<<pos2_2.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos1_0 = ("<<pos1_0.x()<<", "<<pos1_0.y()<<", "<<pos1_0.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos1_1 = ("<<pos1_1.x()<<", "<<pos1_1.y()<<", "<<pos1_1.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos1_2 = ("<<pos1_2.x()<<", "<<pos1_2.y()<<", "<<pos1_2.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos2_0 = ("<<pos2_0.x()<<", "<<pos2_0.y()<<", "<<pos2_0.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos2_1 = ("<<pos2_1.x()<<", "<<pos2_1.y()<<", "<<pos2_1.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! pos2_2 = ("<<pos2_2.x()<<", "<<pos2_2.y()<<", "<<pos2_2.z()<<") "<<std::endl; double charge = 1; double B = 0.57; @@ -527,21 +527,21 @@ namespace Tracker // the direction of momentum in the first station Acts::Vector3 direct1 = d1.normalized(); - std::cout<<"!!!!!!!!!!! direct1 = ("<<direct1.x()<<", "<<direct1.y()<<", "<<direct1.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! direct1 = ("<<direct1.x()<<", "<<direct1.y()<<", "<<direct1.z()<<") "<<std::endl; // the direction of momentum in the second station Acts::Vector3 direct2 = d2.normalized(); - std::cout<<"!!!!!!!!!!! direct2 = ("<<direct2.x()<<", "<<direct2.y()<<", "<<direct2.z()<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! direct2 = ("<<direct2.x()<<", "<<direct2.y()<<", "<<direct2.z()<<") "<<std::endl; // the vector pointing from the center of circle to the particle at layer 2 in Y-Z plane double R1_z = charge * direct1.y() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - double R1_y = -charge * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - std::cout<<"!!!!!!!!!!! (R1_y, R1_z) = ("<<R1_y<<", "<<R1_z<<") "<<std::endl; + // double R1_y = -charge * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); +// std::cout<<"!!!!!!!!!!! (R1_y, R1_z) = ("<<R1_y<<", "<<R1_z<<") "<<std::endl; // the vector pointing from the center of circle to the particle at layer 3 in Y-Z plane double R2_z = charge * direct2.y() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z()); - double R2_y = -charge * direct2.z() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z()); - std::cout<<"!!!!!!!!!!! (R2_y, R2_z) = ("<<R2_y<<", "<<R2_z<<") "<<std::endl; + // double R2_y = -charge * direct2.z() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z()); +// std::cout<<"!!!!!!!!!!! (R2_y, R2_z) = ("<<R2_y<<", "<<R2_z<<") "<<std::endl; // the norm of radius double R = (pos2_0.z() - pos1_2.z()) / (R2_z - R1_z); - std::cout<<"!!!!!!!!!!! R = "<<R<<std::endl; +// std::cout<<"!!!!!!!!!!! R = "<<R<<std::endl; // the norm of momentum in Y-Z plane double p_yz = 0.3*B*R / 1000.0; // R(mm), p(GeV), B(T) double p_z = p_yz * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); @@ -549,9 +549,9 @@ namespace Tracker double p_x = direct1.x() * p_z / direct1.z(); // total momentum at the layer 0 const Acts::Vector3 mom(p_x, p_y, p_z); - double p = mom.norm(); - std::cout<<"!!!!!!!!!!! InitTrack momentum on layer 0: ( "<<mom.x()*1000<<", "<<mom.y()*1000<<", "<<mom.z()*1000<<", "<<p*1000<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! truth momentum: ( "<<truthmom.px()<<", "<<truthmom.py()<<", "<<truthmom.pz()<<", "<<truthmom.m()<<" ) "<<std::endl; + // double p = mom.norm(); +// std::cout<<"!!!!!!!!!!! InitTrack momentum on layer 0: ( "<<mom.x()*1000<<", "<<mom.y()*1000<<", "<<mom.z()*1000<<", "<<p*1000<<") "<<std::endl; +// std::cout<<"!!!!!!!!!!! truth momentum: ( "<<truthmom.px()<<", "<<truthmom.py()<<", "<<truthmom.pz()<<", "<<truthmom.m()<<" ) "<<std::endl; if ((p_x*1000 - truthmom.px()) / std::fabs(truthmom.px()) < -10) m_hist_InitReso_px->Fill( -9.5 ); else if ((p_x*1000 - truthmom.px()) / std::fabs(truthmom.px()) > 10) m_hist_InitReso_px->Fill( 9.5 ); @@ -593,15 +593,15 @@ namespace Tracker //--------------------------------------------------------------------------- StatusCode TruthSeededTrackFinder::finalize() { - ATH_MSG_INFO( "Finalizing" ); - ATH_MSG_INFO( m_numberOfEvents << " events processed" ); - ATH_MSG_INFO( m_numberOfSPCollection << " spacepoint collections processed" ); - ATH_MSG_INFO( m_numberOfEmptySPCollection<< " spacepoint collections empty" ); - ATH_MSG_INFO( m_numberOfSP<< " sct SP collections processed" ); - ATH_MSG_INFO( m_numberOfNoMap<< " not maped spacepoint" ); - ATH_MSG_INFO( m_numberOfHits<< " sim hits" ); - ATH_MSG_INFO( m_numberOfMatchSP<< " matched spacepoint" ); - ATH_MSG_INFO( m_numberOfFills<< " spacepoint saved" ); + ATH_MSG_DEBUG( "Finalizing" ); + ATH_MSG_DEBUG( m_numberOfEvents << " events processed" ); + ATH_MSG_DEBUG( m_numberOfSPCollection << " spacepoint collections processed" ); + ATH_MSG_DEBUG( m_numberOfEmptySPCollection<< " spacepoint collections empty" ); + ATH_MSG_DEBUG( m_numberOfSP<< " sct SP collections processed" ); + ATH_MSG_DEBUG( m_numberOfNoMap<< " not maped spacepoint" ); + ATH_MSG_DEBUG( m_numberOfHits<< " sim hits" ); + ATH_MSG_DEBUG( m_numberOfMatchSP<< " matched spacepoint" ); + ATH_MSG_DEBUG( m_numberOfFills<< " spacepoint saved" ); return StatusCode::SUCCESS; } diff --git a/Tracking/Acts/ActsInterop/CMakeLists.txt b/Tracking/Acts/ActsInterop/CMakeLists.txt index 41632f128825078ea3e7bc471117c1e35caae2fa..63c79212852d5d2213c74f3bb27f7f145cd604a6 100755 --- a/Tracking/Acts/ActsInterop/CMakeLists.txt +++ b/Tracking/Acts/ActsInterop/CMakeLists.txt @@ -4,7 +4,9 @@ atlas_subdir( ActsInterop ) # External dependencies: -find_package(Acts COMPONENTS Core) +#set( Acts_DIR /home/tboeckh/Documents/acts/run ) +#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH ) +find_package( Acts COMPONENTS Core ) # Component(s) in the package: atlas_add_library( ActsInteropLib diff --git a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt index a121316e188cc27c35f3d90f9a81b569089b9d19..48c9abd929200339bfaa071bfa6625cf3e2a98cd 100755 --- a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt +++ b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt @@ -8,6 +8,8 @@ find_package( Eigen ) find_package( Boost ) find_package( nlohmann_json ) +#set( Acts_DIR /home/tboeckh/Documents/acts/run ) +#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH ) find_package( Acts COMPONENTS Core ) atlas_add_library( FaserActsGeometryLib diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py index 6466848fb515373c2b33bd8c0978d4f162e053bb..095edc7648474af1510d8c1f1174f8c955eccaa8 100644 --- a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py +++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py @@ -1,4 +1,6 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" ############################################################### # diff --git a/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx b/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx index 76416ff7b7a917a9e47a18a87ac125686b6d386a..a8a8bd2dec4016916236128d6c78e815b8015bf2 100644 --- a/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx @@ -75,12 +75,12 @@ std::shared_ptr<const Acts::Layer> CuboidVolumeBuilder::buildLayer( if ( !cfg.surfaces.empty() ) { return layerCreator.planeLayer(gctx, cfg.surfaces, cfg.binsX, cfg.binsY, - Acts::BinningValue::binZ, std::nullopt, trafo, - std::move(ap)); + Acts::BinningValue::binZ, std::nullopt, trafo); +// std::move(ap)); } else { return layerCreator.planeLayer(gctx, {cfg.surface}, cfg.binsX, cfg.binsY, - Acts::BinningValue::binZ, std::nullopt, trafo, - std::move(ap)); + Acts::BinningValue::binZ, std::nullopt, trafo); +// std::move(ap)); } } diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx index e84a69c6a3fe54ee30ecb046a0606a1e264da5e5..c5351bfaaea0780c843fb1aa3a6ec6fd31cdb3ce 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx @@ -71,7 +71,8 @@ FaserActsExtrapolationTool::initialize() ATH_MSG_INFO("Initializing ACTS extrapolation"); - m_logger = makeActsAthenaLogger(this, "Prop", "FaserActsExtrapTool"); + m_logger = Acts::getDefaultLogger("ExtrapolationTool", Acts::Logging::INFO); +// m_logger = makeActsAthenaLogger(this, "Prop", "FaserActsExtrapTool"); ATH_CHECK( m_trackingGeometryTool.retrieve() ); std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry @@ -318,8 +319,8 @@ FaserActsExtrapolationTool::propagate(const EventContext& ctx, ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin"); Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx); - const FaserActsGeometryContext& gctx - = m_trackingGeometryTool->getGeometryContext(ctx); + const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext(); +// const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext(ctx); auto anygctx = gctx.context(); diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx index df260a0f6e8da85b268940795f33775f54b60d5b..f8803a279be6565afe9597c701d5bf3f221fef94 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx @@ -39,9 +39,11 @@ FaserActs::CuboidVolumeBuilder::Config FaserActsLayerBuilder::buildVolume(const FaserActs::CuboidVolumeBuilder::Config cvbConfig; //std::vector<Acts::CuboidVolumeBuilder::VolumeConfig> volumeConfigs = {}; std::vector<FaserActs::CuboidVolumeBuilder::VolumeConfig> volumeConfigs = {}; - - for (int iStation=1; iStation<4; iStation++) { + // iStation starts from 1 for the main detector (Faser-01 geometry) and from 0 if we include the IFT (Faser-02 geometry) + auto siDetMng = static_cast<const TrackerDD::SCT_DetectorManager*>(m_cfg.mng); + int nStations = siDetMng->numerology().numStations(); + for (int iStation=4-nStations; iStation<4; iStation++) { //Acts::CuboidVolumeBuilder::VolumeConfig volumeConfig; FaserActs::CuboidVolumeBuilder::VolumeConfig volumeConfig; diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx index f32a02990835e96bc0d56bfe887604bf3667a4eb..94c852743ebd4dec46d3ee734a7f800dd4384a3e 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx @@ -25,6 +25,8 @@ #include "FaserActsGeometry/CuboidVolumeBuilder.h" #include "Acts/ActsVersion.hpp" #include "Acts/Definitions/Units.hpp" +#include <Acts/Plugins/Json/JsonMaterialDecorator.hpp> +#include <Acts/Plugins/Json/MaterialMapJsonConverter.hpp> // PACKAGE #include "FaserActsGeometry/FaserActsLayerBuilder.h" @@ -73,6 +75,21 @@ FaserActsTrackingGeometrySvc::initialize() cvhConfig, makeActsAthenaLogger(this, "CylVolHlpr", "ActsTGSvc")); Acts::TrackingGeometryBuilder::Config tgbConfig; + + if (m_useMaterialMap) { + std::shared_ptr<const Acts::IMaterialDecorator> matDeco = nullptr; + std::string matFile = m_materialMapInputFile; + ATH_MSG_INFO("Configured to use material input: " << matFile); + if (matFile.find(".json") != std::string::npos) { + // Set up the converter first + Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig; + // Set up the json-based decorator + matDeco = std::make_shared<const Acts::JsonMaterialDecorator>( + jsonGeoConvConfig, m_materialMapInputFile, Acts::Logging::INFO); + } + tgbConfig.materialDecorator = matDeco; + } + try { // SCT tgbConfig.trackingVolumeBuilders.push_back([&]( diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt index 7529f472a8de702fb76046cb78624a9111e65a03..b3f81e4ac59f82e9d53ebb75f68eaddbe3e4f74c 100644 --- a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt +++ b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt @@ -4,6 +4,8 @@ atlas_subdir( FaserActsGeometryInterfaces ) # External dependencies: find_package( Eigen ) +#set( Acts_DIR /home/tboeckh/Documents/acts/run ) +#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH ) find_package( Acts COMPONENTS Core ) find_package( nlohmann_json ) # Component(s) in the package: diff --git a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt index 21e5ed799d3caeaf33d4fc85102b9be48e18e599..22f075abb55848488419bc7129574a6a6a6741fe 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt +++ b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt @@ -5,8 +5,11 @@ atlas_subdir(FaserActsKalmanFilter) find_package( CLHEP ) find_package( Eigen ) find_package( Boost ) +#set( Acts_DIR /home/tboeckh/Documents/acts/run ) +#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH ) find_package( Acts COMPONENTS Core ) + # Component(s) in the package: atlas_add_library( FaserActsKalmanFilterLib PUBLIC_HEADERS FaserActsKalmanFilter @@ -22,23 +25,83 @@ atlas_add_library( FaserActsKalmanFilterLib ) atlas_add_component(FaserActsKalmanFilter + FaserActsKalmanFilter/ActsTrackSeedTool.h + FaserActsKalmanFilter/CircleFit.h + FaserActsKalmanFilter/CircleFitTrackSeedTool.h + FaserActsKalmanFilter/CKF2.h FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h + FaserActsKalmanFilter/EffPlotTool.h + FaserActsKalmanFilter/FASERSourceLink.h FaserActsKalmanFilter/FaserActsGeometryContainers.h + FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h + FaserActsKalmanFilter/GhostBusters.h + FaserActsKalmanFilter/MyTrackSeedTool.h + FaserActsKalmanFilter/IdentifierLink.h FaserActsKalmanFilter/IndexSourceLink.h + FaserActsKalmanFilter/ITrackFinderTool.h + FaserActsKalmanFilter/ITrackSeedTool.h + FaserActsKalmanFilter/KalmanFitterTool.h + FaserActsKalmanFilter/LinearFit.h +# FaserActsKalmanFilter/ClusterTrackSeedTool.h +# FaserActsKalmanFilter/TruthTrackFinderTool.h FaserActsKalmanFilter/Measurement.h +# FaserActsKalmanFilter/MultiTrackFinderTool.h + FaserActsKalmanFilter/PerformanceWriterTool.h + FaserActsKalmanFilter/PlotHelpers.h + FaserActsKalmanFilter/ResPlotTool.h + FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h + FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h + FaserActsKalmanFilter/SeedingAlg.h +# FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h +# FaserActsKalmanFilter/SegmentFitTrackFinderTool.h FaserActsKalmanFilter/SimWriterTool.h FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h FaserActsKalmanFilter/SPSimpleInitialParameterTool.h + FaserActsKalmanFilter/SummaryPlotTool.h + FaserActsKalmanFilter/TrackClassification.h + FaserActsKalmanFilter/TrackSeedWriterTool.h + FaserActsKalmanFilter/TrackSelection.h FaserActsKalmanFilter/TrajectoryWriterTool.h +# FaserActsKalmanFilter/ProtoTrackWriterTool.h FaserActsKalmanFilter/TruthBasedInitialParameterTool.h - src/CombinatorialKalmbanFilterAlg.cxx +# FaserActsKalmanFilter/TruthSeededTrackFinderTool.h + FaserActsKalmanFilter/ThreeStationTrackSeedTool.h + src/ActsTrackSeedTool.cxx + src/CircleFit.cxx + src/CircleFitTrackSeedTool.cxx + src/CKF2.cxx +# src/ClusterTrackSeedTool.cxx + src/CombinatorialKalmanFilterAlg.cxx + src/EffPlotTool.cxx + src/FaserActsKalmanFilterAlg.cxx + src/GhostBusters.cxx + src/MyTrackSeedTool.cxx + src/KalmanFitterTool.cxx +# src/MultiTrackFinderTool.cxx + src/PerformanceWriterTool.cxx + src/PlotHelpers.cxx + src/ResPlotTool.cxx + src/SeedingAlg.cxx + src/RootTrajectoryStatesWriterTool.cxx + src/RootTrajectorySummaryWriterTool.cxx +# src/SegmentFitClusterTrackFinderTool.cxx +# src/SegmentFitTrackFinderTool.cxx src/SimWriterTool.cxx src/SPSeedBasedInitialParameterTool.cxx src/SPSimpleInitialParameterTool.cxx +# src/ProtoTrackWriterTool.cxx src/TrackFindingAlgorithmFunction.cxx + src/TrackFittingFunction.cxx src/TrajectoryWriterTool.cxx src/TruthBasedInitialParameterTool.cxx + src/SummaryPlotTool.cxx + src/TrackClassification.cxx + src/TrackSeedWriterTool.cxx + src/TrackSelection.cxx +# src/TruthTrackFinderTool.cxx +# src/TruthSeededTrackFinderTool.cxx + src/ThreeStationTrackSeedTool.cxx src/components/FaserActsKalmanFilter_entries.cxx PUBLIC_HEADERS FaserActsKalmanFilter INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS} @@ -63,6 +126,7 @@ atlas_add_component(FaserActsKalmanFilter TrackerIdentifier TrackerReadoutGeometry Identifier + TrackerSimEvent TrackerSimData TrackerSeedFinderLib ) diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..95311206b6300722344935b535c4f0d963728392 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h @@ -0,0 +1,116 @@ +#ifndef FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H +#define FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H + + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "TrkTrack/TrackCollection.h" + +class FaserSCT_ID; +namespace TrackerDD { class SCT_DetectorManager; } + + +class ActsTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> { +public: + ActsTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~ActsTrackSeedTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + const std::shared_ptr<const Acts::Surface> initialSurface() const override; + const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + const std::shared_ptr<IdentifierLink> idLinks() const override; + const std::shared_ptr<std::vector<Measurement>> measurements() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override; + const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override; + double targetZPosition() const override; + +private: + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {}; + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {}; + double m_targetZPosition {0.}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { + this, "ClusterContainer", "SCT_ClusterContainer"}; + + // position resolution of a cluster + Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.023}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; + Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"}; + + static Acts::CurvilinearTrackParameters get_params( + const Acts::GeometryContext& gctx, const Amg::Vector3D& position_st1, + const Amg::Vector3D& position_st2, const Amg::Vector3D& position_st3, + const Acts::BoundSymMatrix& cov, double origin); +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +ActsTrackSeedTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +ActsTrackSeedTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> +ActsTrackSeedTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +ActsTrackSeedTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> +ActsTrackSeedTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> +ActsTrackSeedTool::clusters() const { + return m_clusters; +} + +inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> +ActsTrackSeedTool::seedClusters() const { + return m_seedClusters; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> +ActsTrackSeedTool::spacePoints() const { + return m_spacePoints; +} + +inline double ActsTrackSeedTool::targetZPosition() const { + return m_targetZPosition; +} + +#endif // FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h new file mode 100644 index 0000000000000000000000000000000000000000..da7baf0c88406e764b454796e58239e3de7d93b0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h @@ -0,0 +1,156 @@ +#ifndef FASERACTSKALMANFILTER_CKF2_H +#define FASERACTSKALMANFILTER_CKF2_H + + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" +#include "Acts/TrackFinding/MeasurementSelector.hpp" +#include "FaserActsKalmanFilter/Measurement.h" +#include "MagFieldConditions/FaserFieldCacheCondObj.h" +#include "FaserActsKalmanFilter/TrajectoryWriterTool.h" +#include "TrkTrack/TrackCollection.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h" +#include "FaserActsKalmanFilter/PerformanceWriterTool.h" +#include "FaserActsKalmanFilter/KalmanFitterTool.h" +#include <boost/dynamic_bitset.hpp> +using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; +using ClusterSet = boost::dynamic_bitset<>; + +class FaserSCT_ID; + +namespace Trk { +class TrackStateOnSurface; +} + +namespace TrackerDD { +class SCT_DetectorManager; +} + +class CKF2 : public AthAlgorithm { +public: + CKF2(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CKF2() = default; + + StatusCode initialize() override; + StatusCode execute() override; + StatusCode finalize() override; + + using TrackFinderOptions = + Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor, + MeasurementCalibrator, + Acts::MeasurementSelector>; + using CKFResult = Acts::CombinatorialKalmanFilterResult<IndexSourceLink>; + using TrackFitterResult = Acts::Result<CKFResult>; + using TrackFinderResult = std::vector<TrackFitterResult>; + + using KFResult = + Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>; + + using TrackFitterOptions = + Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, + Acts::VoidReverseFilteringLogic>; + + using TrackParameters = Acts::CurvilinearTrackParameters; + using TrackParametersContainer = std::vector<TrackParameters>; + + // Track Finding + class TrackFinderFunction { + public: + virtual ~TrackFinderFunction() = default; + virtual TrackFinderResult operator()(const IndexSourceLinkContainer&, + const TrackParametersContainer&, + const TrackFinderOptions&) const = 0; + }; + + static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + bool resolvePassive, bool resolveMaterial, bool resolveSensitive); + + // Track Fitting + class TrackFitterFunction { + public: + virtual ~TrackFitterFunction() = default; + virtual KFResult operator()(const std::vector<IndexSourceLink>&, + const Acts::BoundTrackParameters&, + const TrackFitterOptions&) const = 0; + }; + + struct TrajectoryInfo { + TrajectoryInfo(const FaserActsRecMultiTrajectory &traj) : + trajectory{traj}, clusterSet{nClusters} { + auto state = Acts::MultiTrajectoryHelpers::trajectoryState(traj.multiTrajectory(), traj.tips().front()); + traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) { + auto typeFlags = state.typeFlags(); + if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + clusterSet.set(state.uncalibrated().index()); + return true; + }); + nMeasurements = state.nMeasurements; + chi2 = state.chi2Sum; + } + + static size_t nClusters; + FaserActsRecMultiTrajectory trajectory; + ClusterSet clusterSet; + size_t nMeasurements; + double chi2; + }; + + static std::shared_ptr<TrackFitterFunction> makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); + + virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; + +private: + size_t m_numberOfEvents {0}; + size_t m_numberOfTrackSeeds {0}; + size_t m_numberOfFittedTracks {0}; + size_t m_numberOfSelectedTracks {0}; + + void computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const; + std::shared_ptr<TrackFinderFunction> m_fit; + std::shared_ptr<TrackFitterFunction> m_kf; + std::unique_ptr<const Acts::Logger> m_logger; + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"}; + Gaudi::Property<int> m_minNumberMeasurements {this, "MinNumberMeasurements", 12}; + Gaudi::Property<bool> m_backwardPropagation {this, "BackwardPropagation", false}; + Gaudi::Property<bool> m_performanceWriter {this, "PerformanceWriter", true}; + Gaudi::Property<bool> m_summaryWriter {this, "SummaryWriter", true}; + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + Gaudi::Property<bool> m_statesWriter {this, "StatesWriter", false}; + Gaudi::Property<bool> m_resolvePassive {this, "resolvePassive", false}; + Gaudi::Property<bool> m_resolveMaterial {this, "resolveMaterial", true}; + Gaudi::Property<bool> m_resolveSensitive {this, "resolveSensitive", true}; + Gaudi::Property<double> m_maxSteps {this, "maxSteps", 10000}; + Gaudi::Property<double> m_chi2Max {this, "chi2Max", 15}; + Gaudi::Property<unsigned long> m_nMax {this, "nMax", 10}; + SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; + ToolHandle<ITrackSeedTool> m_trackSeedTool {this, "TrackSeed", "ClusterTrackSeedTool"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + ToolHandle<PerformanceWriterTool> m_performanceWriterTool {this, "PerformanceWriterTool", "PerformanceWriterTool"}; + ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"}; + ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"}; + ToolHandle<KalmanFitterTool> m_kalmanFitterTool1 {this, "KalmanFitterTool1", "KalmanFitterTool"}; + ToolHandle<KalmanFitterTool> m_kalmanFitterTool2 {this, "KalmanFitterTool2", "KalmanFitterTool"}; + Gaudi::Property<bool> m_isMC {this, "isMC", false}; + + std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const; + std::unique_ptr<Trk::Track> makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const; + const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; + SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "CKFTrackCollection", "CKFTrackCollection" }; +}; + +#endif // FASERACTSKALMANFILTER_CKF2_H + diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h new file mode 100644 index 0000000000000000000000000000000000000000..780a476a722707f280b427a1678f16fcfb5b1cdf --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h @@ -0,0 +1,46 @@ +#ifndef FASERACTSKALMANFILTER_CIRCLEFIT_H +#define FASERACTSKALMANFILTER_CIRCLEFIT_H + +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include <cmath> +#include <vector> + +namespace CircleFit { + + +class CircleData { +public: + CircleData(const std::vector<const Tracker::FaserSCT_SpacePoint *> &spacePoints); + CircleData(const std::vector<Amg::Vector3D> &spacePoints); + double meanX() const; + double meanY() const; + double x(int i) const; + double y(int i) const; + int size() const; + +private: + std::vector<double> m_x{}; + std::vector<double> m_y{}; + int m_size = 0; +}; + + +struct Circle { +public: + Circle() = default; + Circle(double cx, double cy, double r) : cx(cx), cy(cy), r(r) {}; + + double cx = 0; + double cy = 0; + double r = 0; + double s = 0; + double i = 0; + double j = 0; +}; + +double sigma(const CircleData &data, const Circle &circle); +Circle circleFit(const CircleData &data); + +} // namespace CircleFit + +#endif // FASERACTSKALMANFILTER_CIRCLEFIT_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFitTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFitTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..368abb1f228e45e69d0c38da02e63dc65c15fb4d --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFitTrackSeedTool.h @@ -0,0 +1,165 @@ +#ifndef FASERACTSKALMANFILTER_CIRCLEFITTRACKSEEDTOOL_H +#define FASERACTSKALMANFILTER_CIRCLEFITTRACKSEEDTOOL_H + +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" + +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "TrkTrack/TrackCollection.h" +// #include "TrackerSimData/TrackerSimDataCollection.h" +// #include "GeneratorObjects/McEventCollection.h" +#include <array> +#include <memory> +#include <string> +#include <vector> +#include <boost/dynamic_bitset.hpp> + +typedef boost::dynamic_bitset<> ClusterSet; + +class FaserSCT_ID; +namespace TrackerDD { class SCT_DetectorManager; } + +class CircleFitTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> { +public: + CircleFitTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~CircleFitTrackSeedTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + const std::shared_ptr<const Acts::Surface> initialSurface() const override; + const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + const std::shared_ptr<IdentifierLink> idLinks() const override; + const std::shared_ptr<std::vector<Measurement>> measurements() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override; + const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override; + double targetZPosition() const override; + +private: + struct Segment { + public: + Segment(const Trk::Track* track, const FaserSCT_ID *idHelper); + int station; + std::vector<const Tracker::FaserSCT_Cluster*> clusters; + std::vector<const Tracker::FaserSCT_SpacePoint*> spacePoints; + ClusterSet clusterSet; + Acts::Vector3 position; + std::vector<Acts::Vector3> fakePositions; + Acts::Vector3 momentum; + }; + + struct Seed { + Seed(const std::vector<Segment> &segments); + + ClusterSet clusterSet; + std::vector<const Tracker::FaserSCT_Cluster*> clusters; + std::vector<const Tracker::FaserSCT_SpacePoint*> spacePoints; + std::vector<Acts::Vector3> positions; + std::vector<Acts::Vector3> fakePositions; + + double c0, c1, cx, cy, r, chi2, momentum, charge, minZ; + Acts::Vector3 direction; + size_t size; + Acts::CurvilinearTrackParameters get_params(double origin, Acts::BoundSymMatrix cov) const; + + private: + void getChi2(); + double getX(double z); + double getY(double z); + void fit(); + void fakeFit(double B=0.55); + void linearFit(const std::vector<Acts::Vector2> &points); + double m_dx, m_dy; + double m_MeV2GeV = 1e-3; + double m_sigma_x = 0.8; + double m_sigma_y = 0.016; + }; + + void go(const std::array<std::vector<Segment>, 4> &v, std::vector<Segment> &combination, + std::vector<Seed> &seeds, int offset, int k); + + static std::map<Identifier, Index> s_indexMap; + static std::map<Identifier, const Tracker::FaserSCT_SpacePoint*> s_spacePointMap; + + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {}; + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {}; + double m_targetZPosition {0}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { this, "ClusterContainer", "SCT_ClusterContainer"}; + SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey { this, "SpacePoints", "SCT_SpacePointContainer"}; + // SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey { this, "McEventCollection", "TruthEvent"}; + // SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + + Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.04}; + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +CircleFitTrackSeedTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +CircleFitTrackSeedTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> +CircleFitTrackSeedTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +CircleFitTrackSeedTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> +CircleFitTrackSeedTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> +CircleFitTrackSeedTool::clusters() const { + return m_clusters; +} + +inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> +CircleFitTrackSeedTool::seedClusters() const { + return m_seedClusters; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> +CircleFitTrackSeedTool::spacePoints() const { + return m_spacePoints; +} + +inline double CircleFitTrackSeedTool::targetZPosition() const { + return m_targetZPosition; +} + +#endif // FASERACTSKALMANFILTER_CIRCLEFITTRACKSEEDTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ClusterTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ClusterTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..fa869dc1bd7242f5096a16d879b73ab86a9e2173 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ClusterTrackSeedTool.h @@ -0,0 +1,100 @@ +#ifndef FASERACTSKALMANFILTER_CLUSTERTRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_CLUSTERTRACKFINDERTOOL_H + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" + +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "TrkTrack/TrackCollection.h" +#include <memory> +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { class SCT_DetectorManager; } + +class ClusterTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> { +public: + ClusterTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~ClusterTrackSeedTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + const std::shared_ptr<const Acts::Surface> initialSurface() const override; + const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + const std::shared_ptr<IdentifierLink> idLinks() const override; + const std::shared_ptr<std::vector<Measurement>> measurements() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override; + +private: + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { + this, "ClusterContainer", "SCT_ClusterContainer"}; + + // position resolution of a cluster + Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.04}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; + + Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"}; + + static Acts::CurvilinearTrackParameters get_params(const Amg::Vector3D& position_st1, const Amg::Vector3D& position_st2, const Acts::BoundSymMatrix& cov, double origin); +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +ClusterTrackSeedTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +ClusterTrackSeedTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> +ClusterTrackSeedTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +ClusterTrackSeedTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> +ClusterTrackSeedTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> +ClusterTrackSeedTool::clusters() const { + return m_clusters; +} + + +#endif // FASERACTSKALMANFILTER_CLUSTERTRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h index 4b750614a3f496a9cabef0352c223d9b9e5a9658..28058887c9b6f05d384962206c8cca1a64a9d66c 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h @@ -2,82 +2,132 @@ #define COMBINATORIALKALMANFILTERALG_H #include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthAlgorithm.h" #include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" #include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" -#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.h" -#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h" -#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h" +//#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h" +//#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h" #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" #include "Acts/TrackFinding/MeasurementSelector.hpp" #include "FaserActsKalmanFilter/Measurement.h" #include "MagFieldConditions/FaserFieldCacheCondObj.h" #include "FaserActsKalmanFilter/TrajectoryWriterTool.h" #include "TrkTrack/TrackCollection.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h" +#include "FaserActsKalmanFilter/PerformanceWriterTool.h" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include <boost/dynamic_bitset.hpp> +using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; +using ClusterSet = boost::dynamic_bitset<>; + class FaserSCT_ID; -namespace Trk -{ +namespace Trk { class TrackStateOnSurface; } namespace TrackerDD { - class SCT_DetectorManager; +class SCT_DetectorManager; } -class CombinatorialKalmanFilterAlg : public AthReentrantAlgorithm { - public: +class CombinatorialKalmanFilterAlg : public AthAlgorithm { +public: CombinatorialKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); virtual ~CombinatorialKalmanFilterAlg() = default; StatusCode initialize() override; - StatusCode execute(const EventContext& ctx) const override; + StatusCode execute() override; StatusCode finalize() override; using TrackFinderOptions = - Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor, MeasurementCalibrator, Acts::MeasurementSelector>; - using FitterResult = Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>; - using TrackFinderResult = std::vector<FitterResult>; -// using TrackFinderResult = std::vector< -// Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>>; - using TrackFinderFunction = std::function<TrackFinderResult( - const IndexSourceLinkContainer&, const std::vector<Acts::CurvilinearTrackParameters>&, - const TrackFinderOptions&)>; + Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor, + MeasurementCalibrator, + Acts::MeasurementSelector>; + using CKFResult = Acts::CombinatorialKalmanFilterResult<IndexSourceLink>; + using TrackFitterResult = Acts::Result<CKFResult>; + using TrackFinderResult = std::vector<TrackFitterResult>; + using TrackParameters = Acts::CurvilinearTrackParameters; + using TrackParametersContainer = std::vector<TrackParameters>; + + class TrackFinderFunction { + public: + virtual ~TrackFinderFunction() = default; + virtual TrackFinderResult operator()(const IndexSourceLinkContainer&, + const TrackParametersContainer&, + const TrackFinderOptions&) const = 0; + }; - static TrackFinderFunction makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); + struct TrajectoryInfo { + TrajectoryInfo(const FaserActsRecMultiTrajectory &traj) : + trajectory{traj}, clusterSet{nClusters} { + auto state = Acts::MultiTrajectoryHelpers::trajectoryState(traj.multiTrajectory(), traj.tips().front()); + traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) { + auto typeFlags = state.typeFlags(); + if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + clusterSet.set(state.uncalibrated().index()); + return true; + }); + nMeasurements = state.nMeasurements; + chi2 = state.chi2Sum; + } - Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; + static size_t nClusters; + FaserActsRecMultiTrajectory trajectory; + ClusterSet clusterSet; + size_t nMeasurements; + double chi2; + }; + static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + bool resolvePassive, bool resolveMaterial, bool resolveSensitive); + virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; private: - const FaserSCT_ID* m_idHelper{nullptr}; - const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; + size_t m_numberOfEvents {0}; + size_t m_numberOfTrackSeeds {0}; + size_t m_numberOfFittedTracks {0}; + size_t m_numberOfSelectedTracks {0}; -// std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult, std::vector<Tracker::FaserSCT_Cluster> seed_spcollection) const; - std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult, std::vector<Tracker::FaserSCT_SpacePoint> seed_spcollection) const; - const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; + void computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const; + std::shared_ptr<TrackFinderFunction> m_fit; + std::unique_ptr<const Acts::Logger> m_logger; + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; - SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "FaserActsCKFTrackCollection", "FaserActsCKFTrackCollection", "Output trackcollectionname" }; + Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"}; + Gaudi::Property<int> m_minNumberMeasurements {this, "MinNumberMeasurements", 12}; + Gaudi::Property<bool> m_backwardPropagation {this, "BackwardPropagation", false}; + Gaudi::Property<bool> m_performanceWriter {this, "PerformanceWriter", true}; + Gaudi::Property<bool> m_summaryWriter {this, "SummaryWriter", true}; + Gaudi::Property<bool> m_statesWriter {this, "StatesWriter", false}; + Gaudi::Property<bool> m_resolvePassive {this, "resolvePassive", false}; + Gaudi::Property<bool> m_resolveMaterial {this, "resolveMaterial", true}; + Gaudi::Property<bool> m_resolveSensitive {this, "resolveSensitive", true}; + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + Gaudi::Property<double> m_maxSteps {this, "maxSteps", 1000}; + Gaudi::Property<double> m_chi2Max {this, "chi2Max", 15}; + Gaudi::Property<unsigned long> m_nMax {this, "nMax", 10}; + Gaudi::Property<bool> m_isMC {this, "isMC", false}; - ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; -// ToolHandle<SPSeedBasedInitialParameterTool> m_initialParameterTool{this, "InitialParameterTool", "SPSeedBasedInitialParameterTool"}; -// ToolHandle<SPSimpleInitialParameterTool> m_initialParameterTool{this, "InitialParameterTool", "SPSimpleInitialParameterTool"}; - ToolHandle<TruthBasedInitialParameterTool> m_initialParameterTool{this, "InitialParameterTool", "TruthBasedInitialParameterTool"}; - ToolHandle<TrajectoryWriterTool> m_trajectoryWriterTool{this, "OutputTool", "TrajectoryWriterTool"}; SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; - SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_SpacePointContainerKey{this, "SpacePointsSCTName", "SCT_SpacePointContainer", "SCT space point container"}; - SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_Sct_clcontainerKey{this, "SCT_ClusterContainer", "SCT_ClusterContainer"}; - mutable int m_nevents; - mutable int m_ntracks; - mutable int m_nseeds; - mutable int m_nsp1; - mutable int m_nsp2; - mutable int m_nsp3; - mutable int m_nsp10; - mutable int m_nsp11; - mutable int m_ncom; + ToolHandle<ITrackSeedTool> m_trackSeedTool {this, "TrackSeed", "ClusterTrackSeedTool"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + ToolHandle<PerformanceWriterTool> m_performanceWriterTool {this, "PerformanceWriterTool", "PerformanceWriterTool"}; + ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"}; + ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"}; + + std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const; + std::unique_ptr<Trk::Track> makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const; + const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; + SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "CKFTrackCollection", "CKFTrackCollection" }; }; #endif // COMBINATORIALKALMANFILTERALG_H + diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/EffPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/EffPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e5af125d6021d5ab19b71f73eebc63a99604aea5 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/EffPlotTool.h @@ -0,0 +1,57 @@ +#ifndef FASERACTSKALMANFILTER_EFFPLOTTOOL_H +#define FASERACTSKALMANFILTER_EFFPLOTTOOL_H + +#include "FaserActsKalmanFilter/PlotHelpers.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "HepMC/GenParticle.h" +#include "TEfficiency.h" +#include "TProfile.h" +#include <map> +#include <string> + +class EffPlotTool { +public: + std::map<std::string, PlotHelpers::Binning> m_varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, 4, 12)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 20)} + }; + + /// @brief Nested Cache struct + struct EffPlotCache { + TEfficiency* trackEff_vs_pT; ///< Tracking efficiency vs pT + TEfficiency* trackEff_vs_eta; ///< Tracking efficiency vs eta + TEfficiency* trackEff_vs_phi; ///< Tracking efficiency vs phi + }; + + /// Constructor + /// + EffPlotTool() = default; + + /// @brief book the efficiency plots + /// + /// @param effPlotCache the cache for efficiency plots + void book(EffPlotCache& effPlotCache) const; + + /// @brief fill efficiency plots + /// + /// @param effPlotCache cache object for efficiency plots + /// @param truthParticle the truth Particle + /// @param status the reconstruction status + void fill(EffPlotCache& effPlotCache, const HepMC::GenParticle* truthParticle, bool status) const; + + /// @brief write the efficiency plots to file + /// + /// @param effPlotCache cache object for efficiency plots + void write(const EffPlotCache& effPlotCache) const; + + /// @brief delete the efficiency plots + /// + /// @param effPlotCache cache object for efficiency plots + void clear(EffPlotCache& effPlotCache) const; + +private: + const double m_MeV2GeV = 0.001; +}; + +#endif // FASERACTSKALMANFILTER_EFFPLOTTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FASERSourceLink.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FASERSourceLink.h new file mode 100644 index 0000000000000000000000000000000000000000..6ec1c46b9ad12ff6822c070a4ea320d6079dd387 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FASERSourceLink.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include <cassert> +#include <boost/container/flat_map.hpp> +#include "FaserActsKalmanFilter/FaserActsGeometryContainers.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" + +using Index = uint32_t; + +class FASERSourceLink final { +public: + /// Construct from geometry identifier and index. + constexpr FASERSourceLink(Acts::GeometryIdentifier gid, Index idx, Tracker::FaserSCT_Cluster hit) + : m_geometryId(gid), m_index(idx), m_hit(hit) {} + + // Construct an invalid source link. Must be default constructible to + /// satisfy SourceLinkConcept. + FASERSourceLink() = default; + FASERSourceLink(const FASERSourceLink&) = default; + FASERSourceLink(FASERSourceLink&&) = default; + FASERSourceLink& operator=(const FASERSourceLink&) = default; + FASERSourceLink& operator=(FASERSourceLink&&) = default; + + /// Access the geometry identifier. + constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + /// Access the index. + constexpr Index index() const { return m_index; } + /// Access the Tracker::FaserSCT_Cluster hit + constexpr Tracker::FaserSCT_Cluster hit() const { return m_hit; } + +private: + Acts::GeometryIdentifier m_geometryId; + Index m_index; + Tracker::FaserSCT_Cluster m_hit; + + friend constexpr bool operator==(const FASERSourceLink& lhs, + const FASERSourceLink& rhs) { + return (lhs.m_geometryId == rhs.m_geometryId) and + (lhs.m_index == rhs.m_index); + } + friend constexpr bool operator!=(const FASERSourceLink& lhs, + const FASERSourceLink& rhs) { + return not(lhs == rhs); + } +}; + +/// Container of index source links. +/// +/// Since the source links provide a `.geometryId()` accessor, they can be +/// stored in an ordered geometry container. +using FASERSourceLinkContainer = GeometryIdMultiset<FASERSourceLink>; +/// Accessor for the above source link container +/// +/// It wraps up a few lookup methods to be used in the Combinatorial Kalman +/// Filter +using FASERSourceLinkAccessor = GeometryIdMultisetAccessor<FASERSourceLink>; diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h index 8e90ed858c09efc3d46985a7edb354ea2de6c280..34dd7c63e7ef5842ac1416dc30d895bef3ecf997 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h @@ -6,8 +6,8 @@ #define FASERACTSKALMANFILTER_FASERACTSKALMANFILTERALG_H // ATHENA -#include "AthenaBaseComps/AthAlgorithm.h" #include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthAlgorithm.h" #include "GaudiKernel/ServiceHandle.h" #include "GaudiKernel/ITHistSvc.h" #include "Gaudi/Property.h" /*no forward decl: typedef*/ @@ -24,6 +24,7 @@ #include "GeneratorObjects/McEventCollection.h" #include "TrackerSimData/TrackerSimDataCollection.h" #include "TrkTrack/TrackCollection.h" +#include "FaserActsKalmanFilter/TrajectoryWriterTool.h" // ACTS #include "Acts/MagneticField/ConstantBField.hpp" @@ -47,6 +48,9 @@ #include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" #include "FaserActsKalmanFilter/IndexSourceLink.h" #include "FaserActsKalmanFilter/Measurement.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +//#include "FaserActsKalmanFilter/ProtoTrackWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" // STL #include <memory> @@ -73,216 +77,59 @@ using BField_t = FASERMagneticFieldWrapper; //class FaserActsKalmanFilterAlg : public AthReentrantAlgorithm { class FaserActsKalmanFilterAlg : public AthAlgorithm { public: - FaserActsKalmanFilterAlg (const std::string& name, ISvcLocator* pSvcLocator); + FaserActsKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~FaserActsKalmanFilterAlg() = default; + StatusCode initialize() override; - //StatusCode execute(const EventContext& ctx) const override; +// StatusCode execute(const EventContext& ctx) const override; StatusCode execute() override; StatusCode finalize() override; - using FitterResult = Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>; - // Fit function that takes input measurements, initial trackstate and fitter - // options and returns some fit-specific result. - using FitterFunction = std::function<FitterResult( - const std::vector<IndexSourceLink>&, - const Acts::CurvilinearTrackParameters&, - const Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder>&, - const std::vector<const Acts::Surface*>&)>; + using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>; + using TrackFitterOptions = + Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, + Acts::VoidReverseFilteringLogic>; + using TrackFitterResult = + Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>; - using BoundVector = Acts::ActsVector<6>; + using TrackParameters = Acts::CurvilinearTrackParameters; - // Create the fitter function implementation. - static FitterFunction - makeFitterFunction( - ActsExtrapolationDetail::VariantPropagator* varProp); + class TrackFitterFunction { + public: + virtual ~TrackFitterFunction() = default; + virtual TrackFitterResult operator()(const std::vector<IndexSourceLink>&, + const TrackParameters&, + const TrackFitterOptions&) const = 0; + }; - virtual - Acts::MagneticFieldContext - //getMagneticFieldContext(const EventContext& ctx) const; - getMagneticFieldContext() const; + static std::shared_ptr<TrackFitterFunction> makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); - void initializeTree(); + virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; - void fillFitResult(const Acts::GeometryContext& geoctx, const TrajectoryContainer& trajectories, const Acts::BoundTrackParameters& truthParam); +private: + const FaserSCT_ID* m_idHelper {nullptr}; + std::shared_ptr<TrackFitterFunction> m_fit; + std::unique_ptr<const Acts::Logger> m_logger; - // Create a track from the fitter result - std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult,const SpacePointForSeedCollection* seed_spcollection ) const; + Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"}; + std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult, std::vector<const Tracker::FaserSCT_Cluster*> clusters) const; const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; - void clearTrackVariables(); - -private: - const FaserSCT_ID* m_idHelper{nullptr}; - // Read handle for conditions object to get the field cache SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; - ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool{this, "ExtrapolationTool", "FaserActsExtrapolationTool"}; - - Gaudi::Property<std::string> m_fieldMode{this, "FieldMode", "FASER"}; - Gaudi::Property<std::vector<double>> m_constantFieldVector{this, "ConstantFieldVector", {0, 0, 0}}; + ToolHandle<ITrackFinderTool> m_trackFinderTool {this, "TrackFinderTool", "TruthTrackFinderTool"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + ToolHandle<TrajectoryWriterTool> m_trajectoryWriterTool {this, "OutputTool", "TrajectoryWriterTool"}; + ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"}; +// ToolHandle<ProtoTrackWriterTool> m_protoTrackWriterTool {this, "ProtoTrackWriterTool", "ProtoTrackWriterTool"}; - SG::ReadHandleKey<SpacePointForSeedCollection> m_seed_spcollectionKey{this, "FaserSpacePointsSeedsName", "SpacePointForSeedCollection", "SpacePointForSeedCollection"}; - - SG::ReadHandleKey<McEventCollection> m_mcEventKey { this, "McEventCollection", "BeamTruthEvent" }; + SG::ReadHandleKey<McEventCollection> m_mcEventKey { this, "McEventCollection", "BeamTruthEvent" }; SG::ReadHandleKey<TrackerSimDataCollection> m_sctMap {this, "TrackerSimDataCollection", "SCT_SDO_Map"}; const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; - SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "FaserActsCKFTrackCollection", "FaserActsCKFTrackCollection", "Output trackcollection name" }; - - ServiceHandle<ITHistSvc> m_thistSvc; - - TTree *m_trackTree{nullptr}; - - Acts::GeometryIdentifier getGeometryIdentifier(const Identifier id); - int getGeometryIdentifierVolume(int station); - int getGeometryIdentifierLayer(int layer); - int getGeometryIdentifierSensitive(int row, int column); - - /// Acts tree values - int m_eventNr{0}; - int m_trajNr{0}; - int m_trackNr{0}; - - unsigned long m_t_barcode{0}; /// Truth particle barcode - int m_t_charge{0}; /// Truth particle charge - float m_t_eT{0}; /// Truth particle time on the first layer - float m_t_eLOC0{-99.}; /// Truth local x on the first layer - float m_t_eLOC1{-99.}; /// Truth local y on the first layer - float m_t_eTHETA{-99.}; /// Truth particle momentum theta on the first layer - float m_t_ePHI{-99.}; /// Truth particle momentum phi on the first layer - float m_t_eQOP{-99.}; /// Truth particle momentum qop on the first layer - float m_t_x{-99.}; /// Truth particle position x on the first layer - float m_t_y{-99.}; /// Truth particle position y on the first layer - float m_t_z{-99.}; /// Truth particle position z on the first layer - float m_t_px{-99.}; /// Truth particle momentum px on the first layer - float m_t_py{-99.}; /// Truth particle momentum py on the first layer - float m_t_pz{-99.}; /// Truth particle momentum pz on the first layer - - int m_nHoles{0}; /// number of holes in the track fit - int m_nOutliers{0}; /// number of outliers in the track fit - int m_nStates{0}; /// number of all states - int m_nMeasurements{0}; /// number of states with measurements - std::vector<int> m_volumeID; /// volume identifier - std::vector<int> m_layerID; /// layer identifier - std::vector<int> m_moduleID; /// surface identifier - std::vector<float> m_lx_hit; /// uncalibrated measurement local x - std::vector<float> m_ly_hit; /// uncalibrated measurement local y - std::vector<float> m_x_hit; /// uncalibrated measurement global x - std::vector<float> m_y_hit; /// uncalibrated measurement global y - std::vector<float> m_z_hit; /// uncalibrated measurement global z - std::vector<float> m_res_x_hit; /// hit residual x - std::vector<float> m_res_y_hit; /// hit residual y - std::vector<float> m_err_x_hit; /// hit err x - std::vector<float> m_err_y_hit; /// hit err y - std::vector<float> m_pull_x_hit; /// hit pull x - std::vector<float> m_pull_y_hit; /// hit pull y - std::vector<int> m_dim_hit; /// dimension of measurement - - bool m_hasFittedParams{false}; /// if the track has fitted parameter - float m_eLOC0_fit{-99.}; /// fitted parameter eLOC_0 - float m_eLOC1_fit{-99.}; /// fitted parameter eLOC_1 - float m_ePHI_fit{-99.}; /// fitted parameter ePHI - float m_eTHETA_fit{-99.}; /// fitted parameter eTHETA - float m_eQOP_fit{-99.}; /// fitted parameter eQOP - float m_eT_fit{-99.}; /// fitted parameter eT - float m_err_eLOC0_fit{-99.}; /// fitted parameter eLOC_-99.err - float m_err_eLOC1_fit{-99.}; /// fitted parameter eLOC_1 err - float m_err_ePHI_fit{-99.}; /// fitted parameter ePHI err - float m_err_eTHETA_fit{-99.}; /// fitted parameter eTHETA err - float m_err_eQOP_fit{-99.}; /// fitted parameter eQOP err - float m_err_eT_fit{-99.}; /// fitted parameter eT err - float m_px_fit{-99.}; /// fitted parameter global px - float m_py_fit{-99.}; /// fitted parameter global py - float m_pz_fit{-99.}; /// fitted parameter global pz - float m_x_fit{-99.}; /// fitted parameter global PCA x - float m_y_fit{-99.}; /// fitted parameter global PCA y - float m_z_fit{-99.}; /// fitted parameter global PCA z - float m_chi2_fit{-99.}; /// fitted parameter chi2 - float m_ndf_fit{-99.}; /// fitted parameter ndf - int m_charge_fit{-99}; /// fitted parameter charge - - int m_nPredicted{0}; /// number of states with predicted parameter - std::vector<bool> m_prt; /// predicted status - std::vector<float> m_eLOC0_prt; /// predicted parameter eLOC0 - std::vector<float> m_eLOC1_prt; /// predicted parameter eLOC1 - std::vector<float> m_ePHI_prt; /// predicted parameter ePHI - std::vector<float> m_eTHETA_prt; /// predicted parameter eTHETA - std::vector<float> m_eQOP_prt; /// predicted parameter eQOP - std::vector<float> m_eT_prt; /// predicted parameter eT - std::vector<float> m_res_eLOC0_prt; /// predicted parameter eLOC0 residual - std::vector<float> m_res_eLOC1_prt; /// predicted parameter eLOC1 residual - std::vector<float> m_err_eLOC0_prt; /// predicted parameter eLOC0 error - std::vector<float> m_err_eLOC1_prt; /// predicted parameter eLOC1 error - std::vector<float> m_err_ePHI_prt; /// predicted parameter ePHI error - std::vector<float> m_err_eTHETA_prt; /// predicted parameter eTHETA error - std::vector<float> m_err_eQOP_prt; /// predicted parameter eQOP error - std::vector<float> m_err_eT_prt; /// predicted parameter eT error - std::vector<float> m_pull_eLOC0_prt; /// predicted parameter eLOC0 pull - std::vector<float> m_pull_eLOC1_prt; /// predicted parameter eLOC1 pull - std::vector<float> m_x_prt; /// predicted global x - std::vector<float> m_y_prt; /// predicted global y - std::vector<float> m_z_prt; /// predicted global z - std::vector<float> m_px_prt; /// predicted momentum px - std::vector<float> m_py_prt; /// predicted momentum py - std::vector<float> m_pz_prt; /// predicted momentum pz - std::vector<float> m_eta_prt; /// predicted momentum eta - std::vector<float> m_pT_prt; /// predicted momentum pT - - int m_nFiltered{0}; /// number of states with filtered parameter - std::vector<bool> m_flt; /// filtered status - std::vector<float> m_eLOC0_flt; /// filtered parameter eLOC0 - std::vector<float> m_eLOC1_flt; /// filtered parameter eLOC1 - std::vector<float> m_ePHI_flt; /// filtered parameter ePHI - std::vector<float> m_eTHETA_flt; /// filtered parameter eTHETA - std::vector<float> m_eQOP_flt; /// filtered parameter eQOP - std::vector<float> m_eT_flt; /// filtered parameter eT - std::vector<float> m_res_eLOC0_flt; /// filtered parameter eLOC0 residual - std::vector<float> m_res_eLOC1_flt; /// filtered parameter eLOC1 residual - std::vector<float> m_err_eLOC0_flt; /// filtered parameter eLOC0 error - std::vector<float> m_err_eLOC1_flt; /// filtered parameter eLOC1 error - std::vector<float> m_err_ePHI_flt; /// filtered parameter ePHI error - std::vector<float> m_err_eTHETA_flt; /// filtered parameter eTHETA error - std::vector<float> m_err_eQOP_flt; /// filtered parameter eQOP error - std::vector<float> m_err_eT_flt; /// filtered parameter eT error - std::vector<float> m_pull_eLOC0_flt; /// filtered parameter eLOC0 pull - std::vector<float> m_pull_eLOC1_flt; /// filtered parameter eLOC1 pull - std::vector<float> m_x_flt; /// filtered global x - std::vector<float> m_y_flt; /// filtered global y - std::vector<float> m_z_flt; /// filtered global z - std::vector<float> m_px_flt; /// filtered momentum px - std::vector<float> m_py_flt; /// filtered momentum py - std::vector<float> m_pz_flt; /// filtered momentum pz - std::vector<float> m_eta_flt; /// filtered momentum eta - std::vector<float> m_pT_flt; /// filtered momentum pT - std::vector<float> m_chi2; /// chisq from filtering - - int m_nSmoothed{0}; /// number of states with smoothed parameter - std::vector<bool> m_smt; /// smoothed status - std::vector<float> m_eLOC0_smt; /// smoothed parameter eLOC0 - std::vector<float> m_eLOC1_smt; /// smoothed parameter eLOC1 - std::vector<float> m_ePHI_smt; /// smoothed parameter ePHI - std::vector<float> m_eTHETA_smt; /// smoothed parameter eTHETA - std::vector<float> m_eQOP_smt; /// smoothed parameter eQOP - std::vector<float> m_eT_smt; /// smoothed parameter eT - std::vector<float> m_res_eLOC0_smt; /// smoothed parameter eLOC0 residual - std::vector<float> m_res_eLOC1_smt; /// smoothed parameter eLOC1 residual - std::vector<float> m_err_eLOC0_smt; /// smoothed parameter eLOC0 error - std::vector<float> m_err_eLOC1_smt; /// smoothed parameter eLOC1 error - std::vector<float> m_err_ePHI_smt; /// smoothed parameter ePHI error - std::vector<float> m_err_eTHETA_smt; /// smoothed parameter eTHETA error - std::vector<float> m_err_eQOP_smt; /// smoothed parameter eQOP error - std::vector<float> m_err_eT_smt; /// smoothed parameter eT error - std::vector<float> m_pull_eLOC0_smt; /// smoothed parameter eLOC0 pull - std::vector<float> m_pull_eLOC1_smt; /// smoothed parameter eLOC1 pull - std::vector<float> m_x_smt; /// smoothed global x - std::vector<float> m_y_smt; /// smoothed global y - std::vector<float> m_z_smt; /// smoothed global z - std::vector<float> m_px_smt; /// smoothed momentum px - std::vector<float> m_py_smt; /// smoothed momentum py - std::vector<float> m_pz_smt; /// smoothed momentum pz - std::vector<float> m_eta_smt; /// smoothed momentum eta - std::vector<float> m_pT_smt; /// smoothed momentum pT - + SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "FaserActsKFTrackCollection", "FaserActsKFTrackCollection", "Output track collection" }; }; #endif diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h index 35baa239600d5f273dd91c2145eecfd8e1c8b52a..06924bed8e4adbe304697a4f71019d9134be72f8 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h @@ -6,82 +6,88 @@ #pragma once -#include <unordered_map> -#include <utility> - -// ACTS #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/TrackParameters.hpp" - -// PACKAGE #include "FaserActsKalmanFilter/IndexSourceLink.h" +#include <unordered_map> +#include <utility> -using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>; - -struct FaserActsRecMultiTrajectory -{ +/// Store reconstructed trajectories from track finding/fitting. +/// +/// It contains a MultiTrajectory with a vector of entry indices for +/// individual trajectories, and a map of fitted parameters indexed by the +/// entry index. In case of track fitting, there is at most one trajectory +/// in the MultiTrajectory; In case of track finding, there could be +/// multiple trajectories in the MultiTrajectory. +struct FaserActsRecMultiTrajectory { public: - FaserActsRecMultiTrajectory() = default; + /// (Reconstructed) trajectory with multiple states. + using MultiTrajectory = ::Acts::MultiTrajectory<IndexSourceLink>; + /// Fitted parameters identified by indices in the multi trajectory. + using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>; - FaserActsRecMultiTrajectory(const Acts::MultiTrajectory<IndexSourceLink>& multiTraj, - const std::vector<size_t>& tTips, - const IndexedParams& parameters) + /// Default construct an empty object. Required for container compatibility + /// and to signal an error. + FaserActsRecMultiTrajectory() = default; + /// Construct from fitted multi trajectory and parameters. + /// + /// @param multiTraj The multi trajectory + /// @param tTips Tip indices that identify valid trajectories + /// @param parameters Fitted track parameters indexed by trajectory index + FaserActsRecMultiTrajectory(const MultiTrajectory& multiTraj, + const std::vector<size_t>& tTips, + const IndexedParams& parameters) : m_multiTrajectory(multiTraj), m_trackTips(tTips), m_trackParameters(parameters) {} - FaserActsRecMultiTrajectory(const FaserActsRecMultiTrajectory& rhs) - : m_multiTrajectory(rhs.m_multiTrajectory), - m_trackTips(rhs.m_trackTips), - m_trackParameters(rhs.m_trackParameters) {} - - FaserActsRecMultiTrajectory(FaserActsRecMultiTrajectory&& rhs) - : m_multiTrajectory(std::move(rhs.m_multiTrajectory)), - m_trackTips(std::move(rhs.m_trackTips)), - m_trackParameters(std::move(rhs.m_trackParameters)) {} - - ~FaserActsRecMultiTrajectory() = default; - - FaserActsRecMultiTrajectory& operator=(const FaserActsRecMultiTrajectory& rhs) { - m_multiTrajectory = rhs.m_multiTrajectory; - m_trackTips = rhs.m_trackTips; - m_trackParameters = rhs.m_trackParameters; - return *this; - } + /// Return true if there exists no valid trajectory. + bool empty() const { return m_trackTips.empty(); } - FaserActsRecMultiTrajectory& operator=(FaserActsRecMultiTrajectory&& rhs) { - m_multiTrajectory = std::move(rhs.m_multiTrajectory); - m_trackTips = std::move(rhs.m_trackTips); - m_trackParameters = std::move(rhs.m_trackParameters); - return *this; - } + /// Access the underlying multi trajectory. + const MultiTrajectory& multiTrajectory() const { return m_multiTrajectory; } - bool hasTrajectory(const size_t& entryIndex) const { - return std::count(m_trackTips.begin(), m_trackTips.end(), entryIndex) > 0; - } + /// Access the tip indices that identify valid trajectories. + const std::vector<size_t>& tips() const { return m_trackTips; } - bool hasTrackParameters(const size_t& entryIndex) const { - return m_trackParameters.count(entryIndex) > 0; + /// Check if a trajectory exists for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return Whether there is trajectory with provided entry index + bool hasTrajectory(size_t entryIndex) const { + return (0 < std::count(m_trackTips.begin(), m_trackTips.end(), entryIndex)); } - std::pair<std::vector<size_t>, Acts::MultiTrajectory<IndexSourceLink>> - trajectory() const { - return std::make_pair(m_trackTips, m_multiTrajectory); + /// Check if fitted track parameters exists for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return Whether having fitted track parameters or not + bool hasTrackParameters(size_t entryIndex) const { + return (0 < m_trackParameters.count(entryIndex)); } - const Acts::BoundTrackParameters& trackParameters(const size_t& entryIndex) const { + /// Access the fitted track parameters for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return The fitted track parameters of the trajectory + const Acts::BoundTrackParameters& trackParameters(size_t entryIndex) const { auto it = m_trackParameters.find(entryIndex); - if (it != m_trackParameters.end()) { - return it->second; - } else { + if (it == m_trackParameters.end()) { throw std::runtime_error( "No fitted track parameters for trajectory with entry index = " + std::to_string(entryIndex)); } + return it->second; } - private: - Acts::MultiTrajectory<IndexSourceLink> m_multiTrajectory; +private: + // The multiTrajectory + MultiTrajectory m_multiTrajectory; + // The entry indices of trajectories stored in multiTrajectory std::vector<size_t> m_trackTips = {}; + // The fitted parameters at the provided surface for individual trajectories IndexedParams m_trackParameters = {}; }; + +/// Container for multiple trajectories. +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/GhostBusters.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/GhostBusters.h new file mode 100644 index 0000000000000000000000000000000000000000..f8ac55d6cbb62c20ac2de7ce9c8b5741a2bfe8cb --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/GhostBusters.h @@ -0,0 +1,75 @@ +#ifndef FASERACTSKALMANFILTER_GHOSTBUSTERS_H +#define FASERACTSKALMANFILTER_GHOSTBUSTERS_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrkTrack/TrackCollection.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "FaserActsKalmanFilter/TrackClassification.h" + + +class TTree; +class FaserSCT_ID; + +class GhostBusters : public AthReentrantAlgorithm, AthHistogramming { +public: + GhostBusters(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~GhostBusters() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + struct Segment { + public: + Segment(const Trk::Track *track, const FaserSCT_ID *idHelper); + // Segment(const Trk::Track *track, const TrackerSimDataCollection &simDataCollection, + // const FaserSCT_ID *idHelper); + inline int station() const { return m_station; } + inline Amg::Vector3D position() const { return m_position; } + inline double x() const { return m_position.x(); } + inline double y() const { return m_position.y(); } + inline double z() const { return m_position.z(); } + inline double chi2() const { return m_chi2; } + inline size_t size() const { return m_size; } + inline bool isGhost() const { return m_isGhost; } + // inline size_t majorityHits() const { return m_particleHitCounts.empty() ? -1 : m_particleHitCounts.front().hitCount; } + inline const Trk::Track *track() const { return m_track; } + inline void setGhost() { m_isGhost = true; } + private: + // std::vector<ParticleHitCount> m_particleHitCounts {}; + size_t m_size; + Amg::Vector3D m_position; + int m_station; + double m_chi2; + bool m_isGhost = false; + const Trk::Track *m_track; + }; + + ServiceHandle <ITHistSvc> m_histSvc; + SG::WriteHandleKey<TrackCollection> m_outputTrackCollection { this, "OutputCollection", "Segments", "Output track collection name" }; + SG::ReadHandleKey<TrackCollection> m_trackCollection { this, "TrackCollection", "SegmentFit", "Input track collection name" }; + // SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + DoubleProperty m_xTolerance {this, "xTolerance", 0.5}; + DoubleProperty m_yTolerance {this, "yTolerance", 0.25}; + + const FaserSCT_ID *m_idHelper; + + mutable TTree* m_tree; + mutable unsigned int m_event_number; + mutable double m_x; + mutable double m_y; + mutable double m_z; + mutable double m_chi2; + mutable unsigned int m_station; + // mutable unsigned int m_majorityHits; + mutable unsigned int m_size; + mutable bool m_isGhost; +}; + +inline const ServiceHandle <ITHistSvc> &GhostBusters::histSvc() const { + return m_histSvc; +} + +#endif // FASERACTSKALMANFILTER_GHOSTBUSTERS_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..6fbc80c422cb3d83122a7c9ec9524da527221d15 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h @@ -0,0 +1,27 @@ +#ifndef FASERACTSKALMANFILTER_ITRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_ITRACKFINDERTOOL_H + +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/IAlgTool.h" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/IdentifierLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "Acts/EventData/TrackParameters.hpp" + +class ITrackFinderTool : virtual public IAlgTool { +public: + DeclareInterfaceID(ITrackFinderTool, 1, 0); + + // TODO use Acts::BoundTrackParameters instead? + virtual StatusCode run() = 0; + virtual const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const = 0; + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const = 0; + virtual const std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> sourceLinks() const = 0; + virtual const std::shared_ptr<std::vector<IdentifierLink>> idLinks() const = 0; + virtual const std::shared_ptr<std::vector<std::vector<Measurement>>> measurements() const = 0; + virtual const std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> spacePoints() const = 0; + virtual const std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> clusters() const = 0; +}; + +#endif // FASERACTSKALMANFILTER_ITRACKFINDERTOOL_H \ No newline at end of file diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0b664f78ec6e60f1d75f504a343221970d0b938d --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h @@ -0,0 +1,29 @@ +#ifndef FASERACTSKALMANFILTER_ITRACKSEEDTOOL_H +#define FASERACTSKALMANFILTER_ITRACKSEEDTOOL_H + +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/IAlgTool.h" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/IdentifierLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" + +class ITrackSeedTool : virtual public IAlgTool { +public: + DeclareInterfaceID(ITrackSeedTool, 1, 0); + + virtual StatusCode run() = 0; + virtual const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const = 0; + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const = 0; + virtual const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const = 0; + virtual const std::shared_ptr<IdentifierLink> idLinks() const = 0; + virtual const std::shared_ptr<std::vector<Measurement>> measurements() const = 0; + virtual const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const = 0; + virtual const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const = 0; + virtual const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const = 0; + virtual double targetZPosition() const = 0; +}; + +#endif // FASERACTSKALMANFILTER_ITRACKSEEDTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IdentifierLink.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IdentifierLink.h new file mode 100644 index 0000000000000000000000000000000000000000..5d236afec358b683ee5812889656d353a62d4924 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IdentifierLink.h @@ -0,0 +1,10 @@ +#ifndef FASERACTSKALMANFILTER_IDENTIFIERLINK_H +#define FASERACTSKALMANFILTER_IDENTIFIERLINK_H + +#include "Identifier/Identifier.h" + +using Index = uint32_t; + +using IdentifierLink = std::map<Index, Identifier>; + +#endif // FASERACTSKALMANFILTER_IDENTIFIERLINK_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h index 99d101519030fca1d4fd7904bc7549b22a39a6c2..79973020943627dc32655fecb3a24437bb0c1284 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h @@ -15,6 +15,7 @@ #include <boost/container/flat_map.hpp> #include "FaserActsKalmanFilter/FaserActsGeometryContainers.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" /// Index type to reference elements in a container. /// @@ -34,10 +35,10 @@ using Index = uint32_t; class IndexSourceLink final { public: /// Construct from geometry identifier and index. - constexpr IndexSourceLink(Acts::GeometryIdentifier gid, Index idx) - : m_geometryId(gid), m_index(idx) {} + IndexSourceLink(Acts::GeometryIdentifier gid, Index idx, const Tracker::FaserSCT_Cluster* hit) + : m_geometryId(gid), m_index(idx), m_hit(hit) {} - // Construct an invalid source link. Must be default constructible to + // Construct an invalid source link. Must be default constructible to /// satisfy SourceLinkConcept. IndexSourceLink() = default; IndexSourceLink(const IndexSourceLink&) = default; @@ -49,10 +50,13 @@ public: constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; } /// Access the index. constexpr Index index() const { return m_index; } + /// Access the Tracker::FaserSCT_Cluster hit + constexpr const Tracker::FaserSCT_Cluster* hit() const { return m_hit; } private: Acts::GeometryIdentifier m_geometryId; Index m_index; + const Tracker::FaserSCT_Cluster* m_hit; friend constexpr bool operator==(const IndexSourceLink& lhs, const IndexSourceLink& rhs) { diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..8bf92e91580d7d1839fe2ebfaf78bdaba73295a3 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h @@ -0,0 +1,72 @@ +#ifndef FASERACTSKALMANFILTER_KALMANFITTERTOOL_H +#define FASERACTSKALMANFILTER_KALMANFITTERTOOL_H + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "MagFieldConditions/FaserFieldCacheCondObj.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h" +#include "TrkTrack/Track.h" + + +class FaserSCT_ID; + +class KalmanFitterTool : virtual public AthAlgTool { +public: + KalmanFitterTool(const std::string &type, const std::string &name, const IInterface *parent); + virtual ~KalmanFitterTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + using TrackParameters = Acts::BoundTrackParameters; + using IndexedParams = std::unordered_map<size_t, TrackParameters>; + using TrackFitterOptions = + Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>; + using TrackFitterResult = Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>; + class TrackFitterFunction { + public: + virtual ~TrackFitterFunction() = default; + virtual TrackFitterResult operator()(const std::vector<IndexSourceLink>&, + const TrackParameters&, + const TrackFitterOptions&) const = 0; + }; + static std::shared_ptr<TrackFitterFunction> makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); + + virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; + std::unique_ptr<Trk::Track> fit(const EventContext &ctx, const Acts::GeometryContext &gctx, const Trk::Track &inputTrack, + std::vector<FaserActsRecMultiTrajectory> & /*trajectories*/, + const Acts::BoundVector& inputVector = Acts::BoundVector::Zero(), bool isMC=false, double origin=0) const; + +private: + const FaserSCT_ID* m_idHelper {nullptr}; + std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>> + getMeasurementsFromTrack(const Trk::Track &track) const; + // Acts::BoundTrackParameters getParametersFromTrack(const Acts::BoundVector& params, const Trk::TrackParameters *inputParameters) const; + Acts::BoundTrackParameters getParametersFromTrack(const Trk::TrackParameters *inputParameters, const Acts::BoundVector& inputVector, double origin) const; + std::shared_ptr<TrackFitterFunction> m_fit; + std::unique_ptr<const Acts::Logger> m_logger; + Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"}; + Gaudi::Property<std::size_t> m_minMeasurements {this, "MinMeasurements", 12, "minimum number of measurements of the input track"}; + Gaudi::Property<double> m_seedCovarianceScale {this, "SeedCovarianceScale", 100, "scale covariance from initial track"}; + Gaudi::Property<bool> m_isMC {this, "isMC", false}; + Gaudi::Property<bool> m_summaryWriter {this, "SummaryWriter", false}; + Gaudi::Property<bool> m_statesWriter {this, "StatesWriter", false}; + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + + SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"}; + ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"}; + std::unique_ptr<Trk::Track> makeTrack(const Acts::GeometryContext &gctx, TrackFitterResult& fitResult) const; + const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; +}; + +#endif //FASERACTSKALMANFILTER_KALMANFITTERTOOL_H + diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/LinearFit.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/LinearFit.h new file mode 100644 index 0000000000000000000000000000000000000000..f367110a4b7a05cb9bc610628995cfa6df53ddb0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/LinearFit.h @@ -0,0 +1,26 @@ +#ifndef FASERACTSKALMANFILTER_LINEARFIT_H +#define FASERACTSKALMANFILTER_LINEARFIT_H + +#include "Acts/Definitions/Algebra.hpp" + +namespace LinearFit { + +using Vector2 = Acts::Vector2; + +std::pair <Vector2, Vector2 > linearFit(const std::vector<Vector2> &points) { + size_t nPoints = points.size(); + Eigen::Matrix< Vector2::Scalar, Eigen::Dynamic, Eigen::Dynamic > centers(nPoints, 2); + for (size_t i = 0; i < nPoints; ++i) centers.row(i) = points[i]; + + Vector2 origin = centers.colwise().mean(); + Eigen::MatrixXd centered = centers.rowwise() - origin.transpose(); + Eigen::MatrixXd cov = centered.adjoint() * centered; + Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov); + Vector2 axis = eig.eigenvectors().col(1).normalized(); + + return std::make_pair(origin, axis); +} + +} // namespace LinearFit + +#endif // FASERACTSKALMANFILTER_LINEARFIT_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MultiTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MultiTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..56e5db2666157c330e91258776b3a6b34af44278 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MultiTrackFinderTool.h @@ -0,0 +1,232 @@ +#ifndef FASERACTSKALMANFILTER_MULTITRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_MULTITRACKFINDERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/ReadHandleKey.h" +#include <string> +#include <vector> + +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrkTrack/TrackCollection.h" + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +class MultiTrackFinderTool : public extends<AthAlgTool, ITrackFinderTool> { +public: + MultiTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~MultiTrackFinderTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + virtual const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const override; + virtual const std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> sourceLinks() const override; + virtual const std::shared_ptr<std::vector<IdentifierLink>> idLinks() const override; + virtual const std::shared_ptr<std::vector<std::vector<Measurement>>> measurements() const override; + virtual const std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> spacePoints() const override; + virtual const std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> clusters() const override; + + struct Tracklet { + public: + Tracklet(const std::vector<Identifier>& ids, + const std::vector<Acts::GeometryIdentifier>& geoIds, + const std::vector<double>& positions, + const Amg::Vector3D& fitPosition, + const std::vector<const Tracker::FaserSCT_Cluster*>& clusters) + : m_ids(ids), m_geoIds(geoIds), m_positions(positions), m_fitPosition(fitPosition), m_clusters(clusters) {}; + + std::vector<Identifier> ids() const { return m_ids; }; + std::vector<Acts::GeometryIdentifier> geoIds() const { return m_geoIds; } + std::vector<double> clusterPositions() const { return m_positions; } + const std::vector<const Tracker::FaserSCT_Cluster*>& clusters() const { return m_clusters; } + Amg::Vector3D position() const { return m_fitPosition; } + + private: + std::vector<Identifier> m_ids; + std::vector<Acts::GeometryIdentifier> m_geoIds; + std::vector<double> m_positions; + Amg::Vector3D m_fitPosition; + std::vector<const Tracker::FaserSCT_Cluster*> m_clusters; + }; + + struct ProtoTrack { + public: + ProtoTrack(const MultiTrackFinderTool::Tracklet& t1, + const MultiTrackFinderTool::Tracklet& t2, + const MultiTrackFinderTool::Tracklet& t3) + : m_t1(t1), m_t2(t2), m_t3(t3) {} + + Acts::CurvilinearTrackParameters initialTrackParameters( + double covLoc0, double covLoc1, double covPhi, double covTheta, double covQOverP, double covTime) const { + Acts::Vector3 dir = m_t2.position() - m_t1.position(); + Acts::Vector3 pos = m_t1.position() - m_t1.position().z()/dir.z() * dir; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + auto [abs_momentum, charge] = momentum({{1, m_t1.position()}, {2, m_t2.position()}, {3, m_t3.position()}}); + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = covTime; + + Acts::CurvilinearTrackParameters params = + Acts::CurvilinearTrackParameters(pos4, dir, abs_momentum, charge, cov); + return params; + } + + std::tuple<std::vector<Measurement>, std::vector<IndexSourceLink>, std::map<Index, Identifier>, std::vector<const Tracker::FaserSCT_Cluster*>> run() const { + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::map<Index, Identifier> idLinks; + std::vector<Measurement> measurements; + std::vector<const Tracker::FaserSCT_Cluster*> clusters; + clusters.reserve(m_t1.clusters().size() + m_t2.clusters().size() + m_t3.clusters().size()); + clusters.insert(clusters.end(), m_t1.clusters().begin(), m_t1.clusters().end()); + clusters.insert(clusters.end(), m_t2.clusters().begin(), m_t2.clusters().end()); + clusters.insert(clusters.end(), m_t3.clusters().begin(), m_t3.clusters().end()); + + for (const MultiTrackFinderTool::Tracklet& tracklet : {m_t1, m_t2, m_t3}) { + // FIXME check that ids, geoIds and positions have the same size + auto ids = tracklet.ids(); + auto geoIds = tracklet.geoIds(); + auto positions = tracklet.clusterPositions(); + for (size_t i = 0; i < tracklet.ids().size(); ++i) { + idLinks[measurements.size()] = ids[i]; + IndexSourceLink sourceLink(geoIds[i], measurements.size()); + Eigen::Matrix<double, 1, 1> clusterPos {positions[i]}; + Eigen::Matrix<double, 1, 1> clusterCov {0.04 * 0.04,}; + ThisMeasurement meas(sourceLink, Indices, clusterPos, clusterCov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + } + } + return std::make_tuple(measurements, sourceLinks, idLinks, clusters); + } + + double chi2() const { + return calc_chi2({m_t1.position(), m_t2.position(), m_t3.position()}); + } + + private: + Tracklet m_t1, m_t2, m_t3; + + static std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57) { + Acts::Vector3 vec_l = pos.at(3) - pos.at(1); + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos.at(2).z() - pos.at(1).z()) / (pos.at(3).z() - pos.at(1).z()); + Acts::Vector3 vec_m = pos.at(1) + t * vec_l; + Acts::Vector3 vec_s = pos.at(2) - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); + double charge = vec_s.y() < 0 ? 1 : -1; + return std::make_pair(p_yz, charge); + } + + static std::pair<Acts::Vector3, Acts::Vector3> linear_fit(const std::vector<Acts::Vector3>& hits) { + size_t n_hits = hits.size(); + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> centers(n_hits, 3); + for (size_t i = 0; i < n_hits; ++i) centers.row(i) = hits[i]; + Acts::Vector3 origin = centers.colwise().mean(); + Eigen::MatrixXd centered = centers.rowwise() - origin.transpose(); + Eigen::MatrixXd cov = centered.adjoint() * centered; + Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov); + Acts::Vector3 axis = eig.eigenvectors().col(2).normalized(); + return std::make_pair(origin, axis); + } + + double calc_chi2(const std::vector<Acts::Vector3>& hits) const { + auto [origin, axis] = linear_fit(hits); + double chi2 = 0; + for (const Acts::Vector3& hit : hits) { + Acts::Vector3 exp = origin + (hit.z() - origin.z()) * axis/axis.z(); + chi2 += (exp.x() - hit.x()) * (exp.x() - hit.x()) + (exp.y() - hit.y()) * (exp.y() - hit.y()); + } + return chi2; + } + }; + + struct sort_chi2 { + inline bool operator() (const ProtoTrack& track1, const ProtoTrack& track2) { + return (track1.chi2() < track2.chi2()); + } + }; + +private: + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> m_sourceLinks {}; + std::shared_ptr<std::vector<IdentifierLink>> m_idLinks {}; + std::shared_ptr<std::vector<std::vector<Measurement>>> m_measurements {}; + std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> m_spacePoints {}; + std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> m_clusters {}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +MultiTrackFinderTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +MultiTrackFinderTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> +MultiTrackFinderTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<std::vector<IdentifierLink>> +MultiTrackFinderTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<std::vector<Measurement>>> +MultiTrackFinderTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> +MultiTrackFinderTool::spacePoints() const { + return m_spacePoints; +} + +inline const std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> +MultiTrackFinderTool::clusters() const { + return m_clusters; +} + +#endif // FASERACTSKALMANFILTER_MULTITRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyAmbiguitySolver.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyAmbiguitySolver.h new file mode 100644 index 0000000000000000000000000000000000000000..47257befa2fcbd70da95d1ee88bd41d0fdabeb2a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyAmbiguitySolver.h @@ -0,0 +1,80 @@ +#ifndef FASERACTSKALMANFILTER_AMBIGUITYSOLVER_H +#define FASERACTSKALMANFILTER_AMBIGUITYSOLVER_H + +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" + +using CombinatorialKalmanFilterResult = Acts::CombinatorialKalmanFilterResult<IndexSourceLink>; +using TrackFitterResult = Acts::Result<CombinatorialKalmanFilterResult>; +using TrackFinderResult = std::vector<TrackFitterResult>; + + +size_t numberMeasurements(const CombinatorialKalmanFilterResult& ckfResult) { + auto traj = FaserActsRecMultiTrajectory(ckfResult.fittedStates, ckfResult.lastMeasurementIndices, ckfResult.fittedParameters); + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + size_t maxMeasurements = 0; + for (const auto& trackTip : trackTips) { + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); + size_t nMeasurements = trajState.nMeasurements; + if (nMeasurements > maxMeasurements) { + maxMeasurements = nMeasurements; + } + std::cout << "# measurements: " << trajState.nMeasurements << std::endl; + } + return maxMeasurements; +} + +int countSharedHits(const CombinatorialKalmanFilterResult& result1, const CombinatorialKalmanFilterResult& result2) { + int count = 0; + std::vector<size_t> hitIndices {}; + + for (auto measIndex : result1.lastMeasurementIndices) { + result1.fittedStates.visitBackwards(measIndex, [&](const auto& state) { + if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + return; + size_t hitIndex = state.uncalibrated().index(); + hitIndices.emplace_back(hitIndex); + }); + } + + for (auto measIndex : result2.lastMeasurementIndices) { + result2.fittedStates.visitBackwards(measIndex, [&](const auto& state) { + if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + return; + size_t hitIndex = state.uncalibrated().index(); + if (std::find(hitIndices.begin(), hitIndices.end(), hitIndex) != hitIndices.end()) { + count += 1; + } + }); + } + return count; +} + + +std::pair<int, int> solveAmbiguity(TrackFinderResult& results, size_t minMeasurements = 13) { + std::map<std::pair<size_t, size_t>, size_t> trackPairs {}; + for (size_t i = 0; i < results.size(); ++i) { + // if (not results.at(i).ok()) continue; + // if (numberMeasurements(results.at(i).value()) < minMeasurements) continue; + for (size_t j = i+1; j < results.size(); ++j) { + // if (not results.at(j).ok()) continue; + // if (numberMeasurements(results.at(j).value()) < minMeasurements) continue; + int n = countSharedHits(results.at(i).value(), results.at(j).value()); + trackPairs[std::make_pair(i, j)] = n; + } + } + + std::pair<size_t, size_t> bestTrackPair; + size_t minSharedHits = std::numeric_limits<size_t>::max(); + for (const auto& trackPair : trackPairs) { + if (trackPair.second < minSharedHits) { + minSharedHits = trackPair.second; + bestTrackPair = trackPair.first; + } + } + + return bestTrackPair; +} + +#endif //FASERACTSKALMANFILTER_AMBIGUITYSOLVER_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..abc4e987434c536b37a20862bef87fc5fe8cbbac --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h @@ -0,0 +1,123 @@ +#ifndef FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H +#define FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" + +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "TrkTrack/TrackCollection.h" +#include <memory> +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { class SCT_DetectorManager; } + + +class MyTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> { +public: + MyTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~MyTrackSeedTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + const std::shared_ptr<const Acts::Surface> initialSurface() const override; + const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + const std::shared_ptr<IdentifierLink> idLinks() const override; + const std::shared_ptr<std::vector<Measurement>> measurements() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override; + const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override; + double targetZPosition() const override; + +private: + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {}; + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {}; + double m_targetZPosition {0.}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { + this, "ClusterContainer", "SCT_ClusterContainer"}; + SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey { + this, "SpacePoints", "SCT_SpacePointContainer"}; + + // position resolution of a cluster + Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.04}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; + Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"}; + + static Acts::CurvilinearTrackParameters get_params(const Amg::Vector3D& p1, const Amg::Vector3D& p2, const Acts::BoundSymMatrix& cov, double origin); + // static std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57); +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +MyTrackSeedTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +MyTrackSeedTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> +MyTrackSeedTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +MyTrackSeedTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> +MyTrackSeedTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> +MyTrackSeedTool::clusters() const { + return m_clusters; +} + +inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> +MyTrackSeedTool::seedClusters() const { + return m_seedClusters; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> +MyTrackSeedTool::spacePoints() const { + return m_spacePoints; +} + +inline double MyTrackSeedTool::targetZPosition() const { + return m_targetZPosition; +} + +#endif // FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PerformanceWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PerformanceWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..198e4515988226e71e76c07b1a812ca00e64c641 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PerformanceWriterTool.h @@ -0,0 +1,51 @@ +#ifndef FASERACTSKALMANFILTER_PERFORMANCEWRITER_H +#define FASERACTSKALMANFILTER_PERFORMANCEWRITER_H + +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserActsKalmanFilter/ResPlotTool.h" +#include "FaserActsKalmanFilter/EffPlotTool.h" +#include "FaserActsKalmanFilter/SummaryPlotTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "GeneratorObjects/McEventCollection.h" +#include "Acts/Geometry/GeometryContext.hpp" +class TFile; +struct FaserActsRecMultiTrajectory; +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; + +class PerformanceWriterTool : public AthAlgTool { +public: + PerformanceWriterTool(const std::string& type, const std::string& name, const IInterface* parent); + ~PerformanceWriterTool() override = default; + + StatusCode initialize() override; + StatusCode finalize() override; + + StatusCode write(const Acts::GeometryContext& geoContext, const TrajectoriesContainer& trajectories); + +private: + std::unique_ptr<const Acts::BoundTrackParameters> extrapolateToReferenceSurface( + const EventContext& ctx, const HepMC::GenParticle* particle) const; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { + this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey { + this, "McEventCollection", "BeamTruthEvent"}; + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { + this, "ExtrapolationTool", "FaserActsExtrapolationTool"}; + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + Gaudi::Property<std::string> m_filePath{this, "FilePath", "performance_ckf.root"}; + TFile* m_outputFile{nullptr}; + + /// Plot tool for residuals and pulls. + ResPlotTool m_resPlotTool; + ResPlotTool::ResPlotCache m_resPlotCache; + /// Plot tool for efficiency + EffPlotTool m_effPlotTool; + EffPlotTool::EffPlotCache m_effPlotCache; + /// Plot tool for track hit info + SummaryPlotTool m_summaryPlotTool; + SummaryPlotTool::SummaryPlotCache m_summaryPlotCache; +}; + +#endif // FASERACTSKALMANFILTER_PERFORMANCEWRITER_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PlotHelpers.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PlotHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..c3e8a1caf22d1debbea709c8fbbfe3c8a1b695c2 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/PlotHelpers.h @@ -0,0 +1,113 @@ +#ifndef FASERACTSKALMANFILTER_PLOTHELPERS_H +#define FASERACTSKALMANFILTER_PLOTHELPERS_H + +#include "TEfficiency.h" +#include "TFitResult.h" +#include "TFitResultPtr.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TProfile.h" +#include <string> + +namespace PlotHelpers { + +struct Binning { + Binning() = default; + + Binning(std::string bTitle, int bins, float bMin, float bMax) + : title(bTitle), nBins(bins), min(bMin), max(bMax) {}; + + std::string title; ///< title to be displayed + int nBins; ///< number of bins + float min; ///< minimum value + float max; ///< maximum value +}; + + +/// @brief book a 1D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varBinning the binning info of variable +/// @return histogram pointer +TH1F *bookHisto(const char *histName, const char *histTitle, + const Binning &varBinning); + +/// @brief book a 2D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return histogram pointer +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D histogram +/// @param hist histogram to fill +/// @param value value to fill +/// @param weight weight to fill +void fillHisto(TH1F* hist, float value, float weight = 1.0); + +/// @brief fill a 2D histogram +/// @param hist histogram to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param weight weight to fill +void fillHisto(TH2F* hist, float xValue, float yValue, float weight = 1.0); + +/// @brief extract details, i.e. mean and width of a 1D histogram and fill +/// them into histograms +/// @param inputHist histogram to investigate +/// @param j which bin number of meanHist and widthHist to fill +/// @param meanHist histogram to fill the mean value of inputHist +/// @param widthHist histogram to fill the width value of inputHist +/// +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist); + +/// @brief book a 1D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varBinning the binning info of variable +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, const Binning& varBinning); + +/// @brief book a 2D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D efficiency plot +/// @param efficiency plot to fill +/// @param value value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float value, bool status); + +/// @brief fill a 2D efficiency plot +/// @param efficiency plot to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status); + +/// @brief book a TProfile plot +/// @param profName the name of plot +/// @param profTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TProfile pointer +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a TProfile plot +/// @param profile plot to fill +/// @param xValue xvalue to fill +/// @param yValue yvalue to fill +/// @param weight weight to fill +void fillProf(TProfile* profile, float xValue, float yValue, float weight = 1.0); + +} // namespace PlotHelpers + +#endif // FASERACTSKALMANFILTER_PLOTHELPERS_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ProtoTrackWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ProtoTrackWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..a71ddb56ab7b70af4930fc5cd1369010a5e7446b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ProtoTrackWriterTool.h @@ -0,0 +1,61 @@ +#ifndef FASERACTSKALMANFILTER_PROTOTRACKWRITERTOOL_H +#define FASERACTSKALMANFILTER_PROTOTRACKWRITERTOOL_H + +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "GaudiKernel/ToolHandle.h" +#include <memory> +#include <string> +#include <vector> + +#include "Acts/EventData/TrackParameters.hpp" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "FaserActsKalmanFilter/Measurement.h" + +class FaserSCT_ID; +class TFile; +class TTree; + +class ProtoTrackWriterTool : public AthAlgTool { +public: + ProtoTrackWriterTool(const std::string& type, const std::string& name, + const IInterface* parent); + virtual ~ProtoTrackWriterTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + StatusCode write(std::shared_ptr<const Acts::CurvilinearTrackParameters> protoTrackParameters, + std::shared_ptr<std::vector<Measurement>> measurements, + const Acts::GeometryContext& ctx) const; + +private: + const FaserSCT_ID* m_idHelper{nullptr}; + + ToolHandle<ITrackFinderTool> m_trackFinderTool {this, "TrackFinderTool", "TruthTrackFinderTool"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + Gaudi::Property<std::string> m_filePath {this, "File", "ProtoTracks.root", "Root file"}; + TFile* m_file; + TTree* m_params; + TTree* m_meas; + + mutable int m_run_number; + mutable int m_event_number; + mutable double m_x; + mutable double m_y; + mutable double m_z; + mutable double m_px; + mutable double m_py; + mutable double m_pz; + mutable int m_station; + mutable int m_layer; + mutable int m_phi; + mutable int m_eta; + mutable int m_side; + mutable double m_meas_eLOC0; + mutable double m_meas_eLOC1; +}; + +#endif // FASERACTSKALMANFILTER_PROTOTRACKWRITERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ResPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ResPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0b65984bed7e7de4c7975fdf9cc67248c253dab7 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ResPlotTool.h @@ -0,0 +1,87 @@ +#ifndef FASERACTSKALMANFILTER_RESPLOTTOOL_H +#define FASERACTSKALMANFILTER_RESPLOTTOOL_H + +#include "FaserActsKalmanFilter/PlotHelpers.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "HepMC/GenParticle.h" +#include "TH1F.h" +#include "TH2F.h" +#include <map> +#include <string> +#include <vector> + +class ResPlotTool { +public: + std::vector<std::string> m_paramNames = {"x0", "y0", "phi", "theta", "qop", "t"}; + std::map<std::string, PlotHelpers::Binning> m_varBinning { + {"Eta", PlotHelpers::Binning("#eta", 40, 4, 12)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 20)}, + {"Pull", PlotHelpers::Binning("pull", 100, -5, 5)}, + {"Residual_x0", PlotHelpers::Binning("r_{x0} [mm]", 100, -0.1, 0.1)}, + {"Residual_y0", PlotHelpers::Binning("r_{y0} [mm]", 100, -4, 4)}, + {"Residual_phi", PlotHelpers::Binning("r_{#phi} [rad]", 100, -0.3, 0.3)}, + {"Residual_theta", PlotHelpers::Binning("r_{#theta} [rad]", 100, -0.002, 0.002)}, + {"Residual_qop", PlotHelpers::Binning("r_{q/p} [c/GeV]", 100, -0.002, 0.002)}, + {"Residual_t", PlotHelpers::Binning("r_{t} [s]", 100, -1000, 1000)}, + }; + + /// @brief Nested Cache struct + struct ResPlotCache { + std::map<std::string, TH1F*> res; ///< Residual distribution + std::map<std::string, TH2F*> res_vs_eta; ///< Residual vs eta scatter plot + std::map<std::string, TH1F*> resMean_vs_eta; ///< Residual mean vs eta distribution + std::map<std::string, TH1F*> resWidth_vs_eta; ///< Residual width vs eta distribution + std::map<std::string, TH2F*> res_vs_pT; ///< Residual vs pT scatter plot + std::map<std::string, TH1F*> resMean_vs_pT; ///< Residual mean vs pT distribution + std::map<std::string, TH1F*> resWidth_vs_pT; ///< Residual width vs pT distribution + + std::map<std::string, TH1F*> pull; ///< Pull distribution + std::map<std::string, TH2F*> pull_vs_eta; ///< Pull vs eta scatter plot + std::map<std::string, TH1F*> pullMean_vs_eta; ///< Pull mean vs eta distribution + std::map<std::string, TH1F*> pullWidth_vs_eta; ///< Pull width vs eta distribution + std::map<std::string, TH2F*> pull_vs_pT; ///< Pull vs pT scatter plot + std::map<std::string, TH1F*> pullMean_vs_pT; ///< Pull mean vs pT distribution + std::map<std::string, TH1F*> pullWidth_vs_pT; ///< Pull width vs pT distribution + }; + + /// Constructor + /// + ResPlotTool() = default; + + /// @brief book the histograms + /// + /// @param resPlotCache the cache for residual/pull histograms + void book(ResPlotCache& resPlotCache) const; + + /// @brief fill the histograms + /// + /// @param resPlotCache the cache for residual/pull histograms + /// @param gctx the geometry context + /// @param truthParticle the truth particle + /// @param fittedParamters the fitted parameters at perigee surface + void fill(ResPlotCache& resPlotCache, const Acts::GeometryContext& gctx, + std::unique_ptr<const Acts::BoundTrackParameters> truthParameters, + const Acts::BoundTrackParameters& fittedParameters) const; + + /// @brief extract the details of the residual/pull plots and fill details + /// + /// into separate histograms + /// @param resPlotCache the cache object for residual/pull histograms + void refinement(ResPlotCache& resPlotCache) const; + + /// @brief write the histograms to output file + /// + /// @param resPlotCache the cache object for residual/pull histograms + void write(const ResPlotCache& resPlotCache) const; + + /// @brief delele the histograms + /// + /// @param resPlotCache the cache object for residual/pull histograms + void clear(ResPlotCache& resPlotCache) const; + +private: + const double m_MeV2GeV = 0.001; +}; + +#endif // FASERACTSKALMANFILTER_RESPLOTTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..6f0885d33ec1200edbd28761352a36840fd11e47 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h @@ -0,0 +1,130 @@ +#ifndef FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H +#define FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "GeneratorObjects/McEventCollection.h" +#include <array> +#include <string> +#include <vector> + + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} +class TFile; +class TTree; +struct FaserActsRecMultiTrajectory; +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; + +class RootTrajectoryStatesWriterTool : public AthAlgTool { +public: + RootTrajectoryStatesWriterTool(const std::string& type, const std::string& name, const IInterface* parent); + ~RootTrajectoryStatesWriterTool() override = default; + + StatusCode initialize() override; + StatusCode finalize() override; + + StatusCode write(const Acts::GeometryContext& gctx, const TrajectoriesContainer& trajectories, bool isMC) const; + +private: + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "TruthEvent"}; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey {this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey {this, "FaserSiHitCollection", "SCT_Hits"}; + + const double m_MeV2GeV = 0.001; + + const FaserSCT_ID* m_idHelper{nullptr}; + const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr}; + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + Gaudi::Property<std::string> m_filePath {this, "FilePath", "track_states_ckf.root", "Output root file"}; + Gaudi::Property<std::string> m_treeName {this, "TreeName", "tree", "Tree name"}; + Gaudi::Property<bool> m_mc {this, "MC", false}; + TFile* m_outputFile; + TTree* m_outputTree; + + mutable uint32_t m_eventNr{0}; ///< the event number + mutable uint32_t m_multiTrajNr{0}; ///< the multi-trajectory number + mutable unsigned int m_subTrajNr{0}; ///< the multi-trajectory sub-trajectory number + + mutable std::vector<float> m_t_x; ///< Global truth hit position x + mutable std::vector<float> m_t_y; ///< Global truth hit position y + mutable std::vector<float> m_t_z; ///< Global truth hit position z + mutable std::vector<float> m_t_dx; ///< Truth particle direction x at global hit position + mutable std::vector<float> m_t_dy; ///< Truth particle direction y at global hit position + mutable std::vector<float> m_t_dz; ///< Truth particle direction z at global hit position + + mutable std::vector<float> m_t_eLOC0; ///< truth parameter eBoundLoc0 + mutable std::vector<float> m_t_eLOC1; ///< truth parameter eBoundLoc1 + mutable std::vector<float> m_t_ePHI; ///< truth parameter ePHI + mutable std::vector<float> m_t_eTHETA; ///< truth parameter eTHETA + mutable std::vector<float> m_t_eQOP; ///< truth parameter eQOP + mutable std::vector<float> m_t_eT; ///< truth parameter eT + + mutable unsigned int m_nStates{0}; ///< number of all states + mutable unsigned int m_nMeasurements{0}; ///< number of states with measurements + mutable std::vector<int> m_volumeID; ///< volume identifier + mutable std::vector<int> m_layerID; ///< layer identifier + mutable std::vector<int> m_moduleID; ///< surface identifier + mutable std::vector<int> m_station; ///< station + mutable std::vector<int> m_layer; ///< layer + mutable std::vector<int> m_phi_module; ///< phi module (rows) + mutable std::vector<int> m_eta_module; ///< eta module (columns) + mutable std::vector<int> m_side; ///< module side + mutable std::vector<float> m_pathLength; ///< path length + mutable std::vector<float> m_lx_hit; ///< uncalibrated measurement local x + mutable std::vector<float> m_ly_hit; ///< uncalibrated measurement local y + mutable std::vector<float> m_x_hit; ///< uncalibrated measurement global x + mutable std::vector<float> m_y_hit; ///< uncalibrated measurement global y + mutable std::vector<float> m_z_hit; ///< uncalibrated measurement global z + mutable std::vector<float> m_res_x_hit; ///< hit residual x + mutable std::vector<float> m_res_y_hit; ///< hit residual y + mutable std::vector<float> m_err_x_hit; ///< hit err x + mutable std::vector<float> m_err_y_hit; ///< hit err y + mutable std::vector<float> m_pull_x_hit; ///< hit pull x + mutable std::vector<float> m_pull_y_hit; ///< hit pull y + mutable std::vector<int> m_dim_hit; ///< dimension of measurement + + mutable std::array<int, 3> m_nParams; ///< number of states which have filtered/predicted/smoothed parameters + mutable std::array<std::vector<bool>, 3> m_hasParams; ///< status of the filtered/predicted/smoothed parameters + mutable std::array<std::vector<float>, 3> m_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 + mutable std::array<std::vector<float>, 3> m_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 + mutable std::array<std::vector<float>, 3> m_ePHI; ///< predicted/filtered/smoothed parameter ePHI + mutable std::array<std::vector<float>, 3> m_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA + mutable std::array<std::vector<float>, 3> m_eQOP; ///< predicted/filtered/smoothed parameter eQOP + mutable std::array<std::vector<float>, 3> m_eT; ///< predicted/filtered/smoothed parameter eT + mutable std::array<std::vector<float>, 3> m_res_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 residual + mutable std::array<std::vector<float>, 3> m_res_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 residual + mutable std::array<std::vector<float>, 3> m_res_ePHI; ///< predicted/filtered/smoothed parameter ePHI residual + mutable std::array<std::vector<float>, 3> m_res_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA residual + mutable std::array<std::vector<float>, 3> m_res_eQOP; ///< predicted/filtered/smoothed parameter eQOP residual + mutable std::array<std::vector<float>, 3> m_res_eT; ///< predicted/filtered/smoothed parameter eT residual + mutable std::array<std::vector<float>, 3> m_err_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 error + mutable std::array<std::vector<float>, 3> m_err_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 error + mutable std::array<std::vector<float>, 3> m_err_ePHI; ///< predicted/filtered/smoothed parameter ePHI error + mutable std::array<std::vector<float>, 3> m_err_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA error + mutable std::array<std::vector<float>, 3> m_err_eQOP; ///< predicted/filtered/smoothed parameter eQOP error + mutable std::array<std::vector<float>, 3> m_err_eT; ///< predicted/filtered/smoothed parameter eT error + mutable std::array<std::vector<float>, 3> m_pull_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 pull + mutable std::array<std::vector<float>, 3> m_pull_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 pull + mutable std::array<std::vector<float>, 3> m_pull_ePHI; ///< predicted/filtered/smoothed parameter ePHI pull + mutable std::array<std::vector<float>, 3> m_pull_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA pull + mutable std::array<std::vector<float>, 3> m_pull_eQOP; ///< predicted/filtered/smoothed parameter eQOP pull + mutable std::array<std::vector<float>, 3> m_pull_eT; ///< predicted/filtered/smoothed parameter eT pull + mutable std::array<std::vector<float>, 3> m_x; ///< predicted/filtered/smoothed parameter global x + mutable std::array<std::vector<float>, 3> m_y; ///< predicted/filtered/smoothed parameter global y + mutable std::array<std::vector<float>, 3> m_z; ///< predicted/filtered/smoothed parameter global z + mutable std::array<std::vector<float>, 3> m_px; ///< predicted/filtered/smoothed parameter px + mutable std::array<std::vector<float>, 3> m_py; ///< predicted/filtered/smoothed parameter py + mutable std::array<std::vector<float>, 3> m_pz; ///< predicted/filtered/smoothed parameter pz + mutable std::array<std::vector<float>, 3> m_eta; ///< predicted/filtered/smoothed parameter eta + mutable std::array<std::vector<float>, 3> m_pT; ///< predicted/filtered/smoothed parameter pT + + mutable std::vector<float> m_chi2; ///< chisq from filtering +}; + +#endif // FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..90cf6cf84ca8a95b41397bd00dea30d85135967f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h @@ -0,0 +1,118 @@ +#ifndef FASERACTSKALMANFILTER_ROOTTRAJECTORYSUMMARYWRITERTOOL_H +#define FASERACTSKALMANFILTER_ROOTTRAJECTORYSUMMARYWRITERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "FaserActsKalmanFilter/IdentifierLink.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "GeneratorObjects/McEventCollection.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include <array> +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} +class TFile; +class TTree; +struct FaserActsRecMultiTrajectory; +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; + +class RootTrajectorySummaryWriterTool : public AthAlgTool { +public: + RootTrajectorySummaryWriterTool(const std::string& type, const std::string& name, const IInterface* parent); + ~RootTrajectorySummaryWriterTool() override = default; + StatusCode write( const Acts::GeometryContext& geoContext, const TrajectoriesContainer& trajectories, bool isMC) const; + StatusCode initialize() override; + StatusCode finalize() override; + +private: + std::unique_ptr<const Acts::BoundTrackParameters> extrapolateToReferenceSurface( + const EventContext& ctx, const HepMC::GenParticle* particle) const; + const FaserSCT_ID* m_idHelper {nullptr}; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey { + this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey { + this, "McEventCollection", "TruthEvent"}; + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { + this, "ExtrapolationTool", "FaserActsExtrapolationTool"}; + + Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"}; + Gaudi::Property<std::string> m_filePath{this, "FilePath", "track_summary_ckf.root", "Output root file"}; + Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", "Tree name"}; + + const double m_MeV2GeV = 0.001; + + TFile* m_outputFile; + TTree* m_outputTree; + mutable uint32_t m_eventNr{0}; ///< The event number + mutable std::vector<uint32_t> m_multiTrajNr; ///< The multi-trajectory numbers in event + mutable std::vector<unsigned int> m_subTrajNr; ///< The multi-trajectory sub-trajectory number in event + + mutable std::vector<unsigned int> m_nStates; ///< The number of states + mutable std::vector<unsigned int> m_nMeasurements; ///< The number of measurements + mutable std::vector<unsigned int> m_nOutliers; ///< The number of outliers + mutable std::vector<unsigned int> m_nHoles; ///< The number of holes + mutable std::vector<unsigned int> m_nSharedHits; ///< The number of shared hits + mutable std::vector<float> m_chi2Sum; ///< The total chi2 + mutable std::vector<unsigned int> m_NDF; ///< The number of ndf of the measurements+outliers + mutable std::vector<std::vector<double>> m_measurementChi2; ///< The chi2 on all measurement states + mutable std::vector<std::vector<double>> m_outlierChi2; ///< The chi2 on all outlier states + // FIXME replace volume, layer, ... with station, layer, ... + mutable std::vector<std::vector<double>> m_measurementVolume; ///< The volume id of the measurements + mutable std::vector<std::vector<double>> m_measurementLayer; ///< The layer id of the measurements + mutable std::vector<std::vector<double>> m_outlierVolume; ///< The volume id of the outliers + mutable std::vector<std::vector<double>> m_outlierLayer; ///< The layer id of the outliers + + // The majority truth particle info + mutable std::vector<unsigned int> m_nMajorityHits; ///< The number of hits from majority particle + mutable std::vector<uint64_t> m_majorityParticleId; ///< The particle Id of the majority particle + mutable std::vector<int> m_t_charge; ///< Charge of majority particle + mutable std::vector<float> m_t_time; ///< Time of majority particle + mutable std::vector<float> m_t_vx; ///< Vertex x positions of majority particle + mutable std::vector<float> m_t_vy; ///< Vertex y positions of majority particle + mutable std::vector<float> m_t_vz; ///< Vertex z positions of majority particle + mutable std::vector<float> m_t_px; ///< Initial momenta px of majority particle + mutable std::vector<float> m_t_py; ///< Initial momenta py of majority particle + mutable std::vector<float> m_t_pz; ///< Initial momenta pz of majority particle + mutable std::vector<float> m_t_theta; ///< In * m_MeV2GeVitial momenta theta of majority particle + mutable std::vector<float> m_t_phi; ///< Initial momenta phi of majority particle + mutable std::vector<float> m_t_p; ///< Initial abs momenta of majority particle + mutable std::vector<float> m_t_pT; ///< Initial momenta pT of majority particle + mutable std::vector<float> m_t_eta; ///< Initial momenta eta of majority particle + + mutable std::vector<bool> m_hasFittedParams; ///< If the track has fitted parameter + // The fitted parameters + mutable std::vector<float> m_eLOC0_fit; ///< Fitted parameters eBoundLoc0 of track + mutable std::vector<float> m_eLOC1_fit; ///< Fitted parameters eBoundLoc1 of track + mutable std::vector<float> m_ePHI_fit; ///< Fitted parameters ePHI of track + mutable std::vector<float> m_eTHETA_fit; ///< Fitted parameters eTHETA of track + mutable std::vector<float> m_eQOP_fit; ///< Fitted parameters eQOP of track + mutable std::vector<float> m_eT_fit; ///< Fitted parameters eT of track + // The error of fitted parameters + mutable std::vector<float> m_err_eLOC0_fit; ///< Fitted parameters eLOC err of track + mutable std::vector<float> m_err_eLOC1_fit; ///< Fitted parameters eBoundLoc1 err of track + mutable std::vector<float> m_err_ePHI_fit; ///< Fitted parameters ePHI err of track + mutable std::vector<float> m_err_eTHETA_fit; ///< Fitted parameters eTHETA err of track + mutable std::vector<float> m_err_eQOP_fit; ///< Fitted parameters eQOP err of track + mutable std::vector<float> m_err_eT_fit; ///< Fitted parameters eT err of track + // The residual of fitted parameters + mutable std::vector<float> m_res_eLOC0_fit; ///< Fitted parameters eLOC res of track + mutable std::vector<float> m_res_eLOC1_fit; ///< Fitted parameters eBoundLoc1 res of track + mutable std::vector<float> m_res_ePHI_fit; ///< Fitted parameters ePHI res of track + mutable std::vector<float> m_res_eTHETA_fit; ///< Fitted parameters eTHETA res of track + mutable std::vector<float> m_res_eQOP_fit; ///< Fitted parameters eQOP res of track + mutable std::vector<float> m_res_eT_fit; ///< Fitted parameters eT res of track + // The pull of fitted parameters + mutable std::vector<float> m_pull_eLOC0_fit; ///< Fitted parameters eLOC pull of track + mutable std::vector<float> m_pull_eLOC1_fit; ///< Fitted parameters eBoundLoc1 pull of track + mutable std::vector<float> m_pull_ePHI_fit; ///< Fitted parameters ePHI pull of track + mutable std::vector<float> m_pull_eTHETA_fit; ///< Fitted parameters eTHETA pull of track + mutable std::vector<float> m_pull_eQOP_fit; ///< Fitted parameters eQOP pull of track + mutable std::vector<float> m_pull_eT_fit; ///< Fitted parameters eT pull of track +}; + +#endif // FASERACTSKALMANFILTER_ROOTTRAJECTORYSUMMARYWRITERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SeedingAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SeedingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..49fd1c901ab2f0159cd033401ddde589b61262e6 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SeedingAlg.h @@ -0,0 +1,23 @@ +#ifndef FASERACTSKALMANFILTER_SEEDINGALG_H +#define FASERACTSKALMANFILTER_SEEDINGALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include <boost/dynamic_bitset.hpp> + + +class SeedingAlg : public AthAlgorithm { +public: + SeedingAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~SeedingAlg() = default; + + StatusCode initialize() override; + StatusCode execute() override; + StatusCode finalize() override; + +private: + ToolHandle<ITrackSeedTool> m_trackSeedTool {this, "TrackSeed", "CircleFitTrackSeedTool"}; +}; + +#endif // FASERACTSKALMANFILTER_SEEDINGALG_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..6bf7ba6984300ae218a39015786d99d034922e64 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h @@ -0,0 +1,106 @@ +#ifndef FASERACTSKALMANFILTER_SEGMENTFITCLUSTERTRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_SEGMENTFITCLUSTERTRACKFINDERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/ReadHandleKey.h" +#include <string> +#include <vector> + +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrkTrack/TrackCollection.h" + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +class SegmentFitClusterTrackFinderTool : public extends<AthAlgTool, ITrackFinderTool> { +public: + SegmentFitClusterTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~SegmentFitClusterTrackFinderTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + virtual const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const override; + virtual const std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> sourceLinks() const override; + virtual const std::shared_ptr<std::vector<IdentifierLink>> idLinks() const override; + virtual const std::shared_ptr<std::vector<std::vector<Measurement>>> measurements() const override; + virtual const std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> spacePoints() const override; + virtual const std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> clusters() const override; + +private: + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> m_sourceLinks {}; + std::shared_ptr<std::vector<IdentifierLink>> m_idLinks {}; + std::shared_ptr<std::vector<std::vector<Measurement>>> m_measurements {}; + std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> m_spacePoints {}; + std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> m_clusters {}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + static std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57); + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + + // covariance of the initial parameters + Gaudi::Property<double> m_sigmaCluster {this, "sigmaCluster", 0.04}; + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; +}; + + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +SegmentFitClusterTrackFinderTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +SegmentFitClusterTrackFinderTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> +SegmentFitClusterTrackFinderTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<std::vector<IdentifierLink>> +SegmentFitClusterTrackFinderTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<std::vector<Measurement>>> +SegmentFitClusterTrackFinderTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> +SegmentFitClusterTrackFinderTool::spacePoints() const { + return m_spacePoints; +} + +inline const std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> +SegmentFitClusterTrackFinderTool::clusters() const { + return m_clusters; +} + +#endif // FASERACTSKALMANFILTER_SEGMENTFITCLUSTERTRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..3f555be285fc792c42db3b8903f9e208e4fa7902 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SegmentFitTrackFinderTool.h @@ -0,0 +1,98 @@ +#ifndef FASERACTSKALMANFILTER_SEGMENTFITTRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_SEGMENTFITTRACKFINDERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/ReadHandleKey.h" +#include <string> +#include <vector> + +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrkTrack/TrackCollection.h" + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +class SegmentFitTrackFinderTool : public extends<AthAlgTool, ITrackFinderTool> { +public: + SegmentFitTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~SegmentFitTrackFinderTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + virtual const std::shared_ptr<const Acts::CurvilinearTrackParameters> initialTrackParameters() const override; + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const override; + virtual const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + virtual const std::shared_ptr<IdentifierLink> idLinks() const override; + virtual const std::shared_ptr<std::vector<Measurement>> measurements() const override; + virtual const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> spacePoints() const override; + +private: + std::shared_ptr<const Acts::CurvilinearTrackParameters> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> m_spacePoints {}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + static double momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57) ; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey { + this, "SpacePoints", "SCT_SpacePointContainer", "Space point container"}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; +}; + + +inline const std::shared_ptr<const Acts::CurvilinearTrackParameters> + SegmentFitTrackFinderTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> + SegmentFitTrackFinderTool::initialSurface() const { +return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> + SegmentFitTrackFinderTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +SegmentFitTrackFinderTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> + SegmentFitTrackFinderTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> + SegmentFitTrackFinderTool::spacePoints() const { + return m_spacePoints; +} +#endif // FASERACTSKALMANFILTER_SEGMENTFITTRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SummaryPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SummaryPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..ea54ffc0f424409ce16887c8824ce271f9a342c2 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SummaryPlotTool.h @@ -0,0 +1,67 @@ +#ifndef FASERACTSKALMANFILTER_SUMMARYPLOTTOOL_H +#define FASERACTSKALMANFILTER_SUMMARYPLOTTOOL_H + +#include "FaserActsKalmanFilter/PlotHelpers.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "TProfile.h" +#include <map> +#include <string> + +class SummaryPlotTool { +public: + std::map<std::string, PlotHelpers::Binning> m_varBinning { + {"Eta", PlotHelpers::Binning("#eta", 40, 4, 12)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 20)}, + {"Num", PlotHelpers::Binning("N", 30, -0.5, 29.5)} + }; + + /// @brief Nested Cache struct + struct SummaryPlotCache { + TProfile* nStates_vs_eta; ///< Number of total states vs eta + TProfile* nMeasurements_vs_eta; ///< Number of non-outlier measurements vs eta + TProfile* nHoles_vs_eta; ///< Number of holes vs eta + TProfile* nOutliers_vs_eta; ///< Number of outliers vs eta + TProfile* nSharedHits_vs_eta; ///< Number of Shared Hits vs eta + TProfile* nStates_vs_pt; ///< Number of total states vs pt + TProfile* nMeasurements_vs_pt; ///< Number of non-outlier measurements vs pt + TProfile* nHoles_vs_pt; ///< Number of holes vs pt + TProfile* nOutliers_vs_pt; ///< Number of outliers vs pt + TProfile* nSharedHits_vs_pt; ///< Number of Shared Hits vs pt + }; + + /// Constructor + /// + SummaryPlotTool() = default; + + /// @brief book the track info plots + /// + /// @param trackSummaryPlotCache the cache for track info plots + void book(SummaryPlotCache& trackSummaryPlotCache) const; + + /// @brief fill reco track info w.r.t. fitted track parameters + /// + /// @param trackSummaryPlotCache cache object for track info plots + /// @param fittedParameters fitted track parameters of this track + /// @param nStates number of track states + /// @param nMeasurements number of measurements + /// @param nOutliers number of outliers + /// @param nHoles number of holes + /// @param nSharedHits number of shared hits + void fill(SummaryPlotCache& trackSummaryPlotCache, + const Acts::BoundTrackParameters& fittedParameters, size_t nStates, + size_t nMeasurements, size_t nOutliers, size_t nHoles, + size_t nSharedHits) const; + + /// @brief write the track info plots to file + /// + /// @param trackSummaryPlotCache cache object for track info plots + void write(const SummaryPlotCache& trackSummaryPlotCache) const; + + /// @brief delete the track info plots + /// + /// @param trackSummaryPlotCache cache object for track info plots + void clear(SummaryPlotCache& trackSummaryPlotCache) const; +}; + +#endif // FASERACTSKALMANFILTER_SUMMARYPLOTTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..22cbf9af8420d5100635bbc0f6a00f760e111097 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h @@ -0,0 +1,134 @@ +#ifndef FASERACTSKALMANFILTER_THREESTATIONTRACKSEEDTOOL_H +#define FASERACTSKALMANFILTER_THREESTATIONTRACKSEEDTOOL_H + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" + +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "TrkTrack/TrackCollection.h" +#include <memory> +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { class SCT_DetectorManager; } + +class ThreeStationTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> { +public: + ThreeStationTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~ThreeStationTrackSeedTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override; + const std::shared_ptr<const Acts::Surface> initialSurface() const override; + const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override; + const std::shared_ptr<IdentifierLink> idLinks() const override; + const std::shared_ptr<std::vector<Measurement>> measurements() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override; + const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override; + const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override; + double targetZPosition() const override; + +private: + + struct Tracklet { + public: + Tracklet(const Amg::Vector3D& position, const std::vector<const Tracker::FaserSCT_Cluster*>& clusters) + : m_position(position), m_clusters(clusters) {} + inline const Amg::Vector3D position() const { return m_position; } + inline const std::vector<const Tracker::FaserSCT_Cluster*> clusters() const { return m_clusters; } + inline int size() const { return m_clusters.size(); } + private: + const Amg::Vector3D m_position; + const std::vector<const Tracker::FaserSCT_Cluster*> m_clusters; + }; + + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {}; + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {}; + std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {}; + double m_targetZPosition {0.}; + + const FaserSCT_ID* m_idHelper {nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager {nullptr}; + + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + SG::ReadHandleKey<TrackCollection> m_trackCollection { + this, "TrackCollection", "SegmentFit", "Input track collection name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey { + this, "ClusterContainer", "SCT_ClusterContainer"}; + + // position resolution of a cluster + Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.04}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; + + Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"}; + + static Acts::CurvilinearTrackParameters get_params( + const Amg::Vector3D& position_st1, const Amg::Vector3D& position_st2, const Amg::Vector3D& position_st3, const Acts::BoundSymMatrix& cov, double origin); + static std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57); +}; + +inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> +ThreeStationTrackSeedTool::initialTrackParameters() const { + return m_initialTrackParameters; +} + +inline const std::shared_ptr<const Acts::Surface> +ThreeStationTrackSeedTool::initialSurface() const { + return m_initialSurface; +} + +inline const std::shared_ptr<std::vector<IndexSourceLink>> +ThreeStationTrackSeedTool::sourceLinks() const { + return m_sourceLinks; +} + +inline const std::shared_ptr<IdentifierLink> +ThreeStationTrackSeedTool::idLinks() const { + return m_idLinks; +} + +inline const std::shared_ptr<std::vector<Measurement>> +ThreeStationTrackSeedTool::measurements() const { + return m_measurements; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> +ThreeStationTrackSeedTool::clusters() const { + return m_clusters; +} + +inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> +ThreeStationTrackSeedTool::seedClusters() const { + return m_seedClusters; +} + +inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> +ThreeStationTrackSeedTool::spacePoints() const { + return m_spacePoints; +} + +inline double ThreeStationTrackSeedTool::targetZPosition() const { + return m_targetZPosition; +} + +#endif // FASERACTSKALMANFILTER_THREESTATIONTRACKSEEDTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackClassification.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackClassification.h new file mode 100644 index 0000000000000000000000000000000000000000..2ca594c7dfd08c322c08ae193239fa8cafbc5ae9 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackClassification.h @@ -0,0 +1,23 @@ +#ifndef FASERACTSKALMANFILTER_TRACKCLASSIFICATION_H +#define FASERACTSKALMANFILTER_TRACKCLASSIFICATION_H + +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "TrackerSimData/TrackerSimDataCollection.h" + +struct ParticleHitCount { + int particleId; + size_t hitCount; +}; + +/// Identify all particles that contribute to a trajectory. +void identifyContributingParticles( + const TrackerSimDataCollection& simDataCollection, + const FaserActsRecMultiTrajectory& trajectories, size_t tip, + std::vector<ParticleHitCount>& particleHitCounts); + +void identifyContributingParticles( + const TrackerSimDataCollection& simDataCollection, + const std::vector<const Tracker::FaserSCT_Cluster*> clusters, + std::vector<ParticleHitCount>& particleHitCounts); + +#endif // FASERACTSKALMANFILTER_TRACKCLASSIFICATION_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e078acc19edd584ce2f514a4a3985bbaf7cc326c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h @@ -0,0 +1,50 @@ +#ifndef FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H +#define FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H + + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Acts/EventData/TrackParameters.hpp" + +class TFile; +class TTree; + +class TrackSeedWriterTool : public AthAlgTool { + public: + TrackSeedWriterTool(const std::string& type, + const std::string& name, const IInterface* parent); + virtual ~TrackSeedWriterTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + void writeout(const Acts::GeometryContext& gctx, + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>& initialParameters) const; + +private: + void initializeTree(); + void clearVariables() const; + Gaudi::Property<std::string> m_filePath{this, "FilePath", "TrackSeeds.root", ""}; + Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", ""}; + TFile* m_file; + TTree* m_tree; + + mutable int m_runNumber; + mutable int m_eventNumber; + mutable std::vector<float> m_eLOC0; + mutable std::vector<float> m_eLOC1; + mutable std::vector<float> m_ePHI; + mutable std::vector<float> m_eTHETA; + mutable std::vector<float> m_eQOP; + mutable std::vector<float> m_err_eLOC0; + mutable std::vector<float> m_err_eLOC1; + mutable std::vector<float> m_err_ePHI; + mutable std::vector<float> m_err_eTHETA; + mutable std::vector<float> m_err_eQOP; + mutable std::vector<float> m_x; + mutable std::vector<float> m_y; + mutable std::vector<float> m_z; + mutable std::vector<float> m_px; + mutable std::vector<float> m_py; + mutable std::vector<float> m_pz; +}; + + +#endif // FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSelection.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSelection.h new file mode 100644 index 0000000000000000000000000000000000000000..858bb15c82b1e1d58ce8d92698e17aacac0b9baf --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSelection.h @@ -0,0 +1,20 @@ +#ifndef FASERACTSKALMANFILTER_TRACKSELECTION_H +#define FASERACTSKALMANFILTER_TRACKSELECTION_H + +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" + +using TrackFitterResult = +Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>; +using TrackFinderResult = std::vector<TrackFitterResult>; + +struct TrackQuality { + Acts::CombinatorialKalmanFilterResult<IndexSourceLink> track; + size_t nMeasurements; + double chi2; +}; + +void selectTracks(TrackFinderResult& results, std::vector<TrackQuality>& trackQuality); + +#endif // FASERACTSKALMANFILTER_TRACKSELECTION_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h index 659cea7fa08321bb43a38fcc598a7054b119262c..0643ad9ce973f65453e72063701befaa3b2789ec 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h @@ -7,7 +7,7 @@ class TFile; class TTree; -class FaserActsRecMultiTrajectory; +struct FaserActsRecMultiTrajectory; using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; class TrajectoryWriterTool : public AthAlgTool { @@ -21,7 +21,7 @@ class TrajectoryWriterTool : public AthAlgTool { virtual StatusCode finalize() override; void writeout(TrajectoriesContainer trajectories, - Acts::GeometryContext geoContext,std::vector<Acts::CurvilinearTrackParameters> traj ) const; + Acts::GeometryContext geoContext, std::vector<Acts::CurvilinearTrackParameters> traj ) const; void clearVariables() const; @@ -60,6 +60,10 @@ class TrajectoryWriterTool : public AthAlgTool { mutable std::vector<float> m_x_hit; mutable std::vector<float> m_y_hit; mutable std::vector<float> m_z_hit; + mutable std::vector<float> m_meas_eLOC0; + mutable std::vector<float> m_meas_eLOC1; + mutable std::vector<float> m_meas_cov_eLOC0; + mutable std::vector<float> m_meas_cov_eLOC1; mutable std::vector<float> m_res_x_hit; mutable std::vector<float> m_res_y_hit; mutable std::vector<float> m_err_x_hit; diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthSeededTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthSeededTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..79425aa17c64a68e4c517170587a6fc84ac973c3 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthSeededTrackFinderTool.h @@ -0,0 +1,113 @@ +#ifndef FASERACTSKALMANFILTER_TRUTHSEEDEDTRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_TRUTHSEEDEDTRACKFINDERTOOL_H + +#include "Acts/Definitions/Units.hpp" +#include "AthenaBaseComps/AthAlgTool.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "GeneratorObjects/McEventCollection.h" +#include "StoreGate/ReadHandleKey.h" +#include "TrackerSpacePoint/SpacePointForSeedCollection.h" +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + +using namespace Acts::UnitLiterals; + +class TruthSeededTrackFinderTool : public extends<AthAlgTool, ITrackFinderTool> { +public: + TruthSeededTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~TruthSeededTrackFinderTool() = default; + + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + virtual const std::shared_ptr<const Acts::CurvilinearTrackParameters> initialTrackParameters() const override { + return m_initialTrackParameters; + } + + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const override { + return m_initialSurface; + } + + virtual const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override { + return m_sourceLinks; + } + + virtual const std::shared_ptr<IdentifierLink> idLinks() const override; + + virtual const std::shared_ptr<std::vector<Measurement>> measurements() const override { + return m_measurements; + } + + virtual const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> spacePoints() const override; + +private: + std::shared_ptr<const Acts::CurvilinearTrackParameters> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> m_spacePoints {}; + + const FaserSCT_ID* m_idHelper{nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; + + static std::vector<Acts::Vector3> map2vector(const std::map<int, Acts::Vector3>& positions, int station); + static Acts::Vector3 average(const std::vector<Acts::Vector3>& spacePoints); + static std::pair<Acts::Vector3, Acts::Vector3> linear_fit(const std::vector<Acts::Vector3>& position); + static std::pair<double, double> momentum2(const std::map<int, Acts::Vector3>& hits, double B=0.57) ; + + SG::ReadHandleKey<SpacePointForSeedCollection> m_spacePointCollectionKey { + this, "FaserSpacePointsSeedsName", "Seeds_SpacePointContainer"}; + SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "BeamTruthEvent"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + + Gaudi::Property<bool> m_useTrueInitialParameters {this, "useTrueInitialParameters", true}; + + // covariance matrix of measurement + Gaudi::Property<double> m_covMeas00 {this, "covMeas00", 0.0004}; + Gaudi::Property<double> m_covMeas01 {this, "covMeas01", 0.01}; + Gaudi::Property<double> m_covMeas10 {this, "covMeas10", 0.01}; + Gaudi::Property<double> m_covMeas11 {this, "covMeas11", 0.64}; + + // smearing of initial parameters + Gaudi::Property<double> m_sigmaLoc0 {this, "sigmaLoc0", 0}; + Gaudi::Property<double> m_sigmaLoc1 {this, "sigmaLoc1", 0}; + Gaudi::Property<double> m_sigmaPhi {this, "sigmaPhi", 0}; + Gaudi::Property<double> m_sigmaTheta {this, "sigmaTheta", 0}; + Gaudi::Property<double> m_sigmaP {this, "sigmaP", 0}; + Gaudi::Property<double> m_sigmaTime {this, "sigmaTime", 0}; + + // covariance parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; +}; + +inline const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> +TruthSeededTrackFinderTool::spacePoints() const { + return m_spacePoints; +} + +inline const std::shared_ptr<IdentifierLink> +TruthSeededTrackFinderTool::idLinks() const { + return m_idLinks; +} + + +#endif // FASERACTSKALMANFILTER_TRUTHSEEDEDTRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..3bfe35b68013a3ef323a43c245e046b7248be094 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthTrackFinderTool.h @@ -0,0 +1,109 @@ +#ifndef FASERACTSKALMANFILTER_TRUTHTRACKFINDERTOOL_H +#define FASERACTSKALMANFILTER_TRUTHTRACKFINDERTOOL_H + +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +#include "Gaudi/Property.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/IInterface.h" +#include "GaudiKernel/StatusCode.h" +#include "StoreGate/ReadHandleKey.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include <string> +#include <vector> + +class FaserSCT_ID; +namespace TrackerDD { +class SCT_DetectorManager; +} + + +class TruthTrackFinderTool : public extends<AthAlgTool, ITrackFinderTool> { +public: + TruthTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~TruthTrackFinderTool() = default; + + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual StatusCode run() override; + + virtual const std::shared_ptr<const Acts::CurvilinearTrackParameters> initialTrackParameters() const override { + return m_initialTrackParameters; + } + + virtual const std::shared_ptr<const Acts::Surface> initialSurface() const override { + return m_initialSurface; + } + + virtual const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override { + return m_sourceLinks; + } + + virtual const std::shared_ptr<IdentifierLink> idLinks() const override; + + virtual const std::shared_ptr<std::vector<Measurement>> measurements() const override { + return m_measurements; + } + + virtual const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> spacePoints() const override; + +private: + std::shared_ptr<const Acts::CurvilinearTrackParameters> m_initialTrackParameters; + std::shared_ptr<const Acts::Surface> m_initialSurface; + std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {}; + std::shared_ptr<IdentifierLink> m_idLinks {}; + std::shared_ptr<std::vector<Measurement>> m_measurements {}; + std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> m_spacePoints {}; + + const FaserSCT_ID* m_idHelper{nullptr}; + const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; + + SG::ReadHandleKey<FaserSiHitCollection> m_siHitCollectionKey { + this, "FaserSiHitCollection", "SCT_Hits"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool { + this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + + // smearing of measurements + Gaudi::Property<double> m_sigma0 {this, "sigmaMeasLoc0", 0}; + Gaudi::Property<double> m_sigma1 {this, "sigmaMeasLoc1", 0}; + + // covariance of the measurements + Gaudi::Property<double> m_covMeasLoc0 {this, "covMeasLoc0", 0.01}; + Gaudi::Property<double> m_covMeasLoc1 {this, "covMeasLoc1", 0.01}; + + // smearing of initial parameters + Gaudi::Property<double> m_sigmaLoc0 {this, "sigmaLoc0", 0}; + Gaudi::Property<double> m_sigmaLoc1 {this, "sigmaLoc1", 0}; + Gaudi::Property<double> m_sigmaPhi {this, "sigmaPhi", 0}; + Gaudi::Property<double> m_sigmaTheta {this, "sigmaTheta", 0}; + Gaudi::Property<double> m_sigmaP {this, "sigmaP", 0}; + Gaudi::Property<double> m_sigmaTime {this, "sigmaTime", 0}; + + // covariance of the initial parameters + Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1}; + Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1}; + Gaudi::Property<double> m_covPhi {this, "covPhi", 1}; + Gaudi::Property<double> m_covTheta {this, "covTheta", 1}; + Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1}; + Gaudi::Property<double> m_covTime {this, "covTime", 1}; + + // TODO get parameters of first layer from tracker geometry + Gaudi::Property<int> m_first_station {this, "first_station", 1, "first station for which the initial track parameters are calculated"}; + Gaudi::Property<int> m_first_layer {this, "first_layer", 0, "first layer for which the initial track parameters are calculated"}; + Gaudi::Property<int> m_first_side {this, "first_side", 1, "first side for which the initial track parameters are calculated"}; +}; + +inline const std::shared_ptr<std::vector<Tracker::FaserSCT_SpacePoint>> + TruthTrackFinderTool::spacePoints() const { + return m_spacePoints; +} + +inline const std::shared_ptr<IdentifierLink> +TruthTrackFinderTool::idLinks() const { + return m_idLinks; +} + + +#endif // FASERACTSKALMANFILTER_TRUTHTRACKFINDERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py new file mode 100644 index 0000000000000000000000000000000000000000..ea2dc0cb9eb08c309bf0453216230fe0b2074b4f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py @@ -0,0 +1,125 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg +from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg + + +def FaserActsAlignmentCondAlgCfg(flags, **kwargs): + acc = ComponentAccumulator() + acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs)) + return acc + + +def CKF2_OutputCfg(flags): + acc = ComponentAccumulator() + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "TrackCollection#*", + ] + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + ostream = acc.getEventAlgo("OutputStreamESD") + ostream.TakeItemsFromInput = True + return acc + + +def CKF2Cfg(flags, **kwargs): + # acc = ComponentAccumulator() + acc = FaserSCT_GeometryCfg(flags) + acc.merge(MagneticFieldSvcCfg(flags)) + # acc.merge(FaserActsAlignmentCondAlgCfg(flags)) + acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags) + acc.merge(acts_tracking_geometry_svc ) + + # track_seed_tool = CompFactory.ClusterTrackSeedTool() + # track_seed_tool = CompFactory.ActsTrackSeedTool() + # track_seed_tool = CompFactory.MyTrackSeedTool() + # track_seed_tool = CompFactory.ThreeStationTrackSeedTool() + track_seed_tool = CompFactory.CircleFitTrackSeedTool() + sigma_loc0 = 1.9e-2 + sigma_loc1 = 9e-1 + sigma_phi = 3.3e-2 + sigma_theta = 2.9e-4 + p = 1000 + sigma_p = 0.1 * p + sigma_qop = sigma_p / (p * p) + # initial_variance_inflation = [1000, 1000, 100, 100, 10000] + initial_variance_inflation = [100, 100, 100, 100, 1000] + track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc1 * sigma_loc1 + track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc0 * sigma_loc0 + track_seed_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi + track_seed_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta + track_seed_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop + track_seed_tool.std_cluster = 0.0231 + track_seed_tool.TrackCollection = "Segments" + + trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + trajectory_states_writer_tool1 = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool1.noDiagnostics = kwargs["noDiagnostics"] + trajectory_states_writer_tool1.FilePath = "track_states_ckf1.root" + trajectory_states_writer_tool2 = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool2.FilePath = "track_states_ckf2.root" + trajectory_states_writer_tool2.noDiagnostics = kwargs["noDiagnostics"] + + trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool(**kwargs) + trajectory_summary_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + trajectory_summary_writer_tool1 = CompFactory.RootTrajectorySummaryWriterTool() + trajectory_summary_writer_tool1.FilePath = "track_summary_ckf1.root" + trajectory_summary_writer_tool1.noDiagnostics = kwargs["noDiagnostics"] + trajectory_summary_writer_tool2 = CompFactory.RootTrajectorySummaryWriterTool(**kwargs) + trajectory_summary_writer_tool2.FilePath = "track_summary_ckf2.root" + trajectory_summary_writer_tool2.noDiagnostics = kwargs["noDiagnostics"] + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 1000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + + trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool", **kwargs) + trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool + trajectory_performance_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + + + ckf = CompFactory.CKF2(**kwargs) + kalman_fitter1 = CompFactory.KalmanFitterTool(name="fitterTool1", **kwargs) + kalman_fitter1.noDiagnostics = kwargs["noDiagnostics"] + kalman_fitter1.ActsLogging = "INFO" + kalman_fitter1.SummaryWriter = True + kalman_fitter1.StatesWriter = False + kalman_fitter1.SeedCovarianceScale = 10 + kalman_fitter1.isMC = flags.Input.isMC + kalman_fitter1.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool1 + kalman_fitter1.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool1 + ckf.KalmanFitterTool1 = kalman_fitter1 + + kalman_fitter2 = CompFactory.KalmanFitterTool(name="fitterTool2", **kwargs) + kalman_fitter2.noDiagnostics = kwargs["noDiagnostics"] + kalman_fitter2.ActsLogging = "INFO" + kalman_fitter2.SummaryWriter = True + kalman_fitter2.StatesWriter = False + kalman_fitter2.SeedCovarianceScale = 10 + kalman_fitter2.isMC = flags.Input.isMC + kalman_fitter2.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool2 + kalman_fitter2.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool2 + ckf.KalmanFitterTool2 = kalman_fitter2 + + ckf.TrackSeed = track_seed_tool + ckf.ActsLogging = "INFO" + ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool + ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool + ckf.PerformanceWriterTool = trajectory_performance_writer_tool + ckf.isMC = flags.Input.isMC + ckf.SummaryWriter = True + ckf.StatesWriter = False + ckf.PerformanceWriter = False + + ckf.nMax = 10 + ckf.chi2Max = 25 + acc.addEventAlgo(ckf) + # acc.merge(CKF2_OutputCfg(flags)) + return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py index 46c01fd06268dddf34867f76d358e4ab10f961e3..fac9e7ec1713f9e387da5746ea5c9fd98519202e 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py +++ b/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py @@ -1,43 +1,83 @@ # Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg +from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg -def CombinatorialKalmanFilter_OutputCfg(flags): +def FaserActsAlignmentCondAlgCfg(flags, **kwargs): acc = ComponentAccumulator() - acc.merge(OutputStreamCfg(flags, "ESD")) - ostream = acc.getEventAlgo("OutputStreamESD") - ostream.TakeItemsFromInput = True + acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs)) return acc -def CombinatorialKalmanFilter_OutputAODCfg(flags): + +def CombinatorialKalmanFilter_OutputCfg(flags): acc = ComponentAccumulator() itemList = ["xAOD::EventInfo#*", "xAOD::EventAuxInfo#*", - "FaserSCT_RDO_Container#*", - "xAOD::FaserTriggerData#*", - "xAOD::FaserTriggerDataAux#*", - "ScintWaveformContainer#*", "TrackCollection#*", - "xAOD::WaveformHitContainer#*", - "xAOD::WaveformHitAuxContainer#*", - "xAOD::WaveformClock#*", - "xAOD::WaveformClockAuxInfo#*" ] - acc.merge(OutputStreamCfg(flags, "AOD",itemList)) - ostream = acc.getEventAlgo("OutputStreamAOD") + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + ostream = acc.getEventAlgo("OutputStreamESD") ostream.TakeItemsFromInput = True return acc - def CombinatorialKalmanFilterCfg(flags, **kwargs): - acc = ComponentAccumulator() - kwargs.setdefault("SpacePointsSCTName", "SCT_SpacePointContainer") - combinatorialKalmanFilterAlg = CompFactory.CombinatorialKalmanFilterAlg(**kwargs) - acc.addEventAlgo(combinatorialKalmanFilterAlg) + # acc = ComponentAccumulator() + acc = FaserSCT_GeometryCfg(flags) + acc.merge(MagneticFieldSvcCfg(flags)) + # acc.merge(FaserActsAlignmentCondAlgCfg(flags)) + acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags) + acc.merge(acts_tracking_geometry_svc ) + + # track_seed_tool = CompFactory.ClusterTrackSeedTool() + track_seed_tool = CompFactory.ThreeStationTrackSeedTool() + # track_seed_tool = CompFactory.ActsTrackSeedTool() + # track_seed_tool = CompFactory.MyTrackSeedTool() + sigma_loc0 = 1.9e-2 + sigma_loc1 = 9e-1 + sigma_phi = 3.3e-2 + sigma_theta = 2.9e-4 + p = 1000 + sigma_p = 0.1 * p + sigma_qop = sigma_p / (p * p) + initial_variance_inflation = [100, 100, 100, 100, 1000] + track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc0 * sigma_loc0 + track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc1 * sigma_loc1 + track_seed_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi + track_seed_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta + track_seed_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop + track_seed_tool.std_cluster = 0.023 + track_seed_tool.origin = 0 + + trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + trajectory_states_writer_tool.MC = True + + trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool() + trajectory_summary_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 1000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool") + performance_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + performance_writer_tool.ExtrapolationTool = actsExtrapolationTool + + ckf = CompFactory.CombinatorialKalmanFilterAlg(**kwargs) + ckf.TrackSeed = track_seed_tool + ckf.ActsLogging = "INFO" + ckf.noDiagnostics = kwargs["noDiagnostics"] + ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool + ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool + ckf.PerformanceWriterTool = performance_writer_tool + + ckf.nMax = 10 + ckf.chi2Max = 25 + acc.addEventAlgo(ckf) acc.merge(CombinatorialKalmanFilter_OutputCfg(flags)) - acc.merge(CombinatorialKalmanFilter_OutputAODCfg(flags)) return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/FaserActsKalmanFilterConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/FaserActsKalmanFilterConfig.py index 6d6167c051b868d6032355e5bfd58d2a0f8296bd..a2ad7705968c54771f72345dfb56c82e9f03a8c4 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/python/FaserActsKalmanFilterConfig.py +++ b/Tracking/Acts/FaserActsKalmanFilter/python/FaserActsKalmanFilterConfig.py @@ -1,50 +1,162 @@ -# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg -from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg +# from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg -FaserActsKalmanFilterAlg,FaserActsTrackingGeometrySvc, FaserActsTrackingGeometryTool, FaserActsExtrapolationTool,FaserActsAlignmentCondAlg, THistSvc = CompFactory.getComps("FaserActsKalmanFilterAlg","FaserActsTrackingGeometrySvc", "FaserActsTrackingGeometryTool", "FaserActsExtrapolationTool","FaserActsAlignmentCondAlg", "THistSvc") +# FaserActsKalmanFilterAlg,FaserActsTrackingGeometrySvc, FaserActsTrackingGeometryTool, FaserActsExtrapolationTool,FaserActsAlignmentCondAlg, THistSvc = CompFactory.getComps("FaserActsKalmanFilterAlg","FaserActsTrackingGeometrySvc", "FaserActsTrackingGeometryTool", "FaserActsExtrapolationTool","FaserActsAlignmentCondAlg", "THistSvc") +# +# def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) +# return acc +# +# def FaserActsAlignmentCondAlgCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name = "FaserActsAlignmentCondAlg", **kwargs)) +# #acc.addCondAlgo(CompFactory.NominalAlignmentCondAlg(name = "NominalAlignmentCondAlg", **kwargs)) +# return acc +# +# def FaserActsKalmanFilterCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# # Initialize field service +# acc.merge(MagneticFieldSvcCfg(flags)) +# +# acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) +# acc.merge(FaserActsAlignmentCondAlgCfg(flags, **kwargs)) +# +# kwargs.setdefault("FaserSpacePointsSeedsName", "Seeds_SpacePointContainer") +# actsKalmanFilterAlg = FaserActsKalmanFilterAlg(**kwargs) +# #actsKalmanFilterAlg.TrackingGeometryTool = FaserActsTrackingGeometryTool("TrackingGeometryTool") +# actsExtrapolationTool=FaserActsExtrapolationTool("FaserActsExtrapolationTool") +# actsExtrapolationTool.FieldMode="FASER" +# #actsExtrapolationTool.FieldMode="Constant" +# actsExtrapolationTool.TrackingGeometryTool=FaserActsTrackingGeometryTool("TrackingGeometryTool") +# actsKalmanFilterAlg.ExtrapolationTool=actsExtrapolationTool +# acc.addEventAlgo(actsKalmanFilterAlg) +# histSvc= THistSvc() +# histSvc.Output += [ "KalmanTracks DATAFILE='KalmanTracks.root' OPT='RECREATE'" ] +# acc.addService(histSvc) +# acc.merge(FaserActsKalmanFilter_OutputCfg(flags)) +# return acc +# +# def FaserActsKalmanFilter_OutputCfg(flags): +# """Return ComponentAccumulator with Output for SCT. Not standalone.""" +# acc = ComponentAccumulator() +# acc.merge(OutputStreamCfg(flags, "ESD")) +# ostream = acc.getEventAlgo("OutputStreamESD") +# ostream.TakeItemsFromInput = True +# return acc -def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): +def FaserActsKalmanFilter_OutputCfg(flags): acc = ComponentAccumulator() - acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) - return acc + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "TrackCollection#*", + ] + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + ostream = acc.getEventAlgo("OutputStreamESD") + ostream.TakeItemsFromInput = True + return acc -def FaserActsAlignmentCondAlgCfg(flags, **kwargs): +def FaserActsKalmanFilter_OutputAODCfg(flags): acc = ComponentAccumulator() - acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name = "FaserActsAlignmentCondAlg", **kwargs)) - #acc.addCondAlgo(CompFactory.NominalAlignmentCondAlg(name = "NominalAlignmentCondAlg", **kwargs)) + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "FaserSCT_RDO_Container#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "ScintWaveformContainer#*", + "TrackCollection#*", + "xAOD::WaveformHitContainer#*", + "xAOD::WaveformHitAuxContainer#*", + "xAOD::WaveformClock#*", + "xAOD::WaveformClockAuxInfo#*" + ] + acc.merge(OutputStreamCfg(flags, "AOD",itemList)) + ostream = acc.getEventAlgo("OutputStreamAOD") + ostream.TakeItemsFromInput = True return acc + def FaserActsKalmanFilterCfg(flags, **kwargs): acc = ComponentAccumulator() - # Initialize field service - acc.merge(MagneticFieldSvcCfg(flags)) - - acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) - acc.merge(FaserActsAlignmentCondAlgCfg(flags, **kwargs)) - - kwargs.setdefault("FaserSpacePointsSeedsName", "Seeds_SpacePointContainer") - actsKalmanFilterAlg = FaserActsKalmanFilterAlg(**kwargs) - #actsKalmanFilterAlg.TrackingGeometryTool = FaserActsTrackingGeometryTool("TrackingGeometryTool") - actsExtrapolationTool=FaserActsExtrapolationTool("FaserActsExtrapolationTool") - actsExtrapolationTool.FieldMode="FASER" - #actsExtrapolationTool.FieldMode="Constant" - actsExtrapolationTool.TrackingGeometryTool=FaserActsTrackingGeometryTool("TrackingGeometryTool") - actsKalmanFilterAlg.ExtrapolationTool=actsExtrapolationTool - acc.addEventAlgo(actsKalmanFilterAlg) - histSvc= THistSvc() - histSvc.Output += [ "KalmanTracks DATAFILE='KalmanTracks.root' OPT='RECREATE'" ] - acc.addService(histSvc) - acc.merge(FaserActsKalmanFilter_OutputCfg(flags)) - return acc + track_finder_tool = CompFactory.MultiTrackFinderTool() + # track_finder_tool = CompFactory.SegmentFitClusterTrackFinderTool() + # track_finder_tool = CompFactory.SegmentFitTrackFinderTool() + sigma_loc0 = 1.9e-2 + sigma_loc1 = 9e-1 + sigma_phi = 3.3e-2 + sigma_theta = 2.9e-4 + # sigma_p_rel = 0.1 + p = 1 + sigma_qop = 0.1 * p / (p * p) + initial_variance_inflation = [100, 100, 1000, 1000, 1000] + track_finder_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc1 * sigma_loc1 + track_finder_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc0 * sigma_loc0 + track_finder_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi + track_finder_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta + track_finder_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop + # track_finder_tool.sigmaCluster = 0.04 + # track_finder_tool.covLoc0 = 1e-1 + # track_finder_tool.covLoc1 = 1e-1 + # track_finder_tool.covPhi = 1e-1 + # track_finder_tool.covTheta = 1e-1 + # track_finder_tool.covQOverP = 1e-1 -def FaserActsKalmanFilter_OutputCfg(flags): - """Return ComponentAccumulator with Output for SCT. Not standalone.""" - acc = ComponentAccumulator() - acc.merge(OutputStreamCfg(flags, "ESD")) - ostream = acc.getEventAlgo("OutputStreamESD") - ostream.TakeItemsFromInput = True + # track_finder_tool = CompFactory.TruthSeededTrackFinderTool() + # track_finder_tool.useTrueInitialParameters = False + # track_finder_tool.covMeas00 = 0.0004 + # track_finder_tool.covMeas01 = 0.01 + # track_finder_tool.covMeas10 = 0.01 + # track_finder_tool.covMeas11 = 0.64 + # track_finder_tool.covLoc0 = 1e-4 + # track_finder_tool.covLoc1 = 1e-4 + # track_finder_tool.covPhi = 1e-4 + # track_finder_tool.covTheta = 1e-4 + # track_finder_tool.covQOverP = 1e-4 + + # track_finder_tool.covLoc0 = 1e-1 + # track_finder_tool.covLoc1 = 1e-1 + # track_finder_tool.covPhi = 1e-1 + # track_finder_tool.covTheta = 1e-1 + # track_finder_tool.covQOverP = 1e-1 + + # track_finder_tool.sigmaLoc0 = 0.02 + # track_finder_tool.sigmaLoc1 = 0.8 + # track_finder_tool.sigmaPhi = 2 * pi/180 + # track_finder_tool.sigmaTheta = 2 * pi/180 + # track_finder_tool.sigmaP = 0.1 + + # track_finder_tool = CompFactory.TruthTrackFinderTool() + # track_finder_tool.first_side = 1 + # track_finder_tool.sigmaMeasLoc0 = 0.02 + # track_finder_tool.sigmaMeasLoc1 = 0.8 + # track_finder_tool.covMeasLoc0 = 0.02 * 0.02 * 10 + # track_finder_tool.covMeasLoc1 = 0.8 * 0.8 * 10 + # track_finder_tool.sigmaLoc0 = 0 + # track_finder_tool.sigmaLoc1 = 0 + # track_finder_tool.sigmaPhi = 0 + # track_finder_tool.sigmaTheta = 0 + # track_finder_tool.sigmaP = 0 + # track_finder_tool.covLoc0 = 1e-3 + # track_finder_tool.covLoc1 = 1e-3 + # track_finder_tool.covPhi = 1e-3 + # track_finder_tool.covTheta = 1e-3 + # track_finder_tool.covQOverP = 1e-3 + trajectory_writer_tool = CompFactory.TrajectoryWriterTool() + trajectory_writer_tool.FilePath = "KalmanFilterTrajectories.root" + # trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool() + # trajectory_states_writer_tool.FilePath = "TrajectoryStates.root" + kalman_filter = CompFactory.FaserActsKalmanFilterAlg(**kwargs) + # kalman_filter.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool + kalman_filter.OutputTool = trajectory_writer_tool + kalman_filter.TrackFinderTool = track_finder_tool + kalman_filter.ActsLogging = "VERBOSE" + acc.addEventAlgo(kalman_filter) + acc.merge(FaserActsKalmanFilter_OutputCfg(flags)) + # acc.merge(FaserActsKalmanFilter_OutputAODCfg(flags)) return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..ebe56d179393fcf3f51cb8df510271fbf5a85ebe --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py @@ -0,0 +1,35 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + +def GhostBusters_OutputCfg(flags): + acc = ComponentAccumulator() + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "TrackCollection#*", + ] + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + ostream = acc.getEventAlgo("OutputStreamESD") + ostream.TakeItemsFromInput = True + return acc + + +def GhostBustersCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags) + acc.merge(acts_tracking_geometry_svc ) + acc.addEventAlgo(CompFactory.GhostBusters(**kwargs)) + acc.merge(GhostBusters_OutputCfg(flags)) + + # thistSvc = CompFactory.THistSvc() + # thistSvc.Output += ["HIST2 DATAFILE='GhostBusters.root' OPT='RECREATE'"] + # acc.addService(thistSvc) + + return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/SeedingConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/SeedingConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..e6a84e5b48f6886a0935e6665f4827db55eba958 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/SeedingConfig.py @@ -0,0 +1,16 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentFactory import CompFactory +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg + + +def SeedingCfg(flags, **kwargs): + acc = FaserSCT_GeometryCfg(flags) + acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags) + acc.merge(acts_tracking_geometry_svc ) + seedingAlg = CompFactory.SeedingAlg(**kwargs) + acc.addEventAlgo(seedingAlg) + return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/TI12CKF2Config.py b/Tracking/Acts/FaserActsKalmanFilter/python/TI12CKF2Config.py new file mode 100644 index 0000000000000000000000000000000000000000..748900ed86612abebc50a0f64557223c922d97c8 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/TI12CKF2Config.py @@ -0,0 +1,125 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations + +from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg +from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg + + +def FaserActsAlignmentCondAlgCfg(flags, **kwargs): + acc = ComponentAccumulator() + acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs)) + return acc + + +def CKF2_OutputCfg(flags): + acc = ComponentAccumulator() + itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "TrackCollection#*", + ] + acc.merge(OutputStreamCfg(flags, "ESD", itemList)) + ostream = acc.getEventAlgo("OutputStreamESD") + ostream.TakeItemsFromInput = True + return acc + + +def TI12CKF2Cfg(flags, **kwargs): + # acc = ComponentAccumulator() + acc = FaserSCT_GeometryCfg(flags) + acc.merge(MagneticFieldSvcCfg(flags)) + # acc.merge(FaserActsAlignmentCondAlgCfg(flags)) + acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags) + acc.merge(acts_tracking_geometry_svc ) + + # track_seed_tool = CompFactory.ClusterTrackSeedTool() + # track_seed_tool = CompFactory.ActsTrackSeedTool() + # track_seed_tool = CompFactory.MyTrackSeedTool() + # track_seed_tool = CompFactory.ThreeStationTrackSeedTool() + track_seed_tool = CompFactory.CircleFitTrackSeedTool() + sigma_loc0 = 1.9e-2 + sigma_loc1 = 9e-1 + sigma_phi = 3.3e-2 + sigma_theta = 2.9e-4 + p = 1000 + sigma_p = 0.1 * p + sigma_qop = sigma_p / (p * p) + # initial_variance_inflation = [1000, 1000, 100, 100, 10000] + initial_variance_inflation = [100, 100, 100, 100, 1000] + track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc1 * sigma_loc1 + track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc0 * sigma_loc0 + track_seed_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi + track_seed_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta + track_seed_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop + track_seed_tool.std_cluster = 0.0231 + origin = -1900 + track_seed_tool.origin = origin + track_seed_tool.TrackCollection = "Segments" + + trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + trajectory_states_writer_tool1 = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool1.noDiagnostics = kwargs["noDiagnostics"] + trajectory_states_writer_tool1.FilePath = "track_states_ckf1.root" + trajectory_states_writer_tool2 = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool2.FilePath = "track_states_ckf2.root" + trajectory_states_writer_tool2.noDiagnostics = kwargs["noDiagnostics"] + + trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool(**kwargs) + trajectory_summary_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + trajectory_summary_writer_tool1 = CompFactory.RootTrajectorySummaryWriterTool() + trajectory_summary_writer_tool1.FilePath = "track_summary_ckf1.root" + trajectory_summary_writer_tool1.noDiagnostics = kwargs["noDiagnostics"] + trajectory_summary_writer_tool2 = CompFactory.RootTrajectorySummaryWriterTool(**kwargs) + trajectory_summary_writer_tool2.FilePath = "track_summary_ckf2.root" + trajectory_summary_writer_tool2.noDiagnostics = kwargs["noDiagnostics"] + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 1000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + + # trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool", **kwargs) + # trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool + # trajectory_performance_writer_tool.noDiagnostics = kwargs["noDiagnostics"] + + + ckf = CompFactory.CKF2(**kwargs) + kalman_fitter1 = CompFactory.KalmanFitterTool(name="fitterTool1", **kwargs) + kalman_fitter1.noDiagnostics = kwargs["noDiagnostics"] + kalman_fitter1.ActsLogging = "INFO" + kalman_fitter1.SummaryWriter = True + kalman_fitter1.StatesWriter = True + kalman_fitter1.SeedCovarianceScale = 10 + kalman_fitter1.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool1 + kalman_fitter1.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool1 + kalman_fitter1.origin = origin + ckf.KalmanFitterTool1 = kalman_fitter1 + + kalman_fitter2 = CompFactory.KalmanFitterTool(name="fitterTool2", **kwargs) + kalman_fitter2.noDiagnostics = kwargs["noDiagnostics"] + kalman_fitter2.ActsLogging = "INFO" + kalman_fitter2.SummaryWriter = True + kalman_fitter2.StatesWriter = True + kalman_fitter2.SeedCovarianceScale = 1 + kalman_fitter2.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool2 + kalman_fitter2.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool2 + kalman_fitter2.origin = origin + ckf.KalmanFitterTool2 = kalman_fitter2 + + ckf.TrackSeed = track_seed_tool + ckf.ActsLogging = "INFO" + ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool + ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool + ckf.SummaryWriter = True + ckf.StatesWriter = True + ckf.PerformanceWriter = False + # ckf.PerformanceWriterTool = trajectory_performance_writer_tool + ckf.origin = origin + + ckf.nMax = 10 + ckf.chi2Max = 100000 + acc.addEventAlgo(ckf) + acc.merge(CKF2_OutputCfg(flags)) + return acc diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..013e242db7572fc4a92875cd8a6188ed45bc5171 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx @@ -0,0 +1,147 @@ +#include "FaserActsKalmanFilter/ActsTrackSeedTool.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "boost/container/small_vector.hpp" +#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" + +using namespace Acts::UnitLiterals; + + +ActsTrackSeedTool::ActsTrackSeedTool( + const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode ActsTrackSeedTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_clusterContainerKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode ActsTrackSeedTool::run() { + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey}; + ATH_CHECK(clusterContainer.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext(); + Acts::GeometryContext geoctx = gctx.context(); + + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::map<Index, Identifier> identifierLinkMap; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) { + for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) { + Identifier id = cluster->detectorElement()->identify(); + identifierLinkMap[measurements.size()] = id; + if (identifierMap->count(id) != 0) { + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size(), cluster); + // create measurement + const auto& par = cluster->localPosition(); + Eigen::Matrix<double, 1, 1> pos {par.x(),}; + Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,}; + ThisMeasurement meas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + clusters.push_back(cluster); + } + } + } + + std::map<int, std::vector<Amg::Vector3D>> station_position_map; + for (const Trk::Track* track : *trackCollection) { + auto momentum = track->trackParameters()->front()->momentum(); + ATH_MSG_DEBUG("track momentum: " << momentum.x() << ", " << momentum.y() << ", " << momentum.z()); + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + Identifier id = clusterOnTrack->identify(); + int station = m_idHelper->station(id); + auto fitParameters = track->trackParameters()->front(); + Amg::Vector3D fitPosition = fitParameters->position(); + station_position_map[station].push_back(fitPosition); + break; + } + } + } + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + std::vector<Acts::CurvilinearTrackParameters> initParams {}; + for (const Amg::Vector3D& pos1 : station_position_map[1]) { + for (const Amg::Vector3D& pos2 : station_position_map[2]) { + for (const Amg::Vector3D& pos3 : station_position_map[3]) { + initParams.push_back(get_params(geoctx, pos1, pos2, pos3, cov, m_origin)); +// auto seed = initParams.back(); +// auto seed_momentum = seed.momentum(); + } + } + } + + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams); + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1}); + m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters); + + return StatusCode::SUCCESS; +} + + +StatusCode ActsTrackSeedTool::finalize() { + return StatusCode::SUCCESS; +} + + +Acts::CurvilinearTrackParameters ActsTrackSeedTool::get_params( + const Acts::GeometryContext& gctx, const Amg::Vector3D& pos1, + const Amg::Vector3D& pos2, const Amg::Vector3D& pos3, + const Acts::BoundSymMatrix& cov, double /*origin*/) { + const auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, pos1.z()}, Acts::Vector3{0, 0, -1}); + boost::container::small_vector<const Amg::Vector3D*, 3> spacepoints {}; + spacepoints.push_back(&pos1); + spacepoints.push_back(&pos2); + spacepoints.push_back(&pos3); + auto trackParams = Acts::CurvilinearTrackParameters(Acts::Vector4{0, 0, 0, 0}, Acts::Vector3{0, 0, 0}, 0, 0, cov); + auto optParams = Acts::estimateTrackParamsFromSeed( + gctx, spacepoints.begin(), spacepoints.end(), *surface, Acts::Vector3{0.57_T, 0, 0}, 0.1_T); + if (not optParams.has_value()) { + std::cout << "Estimation of track parameters failed." << std::endl; + } else { + const auto& params = optParams.value(); + double charge = std::copysign(1, params[Acts::eBoundQOverP]); + Acts::Vector4 pos {params.x(), params.y(), params.z(), params.w()}; + Acts::Vector3 dir{std::sin(params[Acts::eBoundTheta]) * std::cos(params[Acts::eBoundPhi]), + std::sin(params[Acts::eBoundTheta]) * std::sin(params[Acts::eBoundPhi]), + std::cos(params[Acts::eBoundTheta])}; + double abs_momentum = std::abs(1/params[Acts::eBoundQOverP]); + trackParams = Acts::CurvilinearTrackParameters(pos, dir, charge, abs_momentum, cov); + } + return trackParams; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e75632427e36b77d968cf9cb961268ac5342a481 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx @@ -0,0 +1,565 @@ +#include "FaserActsKalmanFilter/CKF2.h" + +#include "StoreGate/ReadHandle.h" +#include "StoreGate/ReadCondHandleKey.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrkPrepRawData/PrepRawData.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrkRIO_OnTrack/RIO_OnTrack.h" +#include "TrkSurfaces/Surface.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "FaserActsKalmanFilter/TrackSelection.h" +#include <algorithm> + +#include "FaserActsGeometry/FASERMagneticFieldWrapper.h" + +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" + + +#include "Acts/EventData/Measurement.hpp" + +size_t CKF2::TrajectoryInfo::nClusters {0}; + +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; +//std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; + + +CKF2::CKF2( + const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator) {} + + +StatusCode CKF2::initialize() { + ATH_CHECK(m_fieldCondObjInputKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackSeedTool.retrieve()); + ATH_CHECK(m_kalmanFitterTool1.retrieve()); + ATH_CHECK(m_kalmanFitterTool2.retrieve()); + // ATH_CHECK(m_trackCollection.initialize()); + if (m_performanceWriter && !m_noDiagnostics) { + ATH_CHECK(m_performanceWriterTool.retrieve()); + } + if (m_statesWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectoryStatesWriterTool.retrieve()); + } + if (m_summaryWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectorySummaryWriterTool.retrieve()); + } + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + m_fit = makeTrackFinderFunction(m_trackingGeometryTool->trackingGeometry(), + m_resolvePassive, m_resolveMaterial, m_resolveSensitive); + m_kf = makeTrackFitterFunction(m_trackingGeometryTool->trackingGeometry()); + // FIXME fix Acts logging level + if (m_actsLogging == "VERBOSE") { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE); + } else if (m_actsLogging == "DEBUG") { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG); + } else { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO); + } + return StatusCode::SUCCESS; +} + + +StatusCode CKF2::execute() { + const EventContext& ctx = Gaudi::Hive::currentContext(); + m_numberOfEvents++; + + ATH_CHECK(m_trackCollection.initialize()); + SG::WriteHandle<TrackCollection> trackContainer{m_trackCollection,ctx}; + std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>(); + + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry + = m_trackingGeometryTool->trackingGeometry(); + + const FaserActsGeometryContext& faserActsGeometryContext = m_trackingGeometryTool->getNominalGeometryContext(); + auto gctx = faserActsGeometryContext.context(); + Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx); + Acts::CalibrationContext calibContext; + + CHECK(m_trackSeedTool->run()); + std::shared_ptr<const Acts::Surface> initialSurface = + m_trackSeedTool->initialSurface(); + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialParameters = + m_trackSeedTool->initialTrackParameters(); + std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks = + m_trackSeedTool->sourceLinks(); + double origin = m_trackSeedTool->targetZPosition(); + + std::shared_ptr<std::vector<Measurement>> measurements = m_trackSeedTool->measurements(); + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters = m_trackSeedTool->clusters(); + std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints = m_trackSeedTool->spacePoints(); + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters = m_trackSeedTool->seedClusters(); + + TrajectoryInfo::nClusters = sourceLinks->size(); + TrajectoriesContainer trajectories; + trajectories.reserve(initialParameters->size()); + + Acts::PropagatorPlainOptions pOptions; + pOptions.maxSteps = m_maxSteps; + + Acts::MeasurementSelector::Config measurementSelectorCfg = { + {Acts::GeometryIdentifier(), {m_chi2Max, m_nMax}}, + }; + + Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity(); + rotation.col(0) = Acts::Vector3(0, 0, -1); + rotation.col(1) = Acts::Vector3(0, 1, 0); + rotation.col(2) = Acts::Vector3(1, 0, 0); + Acts::Translation3 trans(0., 0., origin); + Acts::Transform3 trafo(rotation * trans); + initialSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(trafo); + + // Set the CombinatorialKalmanFilter options + CKF2::TrackFinderOptions options( + gctx, magFieldContext, calibContext, + IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements), + Acts::MeasurementSelector(measurementSelectorCfg), + Acts::LoggerWrapper{*m_logger}, pOptions, &(*initialSurface)); + + // Perform the track finding for all initial parameters + m_numberOfTrackSeeds += initialParameters->size(); + ATH_MSG_DEBUG("Invoke track finding with " << initialParameters->size() << " seeds."); + IndexSourceLinkContainer tmp; + for (const auto& sl : *sourceLinks) { + tmp.emplace_hint(tmp.end(), sl); + } + + for (const auto& init : *initialParameters) { + ATH_MSG_DEBUG(" position: " << init.position(gctx).transpose()); + ATH_MSG_DEBUG(" momentum: " << init.momentum().transpose()); + ATH_MSG_DEBUG(" charge: " << init.charge()); + } + + auto results = (*m_fit)(tmp, *initialParameters, options); + + // results contain a MultiTrajectory for each track seed with a trajectory of each branch of the CKF. + // To simplify the ambiguity solving a list of MultiTrajectories is created, each containing only a single track. + std::list<TrajectoryInfo> allTrajectories; + for (auto &result : results) { + if (not result.ok()) { + continue; + } + CKFResult ckfResult = result.value(); + for (size_t trackTip : ckfResult.lastMeasurementIndices) { + allTrajectories.emplace_back(TrajectoryInfo(FaserActsRecMultiTrajectory( + ckfResult.fittedStates, {trackTip}, {{trackTip, ckfResult.fittedParameters.at(trackTip)}}))); + } + } + m_numberOfFittedTracks += allTrajectories.size(); + + // the list of MultiTrajectories is sorted by the number of measurements using the chi2 value as a tie-breaker + allTrajectories.sort([](const TrajectoryInfo &left, const TrajectoryInfo &right) { + if (left.nMeasurements > right.nMeasurements) return true; + if (left.nMeasurements < right.nMeasurements) return false; + if (left.chi2 < right.chi2) return true; + else return false; + }); + + // select all tracks with at least 13 heats and with 6 or less shared hits, starting from the best track + // TODO use Gaudi parameters for the number of hits and shared hits + // TODO allow shared hits only in the first station? + std::vector<FaserActsRecMultiTrajectory> selectedTrajectories {}; + while (not allTrajectories.empty()) { + TrajectoryInfo selected = allTrajectories.front(); + selectedTrajectories.push_back(selected.trajectory); + allTrajectories.remove_if([&](const TrajectoryInfo &p) { + return (p.nMeasurements <= 12) || ((p.clusterSet & selected.clusterSet).count() > 6); + }); + } + + for (const FaserActsRecMultiTrajectory &traj : selectedTrajectories) { + const auto params = traj.trackParameters(traj.tips().front()); + ATH_MSG_DEBUG("Fitted parameters"); + ATH_MSG_DEBUG(" params: " << params.parameters().transpose()); + ATH_MSG_DEBUG(" position: " << params.position(gctx).transpose()); + ATH_MSG_DEBUG(" momentum: " << params.momentum().transpose()); + ATH_MSG_DEBUG(" charge: " << params.charge()); + // double charge = params.charge(); + std::unique_ptr<Trk::Track> track = makeTrack(gctx, traj); + if (track) { + // outputTracks->push_back(std::move(track)); + std::unique_ptr<Trk::Track> track2 = m_kalmanFitterTool1->fit(ctx, gctx, *track, trajectories, Acts::BoundVector::Zero(), m_isMC, origin); + if (track2) { + std::unique_ptr<Trk::Track> track3 = m_kalmanFitterTool2->fit(ctx, gctx, *track2, trajectories, Acts::BoundVector::Zero(), m_isMC, origin); + outputTracks->push_back(std::move(track3)); + m_numberOfSelectedTracks++; + } + } + } + + // run the performance writer + if (m_statesWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectoryStatesWriterTool->write(gctx, selectedTrajectories, m_isMC)); + } + if (m_summaryWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectorySummaryWriterTool->write(gctx, selectedTrajectories, m_isMC)); + } + if (m_performanceWriter && !m_noDiagnostics) { + ATH_CHECK(m_performanceWriterTool->write(gctx, selectedTrajectories)); + } + ATH_CHECK(trackContainer.record(std::move(outputTracks))); + + return StatusCode::SUCCESS; +} + + +StatusCode CKF2::finalize() { + ATH_MSG_INFO("CombinatorialKalmanFilterAlg::finalize()"); + ATH_MSG_INFO(m_numberOfEvents << " events processed."); + ATH_MSG_INFO(m_numberOfTrackSeeds << " seeds."); + ATH_MSG_INFO(m_numberOfFittedTracks << " fitted tracks."); + ATH_MSG_INFO(m_numberOfSelectedTracks << " selected and re-fitted tracks."); + return StatusCode::SUCCESS; +} + + +Acts::MagneticFieldContext CKF2::getMagneticFieldContext(const EventContext& ctx) const { + SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; + if (!readHandle.isValid()) { + std::stringstream msg; + msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << "."; + throw std::runtime_error(msg.str()); + } + const FaserFieldCacheCondObj* fieldCondObj{*readHandle}; + return Acts::MagneticFieldContext(fieldCondObj); +} + + +std::unique_ptr<Trk::Track> +CKF2::makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const { + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + std::unique_ptr<Trk::Track> newtrack = nullptr; + //Get the fit output object + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; + // Loop over all the output state to create track state + traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + // We need to determine the type of state + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + // State is a hole (no associated measurement), use predicted para meters + if (flag[Acts::TrackStateFlag::HoleFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), + state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + // The state was tagged as an outlier, use filtered parameters + else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + // The state is a measurement state, use smoothed parameters + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); + // const auto& psurface=actsParam.referenceSurface(); + Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); + // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); + // auto pos=actsParam.position(tgContext); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit(); + if (fitCluster->detectorElement() != nullptr) { + measState = new Tracker::FaserSCT_ClusterOnTrack{ + fitCluster, + Trk::LocalParameters{ + Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2} + }, + fitCluster->localCovariance(), + m_idHelper->wafer_hash(fitCluster->detectorElement()->identify()) + }; + } + } + double nDoF = state.calibratedSize(); + const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); + // If a state was succesfully created add it to the trajectory + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + // Create the track using the states + const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + // Trk::FitQuality* q = nullptr; + // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter + newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); + return newtrack; +} + + +std::unique_ptr<Trk::Track> +CKF2::makeTrack(Acts::GeometryContext& geoCtx, TrackFitterResult& fitResult) const { + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + std::unique_ptr<Trk::Track> newtrack = nullptr; + //Get the fit output object + const auto& fitOutput = fitResult.value(); + if (fitOutput.fittedParameters.size() > 0) { + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; + // Loop over all the output state to create track state + fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndices.front(), [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + // We need to determine the type of state + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + // State is a hole (no associated measurement), use predicted para meters + if (flag[Acts::TrackStateFlag::HoleFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), + state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + // The state was tagged as an outlier, use filtered parameters + else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + // The state is a measurement state, use smoothed parameters + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); + // const auto& psurface=actsParam.referenceSurface(); + Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); + // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); + // auto pos=actsParam.position(tgContext); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit(); + if (fitCluster->detectorElement() != nullptr) { + measState = new Tracker::FaserSCT_ClusterOnTrack{ + fitCluster, + Trk::LocalParameters{ + Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2} + }, + fitCluster->localCovariance(), + m_idHelper->wafer_hash(fitCluster->detectorElement()->identify()) + }; + } + } + double nDoF = state.calibratedSize(); + const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); + // If a state was succesfully created add it to the trajectory + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + // Create the track using the states + const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + // Trk::FitQuality* q = nullptr; + // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter + newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); + } + return newtrack; +} + +const Trk::TrackParameters* +CKF2::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const { + using namespace Acts::UnitLiterals; + std::optional<AmgSymMatrix(5)> cov = std::nullopt; + if (actsParameter.covariance()){ + AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5)); + // Convert the covariance matrix to GeV + for(int i=0; i < newcov.rows(); i++){ + newcov(i, 4) = newcov(i, 4)*1_MeV; + } + for(int i=0; i < newcov.cols(); i++){ + newcov(4, i) = newcov(4, i)*1_MeV; + } + cov = std::optional<AmgSymMatrix(5)>(newcov); + } + const Amg::Vector3D& pos=actsParameter.position(gctx); + double tphi=actsParameter.get<Acts::eBoundPhi>(); + double ttheta=actsParameter.get<Acts::eBoundTheta>(); + double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV; + double p = std::abs(1. / tqOverP); + Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta)); + const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov); + return curv; +} + +void CKF2::computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const { + // Compute shared hits from all the reconstructed tracks + // Compute nSharedhits and Update ckf results + // hit index -> list of multi traj indexes [traj, meas] + static_assert(Acts::SourceLinkConcept<IndexSourceLink>, + "Source link does not fulfill SourceLinkConcept"); + + std::vector<std::size_t> firstTrackOnTheHit( + sourceLinks->size(), std::numeric_limits<std::size_t>::max()); + std::vector<std::size_t> firstStateOnTheHit( + sourceLinks->size(), std::numeric_limits<std::size_t>::max()); + + for (unsigned int iresult = 0; iresult < results.size(); iresult++) { + if (not results.at(iresult).ok()) { + continue; + } + + auto& ckfResult = results.at(iresult).value(); + auto& measIndexes = ckfResult.lastMeasurementIndices; + + for (auto measIndex : measIndexes) { + ckfResult.fittedStates.visitBackwards(measIndex, [&](const auto& state) { + if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + return; + + std::size_t hitIndex = state.uncalibrated().index(); + + // Check if hit not already used + if (firstTrackOnTheHit.at(hitIndex) == + std::numeric_limits<std::size_t>::max()) { + firstTrackOnTheHit.at(hitIndex) = iresult; + firstStateOnTheHit.at(hitIndex) = state.index(); + return; + } + + // if already used, control if first track state has been marked + // as shared + int indexFirstTrack = firstTrackOnTheHit.at(hitIndex); + int indexFirstState = firstStateOnTheHit.at(hitIndex); + if (not results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) + results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + + // Decorate this track + results.at(iresult).value().fittedStates.getTrackState(state.index()).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + }); + } + } +} + + +namespace { + +using Updater = Acts::GainMatrixUpdater; +using Smoother = Acts::GainMatrixSmoother; + +using Stepper = Acts::EigenStepper<>; +using Navigator = Acts::Navigator; +using Propagator = Acts::Propagator<Stepper, Navigator>; +using CKF = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>; + +using TrackParametersContainer = std::vector<CKF2::TrackParameters>; + +struct TrackFinderFunctionImpl + : public CKF2::TrackFinderFunction { + CKF trackFinder; + + TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {} + + CKF2::TrackFinderResult operator()( + const IndexSourceLinkContainer& sourcelinks, + const TrackParametersContainer& initialParameters, + const CKF2::TrackFinderOptions& options) + const override { + return trackFinder.findTracks(sourcelinks, initialParameters, options); + }; +}; + +} // namespace + +std::shared_ptr<CKF2::TrackFinderFunction> +CKF2::makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + bool resolvePassive, bool resolveMaterial, bool resolveSensitive) { + auto magneticField = std::make_shared<FASERMagneticFieldWrapper>(); + Stepper stepper(std::move(magneticField)); + Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = resolvePassive; + cfg.resolveMaterial = resolveMaterial; + cfg.resolveSensitive = resolveSensitive; + Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + CKF trackFinder(std::move(propagator)); + + // build the track finder functions. owns the track finder object. + return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder)); +} + + +namespace { + +using Updater = Acts::GainMatrixUpdater; +using Smoother = Acts::GainMatrixSmoother; +using Stepper = Acts::EigenStepper<>; +using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; +using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>; + +struct TrackFitterFunctionImpl + : public CKF2::TrackFitterFunction { + Fitter trackFitter; + + TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {} + + CKF2::KFResult operator()( + const std::vector<IndexSourceLink> &sourceLinks, + const Acts::BoundTrackParameters &initialParameters, + const CKF2::TrackFitterOptions &options) + const override { + return trackFitter.fit(sourceLinks, initialParameters, options); + }; +}; + +} // namespace + + +std::shared_ptr<CKF2::TrackFitterFunction> +CKF2::makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) { + auto magneticField = std::make_shared<FASERMagneticFieldWrapper>(); + auto stepper = Stepper(std::move(magneticField)); + Acts::Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + Fitter trackFitter(std::move(propagator)); + return std::make_shared<TrackFitterFunctionImpl>(std::move(trackFitter)); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9f1fab11cf10edac1a497c7af498e737b5bd84c6 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx @@ -0,0 +1,169 @@ +#include "FaserActsKalmanFilter/CircleFit.h" + +namespace CircleFit { + +CircleData::CircleData(const std::vector<const Tracker::FaserSCT_SpacePoint *> &spacePoints) { + for (auto sp: spacePoints) { + m_x.push_back(sp->globalPosition().z()); + m_y.push_back(sp->globalPosition().y()); + } + m_size = spacePoints.size(); +} + +CircleData::CircleData(const std::vector<Amg::Vector3D> &spacePoints) { + for (auto sp: spacePoints) { + m_x.push_back(sp.z()); + m_y.push_back(sp.y()); + } + m_size = spacePoints.size(); +} + +double CircleData::meanX() const { + double mean = 0; + for (double i: m_x) mean += i; + return mean / m_size; +} + +double CircleData::meanY() const { + double mean = 0; + for (double i: m_y) mean += i; + return mean / m_size; +} + +double CircleData::x(int i) const { + return m_x[i]; +} + +double CircleData::y(int i) const { + return m_y[i]; +} + +int CircleData::size() const { + return m_size; +} + + +double sigma(const CircleData &data, const Circle &circle) { + double sum=0.,dx,dy; + for (int i=0; i<data.size(); i++) { + dx = data.x(i) - circle.cx; + dy = data.y(i) - circle.cy; + sum += (sqrt(dx*dx+dy*dy) - circle.r) * (sqrt(dx*dx+dy*dy) - circle.r); + } + return sqrt(sum/data.size()); +} + + +Circle circleFit(const CircleData &data) +/* + Circle fit to a given set of data points (in 2D) + + This is an algebraic fit, due to Taubin, based on the journal article + + G. Taubin, "Estimation Of Planar Curves, Surfaces And Nonplanar + Space Curves Defined By Implicit Equations, With + Applications To Edge And Range Image Segmentation", + IEEE Trans. PAMI, Vol. 13, pages 1115-1138, (1991) + + Input: data - the class of data (contains the given points): + + data.size() - the number of data points + data.X[] - the array of X-coordinates + data.Y[] - the array of Y-coordinates + + Output: + circle - parameters of the fitting circle: + + circle.a - the X-coordinate of the center of the fitting circle + circle.b - the Y-coordinate of the center of the fitting circle + circle.r - the radius of the fitting circle + circle.s - the root mean square error (the estimate of sigma) + circle.j - the total number of iterations + + The method is based on the minimization of the function + + sum [(x-a)^2 + (y-b)^2 - R^2]^2 + F = ------------------------------- + sum [(x-a)^2 + (y-b)^2] + + This method is more balanced than the simple Kasa fit. + + It works well whether data points are sampled along an entire circle or + along a small arc. + + It still has a small bias and its statistical accuracy is slightly + lower than that of the geometric fit (minimizing geometric distances), + but slightly higher than that of the very similar Pratt fit. + Besides, the Taubin fit is slightly simpler than the Pratt fit + + It provides a very good initial guess for a subsequent geometric fit. + + Nikolai Chernov (September 2012) + +*/ +{ + int i, iter, IterMAX = 999; + + double Xi, Yi, Zi; + double Mz, Mxy, Mxx, Myy, Mxz, Myz, Mzz, Cov_xy, Var_z; + double A0, A1, A2, A22, A3, A33; + double Dy, xnew, x, ynew, y; + double DET, Xcenter, Ycenter; + + Circle circle; + + Mxx = Myy = Mxy = Mxz = Myz = Mzz = 0.; + for (i = 0; i < data.size(); i++) { + Xi = data.x(i) - data.meanX(); + Yi = data.y(i) - data.meanY(); + Zi = Xi * Xi + Yi * Yi; + + Mxy += Xi * Yi; + Mxx += Xi * Xi; + Myy += Yi * Yi; + Mxz += Xi * Zi; + Myz += Yi * Zi; + Mzz += Zi * Zi; + } + Mxx /= data.size(); + Myy /= data.size(); + Mxy /= data.size(); + Mxz /= data.size(); + Myz /= data.size(); + Mzz /= data.size(); + + Mz = Mxx + Myy; + Cov_xy = Mxx * Myy - Mxy * Mxy; + Var_z = Mzz - Mz * Mz; + A3 = 4 * Mz; + A2 = -3 * Mz * Mz - Mzz; + A1 = Var_z * Mz + 4 * Cov_xy * Mz - Mxz * Mxz - Myz * Myz; + A0 = Mxz * (Mxz * Myy - Myz * Mxy) + Myz * (Myz * Mxx - Mxz * Mxy) - Var_z * Cov_xy; + A22 = A2 + A2; + A33 = A3 + A3 + A3; + + for (x = 0., y = A0, iter = 0; iter < IterMAX; iter++) { + Dy = A1 + x * (A22 + A33 * x); + xnew = x - y / Dy; + if ((xnew == x) || (!std::isfinite(xnew))) break; + ynew = A0 + xnew * (A1 + xnew * (A2 + xnew * A3)); + if (abs(ynew) >= abs(y)) break; + x = xnew; + y = ynew; + } + + DET = x * x - x * Mz + Cov_xy; + Xcenter = (Mxz * (Myy - x) - Myz * Mxy) / DET / 2; + Ycenter = (Myz * (Mxx - x) - Mxz * Mxy) / DET / 2; + + circle.cx = Xcenter + data.meanX(); + circle.cy = Ycenter + data.meanY(); + circle.r = sqrt(Xcenter * Xcenter + Ycenter * Ycenter + Mz); + circle.s = sigma(data, circle); + circle.i = 0; + circle.j = iter; + + return circle; +} + +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..18499e4964e49ebf4ef041a870125bdae2d2d694 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx @@ -0,0 +1,346 @@ +#include "FaserActsKalmanFilter/CircleFitTrackSeedTool.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "FaserActsKalmanFilter/CircleFit.h" +#include "FaserActsKalmanFilter/LinearFit.h" +#include "FaserActsKalmanFilter/TrackClassification.h" +#include <array> +#include <algorithm> + + +std::map<Identifier,Index> CircleFitTrackSeedTool::s_indexMap {}; +std::map<Identifier, const Tracker::FaserSCT_SpacePoint*> CircleFitTrackSeedTool::s_spacePointMap {}; + +CircleFitTrackSeedTool::CircleFitTrackSeedTool( + const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode CircleFitTrackSeedTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_clusterContainerKey.initialize()); + ATH_CHECK(m_spacePointContainerKey.initialize()); + // ATH_CHECK(m_simDataCollectionKey.initialize()); + // ATH_CHECK(m_mcEventCollectionKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode CircleFitTrackSeedTool::run() { + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey}; + ATH_CHECK(clusterContainer.isValid()); + + SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey}; + ATH_CHECK(spacePointContainer.isValid()); + + // SG::ReadHandle<TrackerSimDataCollection> simData {m_simDataCollectionKey}; + // ATH_CHECK(simData.isValid()); + + // SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey}; + // ATH_CHECK(mcEvents.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + // std::map<int, const HepMC::GenParticle*> particles {}; + // for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) { + // particles[particle->barcode()] = particle; + // } + + // std::map<Identifier, const Tracker::FaserSCT_SpacePoint*> s_spacePointMap {}; + std::vector<const Tracker::FaserSCT_SpacePoint*> spacePoints {}; + for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) { + for (const Tracker::FaserSCT_SpacePoint *spacePoint: *spacePointCollection) { + spacePoints.push_back(spacePoint); + Identifier id1 = spacePoint->cluster1()->identify(); + CircleFitTrackSeedTool::s_spacePointMap[id1] = spacePoint; + Identifier id2 = spacePoint->cluster2()->identify(); + CircleFitTrackSeedTool::s_spacePointMap[id2] = spacePoint; + } + } + + + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, 1>; + std::array<Acts::BoundIndices, 1> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks {}; + std::vector<Measurement> measurements {}; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) { + for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) { + clusters.push_back(cluster); + Identifier id = cluster->detectorElement()->identify(); + CircleFitTrackSeedTool::s_indexMap[cluster->identify()] = measurements.size(); + if (identifierMap->count(id) != 0) { + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size(), cluster); + // create measurement + const auto& par = cluster->localPosition(); + Eigen::Matrix<double, 1, 1> pos {par.x(),}; + Eigen::Matrix<double, 1, 1> cov {0.0231 * 0.0231,}; + ThisMeasurement meas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + } + } + } + + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + std::array<std::vector<Segment>, 4> segments {}; + for (const Trk::Track* track : *trackCollection) { + auto s = Segment(track, m_idHelper); + segments[s.station].push_back(s); + } + + std::vector<Segment> combination {}; + std::vector<Seed> seeds {}; + // create seeds from four stations + go(segments, combination, seeds, 0, 4); + if (seeds.size() < 2) { + // create seeds from three stations + go(segments, combination, seeds, 0, 3); + } + // create seeds from two stations + if (seeds.size() < 2) { + go(segments, combination, seeds, 0, 2); + } + if (seeds.size() < 2) { + go(segments, combination, seeds, 0, 1); + } + + std::list<Seed> allSeeds; + for (const Seed &seed : seeds) allSeeds.push_back(seed); + + /* + allSeeds.sort([](const Seed &left, const Seed &right) { + if (left.size > right.size) return true; + if (left.size < right.size) return false; + if (left.chi2 < right.chi2) return true; + else return false; + }); + + std::vector<Seed> selectedSeeds {}; + while (not allSeeds.empty()) { + Seed selected = allSeeds.front(); + selectedSeeds.push_back(selected); + allSeeds.remove_if([&](const Seed &p) { + return (p.size <= 12) || ((p.clusterSet & selected.clusterSet).count() > 6); + }); + } + */ + + std::vector<Seed> selectedSeeds {}; + for (const Seed &seed : allSeeds) { + selectedSeeds.push_back(seed); + } + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + auto minSeed = std::min_element( + selectedSeeds.begin(), selectedSeeds.end(), [](const Seed &lhs, const Seed &rhs) { + return lhs.minZ < rhs.minZ; + }); + double origin = !selectedSeeds.empty() ? minSeed->minZ : 0; + m_targetZPosition = origin; + std::vector<Acts::CurvilinearTrackParameters> initParams {}; + for (const Seed &seed : selectedSeeds) { + initParams.push_back(seed.get_params(origin, cov)); + } + + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams); + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + // m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1}); + m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters); + m_spacePoints = std::make_shared<std::vector<const Tracker::FaserSCT_SpacePoint*>>(spacePoints); + + /* + std::cout.precision(17); + for (auto &seed : selectedSeeds) { + std::cout << "np.array(["; + for (const Acts::Vector3 &pos : seed.fakePositions) { + std::cout << "[" << pos.x() << ", " << pos.y() << ", " << pos.z() << "], "; + } + std::cout << "])" << std::endl; + std::cout << "chi2: " << seed.chi2 << ", momentum: " << seed.momentum << ", charge: " << seed.charge << std::endl; + std::cout << "fit = np.array([" << seed.c1 << ", " << seed.c0 << ", " << seed.cy << ", " << seed.cx << ", " << seed.r << "])" << std::endl; + + std::vector<ParticleHitCount> particleHitCounts; + identifyContributingParticles(*simData, seed.clusters, particleHitCounts); + auto ip = particles.find(particleHitCounts.front().particleId); + if (ip != particles.end()) { + const HepMC::GenParticle* particle = ip->second; + HepMC::FourVector momentum = particle->momentum(); + std::cout << "true momentum: " << momentum.rho() * 0.001 << std::endl; + } + for (const ParticleHitCount &hitCount : particleHitCounts) { + std::cout << hitCount.particleId << " : " << hitCount.hitCount << std::endl; + } + } + */ + + s_indexMap.clear(); + + return StatusCode::SUCCESS; +} + + +StatusCode CircleFitTrackSeedTool::finalize() { + return StatusCode::SUCCESS; +} + + +void CircleFitTrackSeedTool::go(const std::array<std::vector<Segment>, 4> &v, + std::vector<Segment> &combination, + std::vector<Seed> &seeds, + int offset, int k) { + if (k == 0) { + seeds.push_back(Seed(combination)); + return; + } + for (std::size_t i = offset; i < v.size() + 1 - k; ++i) { + for (const auto& ve : v[i]) { + combination.push_back(ve); + go(v, combination, seeds, i+1, k-1); + combination.pop_back(); + } + } +} + +CircleFitTrackSeedTool::Segment::Segment(const Trk::Track* track, const FaserSCT_ID *idHelper) : + clusterSet(CircleFitTrackSeedTool::s_indexMap.size()) { + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + Identifier id = cluster->identify(); + clusters.push_back(cluster); + if (CircleFitTrackSeedTool::s_spacePointMap.count(id) > 0) { + const Tracker::FaserSCT_SpacePoint *sp = CircleFitTrackSeedTool::s_spacePointMap.at(cluster->identify()); + if (std::find(spacePoints.begin(), spacePoints.end(), sp) == spacePoints.end()) { + spacePoints.push_back(sp); + } + } + station = idHelper->station(id); + clusterSet.set(CircleFitTrackSeedTool::s_indexMap.at(id)); + auto fitParameters = track->trackParameters()->front(); + position = fitParameters->position(); + momentum = fitParameters->momentum(); + } + } + fakePositions.push_back(position); + fakePositions.push_back(position - 30 * momentum.normalized()); + fakePositions.push_back(position + 30 * momentum.normalized()); +} + +CircleFitTrackSeedTool::Seed::Seed(const std::vector<Segment> &segments) : + clusterSet(CircleFitTrackSeedTool::s_indexMap.size()) { + for (const Segment &seg : segments) { + clusters.insert(clusters.end(), seg.clusters.begin(), seg.clusters.end()); + spacePoints.insert(spacePoints.end(), seg.spacePoints.begin(), seg.spacePoints.end()); + positions.push_back(seg.position); + // TODO use reconstruct space points instead of fake positions + fakePositions.insert(fakePositions.end(), seg.fakePositions.begin(), seg.fakePositions.end()); + for (size_t i = 0; i < seg.clusterSet.size(); ++i) { + if (seg.clusterSet[i]) clusterSet.set(i); + } + } + + auto minCluster = std::min_element( + clusters.begin(), clusters.end(), [](const Tracker::FaserSCT_Cluster *lhs, const Tracker::FaserSCT_Cluster *rhs) { + return lhs->globalPosition().z() < rhs->globalPosition().z(); + } ); + minZ = (*minCluster)->globalPosition().z(); + + if (segments.size() > 1) { + direction = positions[1] - positions[0]; + } else { + direction = segments[0].momentum; + } + + std::vector<Acts::Vector2> pointsZX {}; + for (const Acts::Vector3 &pos : fakePositions) { + pointsZX.push_back({pos.z(), pos.x()}); + } + linearFit(pointsZX); + + if (segments.size() > 1) { + fakeFit(); + } else { + momentum = 9999999.; + charge = 1; + } + + getChi2(); + size = clusters.size(); +} + + +void CircleFitTrackSeedTool::Seed::fit() { + CircleFit::CircleData circleData(positions); + CircleFit::Circle circle = CircleFit::circleFit(circleData); + momentum = circle.r > 0 ? circle.r * 0.001 * 0.3 * 0.55 : 9999999.; + charge = circle.cy < 0 ? -1 : 1; +} + +void CircleFitTrackSeedTool::Seed::fakeFit(double B) { + CircleFit::CircleData circleData(fakePositions); + CircleFit::Circle circle = CircleFit::circleFit(circleData); + cx = circle.cx; + cy = circle.cy; + r = circle.r; + momentum = r * 0.3 * B * m_MeV2GeV; + charge = circle.cy > 0 ? 1 : -1; +} + +void CircleFitTrackSeedTool::Seed::linearFit(const std::vector<Acts::Vector2> &points) { + auto [origin, dir] = LinearFit::linearFit(points); + c1 = dir[1]/dir[0]; + c0 = origin[1] - origin[0] * c1; +} + + +double CircleFitTrackSeedTool::Seed::getY(double z) { + double sqt = std::sqrt(-cx*cx + 2*cx*z + r*r - z*z); + return abs(cy - sqt) < abs(cy + sqt) ? cy - sqt : cy + sqt; +} + + +double CircleFitTrackSeedTool::Seed::getX(double z) { + return c0 + z * c1; +} + +void CircleFitTrackSeedTool::Seed::getChi2() { + chi2 = 0; + for (const Acts::Vector3 &pos : fakePositions) { + m_dy = pos.y() - getY(pos.z()); + chi2 += (m_dy * m_dy) / (m_sigma_y * m_sigma_y); + } + + for (const Acts::Vector3 &pos : positions) { + m_dx = pos.x() - getX(pos.x()); + chi2 += (m_dx * m_dx) / (m_sigma_x * m_sigma_x); + } +} + +Acts::CurvilinearTrackParameters CircleFitTrackSeedTool::Seed::get_params(double origin, Acts::BoundSymMatrix cov) const { + Acts::Vector3 pos = positions[0] - (positions[0].z() - origin)/direction.z() * direction; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + return Acts::CurvilinearTrackParameters(pos4, direction.normalized(), momentum, charge, cov); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8d78c9f0eaa1088675806b0a9aee1472ce3396ff --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.cxx @@ -0,0 +1,129 @@ +#include "FaserActsKalmanFilter/ClusterTrackSeedTool.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" + + +// FIXME make this a method of ClusterTrackSeedTool +std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57) { + Acts::Vector3 vec_l = pos.at(3) - pos.at(1); + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos.at(2).z() - pos.at(1).z()) / (pos.at(3).z() - pos.at(1).z()); + Acts::Vector3 vec_m = pos.at(1) + t * vec_l; + Acts::Vector3 vec_s = pos.at(2) - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); + double charge = vec_s.y() < 0 ? 1 : -1; + return std::make_pair(p_yz, charge); +} + + +ClusterTrackSeedTool::ClusterTrackSeedTool( + const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode ClusterTrackSeedTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_clusterContainerKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode ClusterTrackSeedTool::run() { + // create track seeds for multiple tracks + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey}; + ATH_CHECK(clusterContainer.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::map<Index, Identifier> identifierLinkMap; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) { + for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) { + Identifier id = cluster->detectorElement()->identify(); + identifierLinkMap[measurements.size()] = id; + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size()); + // create measurement + const auto& par = cluster->localPosition(); + Eigen::Matrix<double, 1, 1> pos {par.x(),}; + Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,}; + ThisMeasurement meas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + clusters.push_back(cluster); + } + } + + + std::map<int, std::vector<Amg::Vector3D>> station_position_map; + for (const Trk::Track* track : *trackCollection) { + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + Identifier id = clusterOnTrack->identify(); + int station = m_idHelper->station(id); + auto fitParameters = track->trackParameters()->front(); + Amg::Vector3D fitPosition = fitParameters->position(); + station_position_map[station].push_back(fitPosition); + break; + } + } + } + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + std::vector<Acts::CurvilinearTrackParameters> initParams {}; + for (const Amg::Vector3D& pos1 : station_position_map[1]) { + for (const Amg::Vector3D& pos2 : station_position_map[2]) { + initParams.push_back(get_params(pos1, pos2, cov, m_origin)); + } + } + + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams); + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, 1}); + m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters); + + return StatusCode::SUCCESS; +} + + +StatusCode ClusterTrackSeedTool::finalize() { + return StatusCode::SUCCESS; +} + + +Acts::CurvilinearTrackParameters ClusterTrackSeedTool::get_params( + const Amg::Vector3D& position_st1, const Amg::Vector3D& position_st2, const Acts::BoundSymMatrix& cov, double origin) { + Acts::Vector3 dir = position_st2 - position_st1; + Acts::Vector3 pos = position_st1 - (position_st1.z() - origin)/dir.z() * dir; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + return Acts::CurvilinearTrackParameters(pos4, dir, 100000000, 1, cov); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..71afcc4431fabb6064af9601d31dd783de497a4f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx @@ -0,0 +1,359 @@ +#include "FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h" + +#include "StoreGate/ReadHandle.h" +#include "StoreGate/ReadCondHandleKey.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrkPrepRawData/PrepRawData.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrkRIO_OnTrack/RIO_OnTrack.h" +#include "TrkSurfaces/Surface.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "FaserActsKalmanFilter/TrackSelection.h" +#include <algorithm> + + +size_t CombinatorialKalmanFilterAlg::TrajectoryInfo::nClusters {0}; + +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; +std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; + + +CombinatorialKalmanFilterAlg::CombinatorialKalmanFilterAlg( + const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator) {} + + +StatusCode CombinatorialKalmanFilterAlg::initialize() { + ATH_CHECK(m_fieldCondObjInputKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackSeedTool.retrieve()); + // ATH_CHECK(m_trackCollection.initialize()); + if (m_performanceWriter && !m_noDiagnostics) { + ATH_CHECK(m_performanceWriterTool.retrieve()); + } + if (m_statesWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectoryStatesWriterTool.retrieve()); + } + if (m_summaryWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectorySummaryWriterTool.retrieve()); + } + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + m_fit = makeTrackFinderFunction(m_trackingGeometryTool->trackingGeometry(), + m_resolvePassive, m_resolveMaterial, m_resolveSensitive); + if (m_actsLogging == "VERBOSE" && !m_noDiagnostics) { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE); + } else if (m_actsLogging == "DEBUG" && !m_noDiagnostics) { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG); + } else { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO); + } + return StatusCode::SUCCESS; +} + + +StatusCode CombinatorialKalmanFilterAlg::execute() { + + const EventContext& ctx = Gaudi::Hive::currentContext(); + m_numberOfEvents++; + + ATH_CHECK(m_trackCollection.initialize()); + SG::WriteHandle<TrackCollection> trackContainer{m_trackCollection,ctx}; + std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>(); + + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry + = m_trackingGeometryTool->trackingGeometry(); + + const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext(); + auto geoctx = gctx.context(); + Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx); + Acts::CalibrationContext calibContext; + + CHECK(m_trackSeedTool->run()); + std::shared_ptr<const Acts::Surface> initialSurface = + m_trackSeedTool->initialSurface(); + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialParameters = + m_trackSeedTool->initialTrackParameters(); + std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks = + m_trackSeedTool->sourceLinks(); + std::shared_ptr<IdentifierLink> idLinks = m_trackSeedTool->idLinks(); + std::shared_ptr<std::vector<Measurement>> measurements = m_trackSeedTool->measurements(); + std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters = m_trackSeedTool->clusters(); + std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters = m_trackSeedTool->seedClusters(); + + TrajectoryInfo::nClusters = sourceLinks->size(); + + TrajectoriesContainer trajectories; + trajectories.reserve(initialParameters->size()); + + Acts::PropagatorPlainOptions pOptions; + pOptions.maxSteps = m_maxSteps; + + Acts::MeasurementSelector::Config measurementSelectorCfg = { + {Acts::GeometryIdentifier(), {m_chi2Max, m_nMax}}, + }; + + Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity(); + rotation.col(0) = Acts::Vector3(0, 0, -1); + rotation.col(1) = Acts::Vector3(0, 1, 0); + rotation.col(2) = Acts::Vector3(1, 0, 0); + Acts::Translation3 trans(0., 0., 0.); + Acts::Transform3 trafo(rotation * trans); + initialSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(trafo); + + // Set the CombinatorialKalmanFilter options + CombinatorialKalmanFilterAlg::TrackFinderOptions options( + geoctx, magFieldContext, calibContext, + IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements), + Acts::MeasurementSelector(measurementSelectorCfg), + Acts::LoggerWrapper{*m_logger}, pOptions, &(*initialSurface)); + + m_numberOfTrackSeeds += initialParameters->size(); + + // Perform the track finding for all initial parameters + ATH_MSG_DEBUG("Invoke track finding with " << initialParameters->size() << " seeds."); + IndexSourceLinkContainer tmp; + for (const auto& sl : *sourceLinks) { + tmp.emplace_hint(tmp.end(), sl); + } + auto results = (*m_fit)(tmp, *initialParameters, options); + + // results contains a MultiTrajectory for each track seed with a trajectory of each branch of the CKF. + // To simplify the ambiguity solving a list of MultiTrajectories is created, each containing only a single track. + std::list<TrajectoryInfo> allTrajectories; + for (auto &result : results) { + if (not result.ok()) { + continue; + } + CKFResult ckfResult = result.value(); + for (size_t trackTip : ckfResult.lastMeasurementIndices) { + allTrajectories.emplace_back(TrajectoryInfo(FaserActsRecMultiTrajectory( + ckfResult.fittedStates, {trackTip}, {{trackTip, ckfResult.fittedParameters.at(trackTip)}}))); + } + } + + // the list of MultiTrajectories is sorted by the number of measurements using the chi2 value as a tie-breaker + allTrajectories.sort([](const TrajectoryInfo &left, const TrajectoryInfo &right) { + if (left.nMeasurements > right.nMeasurements) return true; + if (left.nMeasurements < right.nMeasurements) return false; + if (left.chi2 < right.chi2) return true; + else return false; + }); + + // select all tracks with at least 13 heats and with 6 or less shared hits, starting from the best track + // TODO use Gaudi parameters for the number of hits and shared hits + // TODO allow shared hits only in the first station? + std::vector<FaserActsRecMultiTrajectory> selectedTrajectories {}; + while (not allTrajectories.empty()) { + TrajectoryInfo selected = allTrajectories.front(); + selectedTrajectories.push_back(selected.trajectory); + allTrajectories.remove_if([&](const TrajectoryInfo &p) { + return (p.nMeasurements <= 12) || ((p.clusterSet & selected.clusterSet).count() > 6); + }); + } + + // create Trk::Tracks from the trajectories + for (const FaserActsRecMultiTrajectory &traj : selectedTrajectories) { + std::unique_ptr<Trk::Track> track = makeTrack(geoctx, traj); + if (track) { + outputTracks->push_back(std::move(track)); + } + } + + // run the performance writer + if (m_statesWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectoryStatesWriterTool->write(geoctx, trajectories, m_isMC)); + } + if (m_summaryWriter && !m_noDiagnostics) { + ATH_CHECK(m_trajectorySummaryWriterTool->write(geoctx, trajectories, m_isMC)); + } + if (m_performanceWriter && !m_noDiagnostics) { + ATH_CHECK(m_performanceWriterTool->write(geoctx, trajectories)); + } + ATH_CHECK(trackContainer.record(std::move(outputTracks))); + + return StatusCode::SUCCESS; +} + + +StatusCode CombinatorialKalmanFilterAlg::finalize() { + ATH_MSG_INFO("CombinatorialKalmanFilterAlg::finalize()"); + ATH_MSG_INFO(m_numberOfEvents << " events processed."); + ATH_MSG_INFO(m_numberOfTrackSeeds << " seeds."); + ATH_MSG_INFO(m_numberOfFittedTracks << " fitted tracks."); + ATH_MSG_INFO(m_numberOfSelectedTracks << " good fitted tracks."); + return StatusCode::SUCCESS; +} + + +Acts::MagneticFieldContext CombinatorialKalmanFilterAlg::getMagneticFieldContext(const EventContext& ctx) const { + SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; + if (!readHandle.isValid()) { + std::stringstream msg; + msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << "."; + throw std::runtime_error(msg.str()); + } + const FaserFieldCacheCondObj* fieldCondObj{*readHandle}; + return Acts::MagneticFieldContext(fieldCondObj); +} + +std::unique_ptr<Trk::Track> +CombinatorialKalmanFilterAlg::makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const { + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + std::unique_ptr<Trk::Track> newtrack = nullptr; + //Get the fit output object + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; + // Loop over all the output state to create track state + traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + // We need to determine the type of state + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + // State is a hole (no associated measurement), use predicted para meters + if (flag[Acts::TrackStateFlag::HoleFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), + state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + // The state was tagged as an outlier, use filtered parameters + else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + // The state is a measurement state, use smoothed parameters + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); + // const auto& psurface=actsParam.referenceSurface(); + Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); + // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); + // auto pos=actsParam.position(tgContext); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit(); + if (fitCluster->detectorElement() != nullptr) { + measState = new Tracker::FaserSCT_ClusterOnTrack{ + fitCluster, + Trk::LocalParameters{ + Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2} + }, + fitCluster->localCovariance(), + m_idHelper->wafer_hash(fitCluster->detectorElement()->identify()) + }; + } + } + double nDoF = state.calibratedSize(); + const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); + // If a state was succesfully created add it to the trajectory + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + // Create the track using the states + const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + // Trk::FitQuality* q = nullptr; + // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter + newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); + return newtrack; +} + +const Trk::TrackParameters* +CombinatorialKalmanFilterAlg::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const { + using namespace Acts::UnitLiterals; + std::optional<AmgSymMatrix(5)> cov = std::nullopt; + if (actsParameter.covariance()){ + AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5)); + // Convert the covariance matrix to GeV + for(int i=0; i < newcov.rows(); i++){ + newcov(i, 4) = newcov(i, 4)*1_MeV; + } + for(int i=0; i < newcov.cols(); i++){ + newcov(4, i) = newcov(4, i)*1_MeV; + } + cov = std::optional<AmgSymMatrix(5)>(newcov); + } + const Amg::Vector3D& pos=actsParameter.position(gctx); + double tphi=actsParameter.get<Acts::eBoundPhi>(); + double ttheta=actsParameter.get<Acts::eBoundTheta>(); + double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV; + double p = std::abs(1. / tqOverP); + Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta)); + const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov); + return curv; +} + +void CombinatorialKalmanFilterAlg::computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const { + // Compute shared hits from all the reconstructed tracks + // Compute nSharedhits and Update ckf results + // hit index -> list of multi traj indexes [traj, meas] + static_assert(Acts::SourceLinkConcept<IndexSourceLink>, + "Source link does not fulfill SourceLinkConcept"); + + std::vector<std::size_t> firstTrackOnTheHit( + sourceLinks->size(), std::numeric_limits<std::size_t>::max()); + std::vector<std::size_t> firstStateOnTheHit( + sourceLinks->size(), std::numeric_limits<std::size_t>::max()); + + for (unsigned int iresult = 0; iresult < results.size(); iresult++) { + if (not results.at(iresult).ok()) { + continue; + } + + auto& ckfResult = results.at(iresult).value(); + auto& measIndexes = ckfResult.lastMeasurementIndices; + + for (auto measIndex : measIndexes) { + ckfResult.fittedStates.visitBackwards(measIndex, [&](const auto& state) { + if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + return; + + std::size_t hitIndex = state.uncalibrated().index(); + + // Check if hit not already used + if (firstTrackOnTheHit.at(hitIndex) == + std::numeric_limits<std::size_t>::max()) { + firstTrackOnTheHit.at(hitIndex) = iresult; + firstStateOnTheHit.at(hitIndex) = state.index(); + return; + } + + // if already used, control if first track state has been marked + // as shared + int indexFirstTrack = firstTrackOnTheHit.at(hitIndex); + int indexFirstState = firstStateOnTheHit.at(hitIndex); + if (not results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) + results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + + // Decorate this track + results.at(iresult).value().fittedStates.getTrackState(state.index()).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + }); + } + } +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmbanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmbanFilterAlg.cxx deleted file mode 100644 index f5c547e61418ca7d5d0e4eb8b1cbdb9651e9316b..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmbanFilterAlg.cxx +++ /dev/null @@ -1,449 +0,0 @@ -#include "FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h" - -#include "StoreGate/ReadHandle.h" -#include "StoreGate/ReadCondHandleKey.h" -#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h" -#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" -#include "TrackerIdentifier/FaserSCT_ID.h" -#include "TrkPrepRawData/PrepRawData.h" -#include "TrackerPrepRawData/FaserSCT_Cluster.h" -#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" -#include "TrkRIO_OnTrack/RIO_OnTrack.h" -#include "TrkSurfaces/Surface.h" -#include "Identifier/Identifier.h" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/EventData/TrackParameters.hpp" -#include "FaserActsKalmanFilter/IndexSourceLink.h" -#include "FaserActsKalmanFilter/Measurement.h" -#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/MagneticField/MagneticFieldContext.hpp" - -using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; -using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, 2>; -using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; -std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; - - -CombinatorialKalmanFilterAlg::CombinatorialKalmanFilterAlg( - const std::string& name, ISvcLocator* pSvcLocator) - : AthReentrantAlgorithm(name, pSvcLocator) {} - - -StatusCode CombinatorialKalmanFilterAlg::initialize() { - ATH_MSG_INFO("CombinatorialKalmanFilterAlg::initialize"); - m_nevents=0; - m_ntracks=0; - m_nseeds=0; - m_nsp10=0; - m_nsp11=0; - m_ncom=0; - m_nsp1=0; - m_nsp2=0; - m_nsp3=0; - - ATH_CHECK(m_trackingGeometryTool.retrieve()); - ATH_CHECK(m_initialParameterTool.retrieve()); - ATH_CHECK(m_trajectoryWriterTool.retrieve()); - ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); - - ATH_CHECK( m_fieldCondObjInputKey.initialize() ); - - ATH_CHECK(m_trackCollection.initialize()); - - if (m_SpacePointContainerKey.key().empty()) { - ATH_MSG_FATAL("empty space point container key"); - return StatusCode::FAILURE; - } - ATH_CHECK(m_SpacePointContainerKey.initialize()); - ATH_CHECK(m_Sct_clcontainerKey.initialize() ); - - return StatusCode::SUCCESS; -} - - -StatusCode CombinatorialKalmanFilterAlg::execute(const EventContext& ctx) const { - ATH_MSG_DEBUG("CombinatorialKalmanFilterAlg::execute"); - m_nevents++; - - SG::ReadHandle<FaserSCT_SpacePointContainer> spcontainer(m_SpacePointContainerKey, ctx); - if (!spcontainer.isValid()) { - ATH_MSG_FATAL( "Could not find the data object "<< spcontainer.name()); - return StatusCode::FAILURE; - } - SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> sct_clcontainer( m_Sct_clcontainerKey, ctx ); -if (!sct_clcontainer.isValid()){ -msg(MSG:: FATAL) << "Could not find the data object "<< sct_clcontainer.name() << " !" << endmsg; -return StatusCode::RECOVERABLE; -} - - - //make TrackCollection - SG::WriteHandle<TrackCollection> trackContainer{m_trackCollection,ctx}; - std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>(); - - const std::shared_ptr<IdentifierMap> identifierMap - = m_trackingGeometryTool->getIdentifierMap(); - - /* - // Create measurement and source link containers - IndexSourceLinkContainer sourceLinks; - MeasurementContainer measurements; - std::vector<Identifier> sp_ids; - std::vector<Tracker::FaserSCT_Cluster> sps; - - std::vector<Acts::Vector3> pos1; - std::vector<Acts::Vector3> pos2; - std::vector<Acts::Vector3> pos3; - pos1.clear();pos2.clear();pos3.clear(); - Tracker::FaserSCT_ClusterContainer::const_iterator coll_it = sct_clcontainer->begin(); - Tracker::FaserSCT_ClusterContainer::const_iterator coll_itend = sct_clcontainer->end(); - for (; coll_it != coll_itend; ++coll_it) { - const Tracker::FaserSCT_ClusterCollection* spcollection = *coll_it; - Tracker::FaserSCT_ClusterCollection::const_iterator sp_it = spcollection->begin(); - Tracker::FaserSCT_ClusterCollection::const_iterator sp_end = spcollection->end(); - for (; sp_it != sp_end; ++sp_it) { - const Tracker::FaserSCT_Cluster* sp = *sp_it; - Identifier id = sp->detectorElement()->identify(); - //Identifier id = sp->associatedSurface().associatedDetectorElementIdentifier(); - Acts::GeometryIdentifier geoId = identifierMap->at(id); - IndexSourceLink sourceLink(geoId, measurements.size()); - sourceLinks.emplace_hint(sourceLinks.end(), std::move(sourceLink)); - ThisMeasurement meas(sourceLink, indices, sp->localPosition(), sp->localCovariance()); - //ThisMeasurement meas(sourceLink, indices, sp->localParameters(), sp->localCovariance()); - measurements.emplace_back(std::move(meas)); - - if(m_idHelper->station(sp->identify())==1)pos1.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); - if(m_idHelper->station(sp->identify())==2)pos2.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); - if(m_idHelper->station(sp->identify())==3)pos3.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); - sp_ids.push_back(sp->identify()); - sps.push_back(*sp); - } - } -*/ - // Create measurement and source link containers - IndexSourceLinkContainer sourceLinks; - MeasurementContainer measurements; - std::vector<Identifier> sp_ids; - std::vector<Tracker::FaserSCT_SpacePoint> sps; - -// std::vector<Acts::Vector3> pos1; -// std::vector<Acts::Vector3> pos2; -// std::vector<Acts::Vector3> pos3; -// pos1.clear();pos2.clear();pos3.clear(); - std::vector<int> layer1; - layer1.clear(); - FaserSCT_SpacePointContainer::const_iterator coll_it = spcontainer->begin(); - FaserSCT_SpacePointContainer::const_iterator coll_itend = spcontainer->end(); - for (; coll_it != coll_itend; ++coll_it) { - const FaserSCT_SpacePointCollection* spcollection = *coll_it; - FaserSCT_SpacePointCollection::const_iterator sp_it = spcollection->begin(); - FaserSCT_SpacePointCollection::const_iterator sp_end = spcollection->end(); - for (; sp_it != sp_end; ++sp_it) { - const Tracker::FaserSCT_SpacePoint* sp = *sp_it; - Identifier id = sp->associatedSurface().associatedDetectorElementIdentifier(); - Acts::GeometryIdentifier geoId = identifierMap->at(id); - IndexSourceLink sourceLink(geoId, measurements.size()); - sourceLinks.emplace_hint(sourceLinks.end(), std::move(sourceLink)); - ThisMeasurement meas(sourceLink, indices, sp->localParameters(), sp->localCovariance()); - measurements.emplace_back(std::move(meas)); - -// if(m_idHelper->station(sp->clusterList().first->identify())==1) { -// pos1.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); -// layer1.push_back(m_idHelper->layer(sp->clusterList().first->identify())); -// } -// if(m_idHelper->station(sp->clusterList().first->identify())==2)pos2.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); -// if(m_idHelper->station(sp->clusterList().first->identify())==3)pos3.push_back(Acts::Vector3(sp->globalPosition().x(),sp->globalPosition().y(),sp->globalPosition().z())); - sp_ids.push_back(sp->clusterList().first->identify()); - sps.push_back(*sp); - } - } - - // Get initial parameters - // FIXME: Get initial parameters from clusterFitter or SeedFinder not MC! - std::vector<Acts::CurvilinearTrackParameters> initialParameters; - auto initialParameter = m_initialParameterTool->getInitialParameters(sp_ids); - initialParameters.push_back(initialParameter); -// if(pos1.size()<1||pos2.size()<1||pos3.size()<1) return StatusCode::SUCCESS; -// std::vector<Acts::CurvilinearTrackParameters> initialParameters; -// initialParameters.clear(); -// Acts::Vector3 pos1a(0,0,0); -// Acts::Vector3 pos2a(0,0,0); -// Acts::Vector3 pos3a(0,0,0); -// for(long unsigned int i1=0;i1<pos1.size();i1++)pos1a+=pos1[i1]; -// for(long unsigned int i1=0;i1<pos2.size();i1++)pos2a+=pos2[i1]; -// for(long unsigned int i1=0;i1<pos3.size();i1++)pos3a+=pos3[i1]; -// pos1a/=pos1.size(); -// pos2a/=pos2.size(); -// pos3a/=pos3.size(); -// m_nsp1+=pos1.size(); -// m_nsp2+=pos2.size(); -// m_nsp3+=pos3.size(); -// for(int i1=0;i1<pos1.size();i1++){ -// for(int i2=0;i2<pos2.size();i2++){ -// for(int i3=0;i3<pos3.size();i3++){ -// auto initialParameter=m_initialParameterTool->getInitialParameters(pos1[i1],pos2[i2],pos3[i3]); -// initialParameters.push_back(initialParameter); -// } -// } -// } - /* - if(pos1.size()>0&&pos2.size()>0&&pos3.size()>0) { - auto initialParameter=m_initialParameterTool->getInitialParameters(pos1a,pos2a,pos3a); - if(initialParameter.momentum().z()>0){ - m_nseeds++; - initialParameters.push_back(initialParameter); - */ - // for one stations -// if(pos1.size()>2) { -// std::vector<Acts::Vector3> pos10; -// std::vector<Acts::Vector3> pos11; -// std::vector<Acts::Vector3> pos12; -// pos10.clear();pos11.clear();pos12.clear(); -// for(std::size_t ipos=0;ipos<pos1.size();ipos++){ -// if(layer1[ipos]==0)pos10.push_back(pos1[ipos]); -// if(layer1[ipos]==1)pos11.push_back(pos1[ipos]); -// if(layer1[ipos]==2)pos12.push_back(pos1[ipos]); -// } -// if(pos10.size()>0&&pos11.size()>0&&pos12.size()>0){ -// auto initialParameter=m_initialParameterTool->getInitialParameters_1station(pos10,pos11,pos12); -// initialParameters.insert(initialParameters.end(),initialParameter.begin(),initialParameter.end()); - /* - //for two stations - if(pos1.size()>1&&pos2.size()>0) { - Acts::Vector3 pos10a(0,0,0); - Acts::Vector3 pos11a(0,0,0); - int n10a=0,n11a=0; - for(int ipos=0;ipos<pos1.size();ipos++){ - if(layer1[ipos]==0){pos10a+=pos1[ipos];n10a++;} - if(layer1[ipos]>0){pos11a+=pos1[ipos];n11a++;} - } - m_nsp10+=n10a; - m_nsp11+=n11a; - if(n10a>0&&n11a>0){ - m_ncom++; - pos10a/=n10a; - pos11a/=n11a; - Acts::Vector3 dir1=(pos11a-pos10a).normalized(); - auto initialParameter=m_initialParameterTool->getInitialParameters_2stations(pos1a,pos2a,dir1); - if(initialParameter.momentum().z()>0){ - m_nseeds++; - initialParameters.push_back(initialParameter); - } - */ - - // Prepare the output data with MultiTrajectory - TrajectoriesContainer trajectories; - trajectories.reserve(initialParameters.size()); - - // Construct a perigee surface as the target surface - auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>( - Acts::Vector3{0., 0., 0.}); - - Acts::PropagatorPlainOptions pOptions; - pOptions.maxSteps = 10000; - /* - Acts::DirectNavigator navigator; - std::unique_ptr<ActsExtrapolationDetail::VariantPropagator> varProp; - Acts::Vector3 constantFieldVector = Acts::Vector3(0,0,0.55); - auto bField = std::make_shared<Acts::ConstantBField>(constantFieldVector); - auto stepper = Acts::EigenStepper<>(std::move(bField)); - auto propagator = Acts::Propagator<decltype(stepper), Acts::DirectNavigator>(std::move(stepper), - std::move(navigator)); - varProp = std::make_unique<VariantPropagator>(propagator); - */ - - Acts::GeometryContext geoContext = m_trackingGeometryTool->getNominalGeometryContext().context(); - Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx); - Acts::CalibrationContext calibContext; - double chi2Max = 15; - size_t nMax = 10; - Acts::MeasurementSelector::Config measurementSelectorCfg = { - {Acts::GeometryIdentifier(), {chi2Max, nMax}}, - }; - std::unique_ptr<const Acts::Logger> logger - = Acts::getDefaultLogger("CombinatorialKalmanFilter", Acts::Logging::INFO); - - // Set the CombinatorialKalmanFilter options - CombinatorialKalmanFilterAlg::TrackFinderOptions options( - geoContext, magFieldContext, calibContext, - IndexSourceLinkAccessor(), MeasurementCalibrator(measurements), - Acts::MeasurementSelector(measurementSelectorCfg), - //Acts::LoggerWrapper{*logger}, varProp, &(*pSurface)); - Acts::LoggerWrapper{*logger}, pOptions, &(*pSurface)); - - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry - = m_trackingGeometryTool->trackingGeometry(); - - // Get track finder function - auto trackFinderFunction = makeTrackFinderFunction(trackingGeometry); - - // Perform the track finding for all initial parameters - ATH_MSG_DEBUG("Invoke track finding with " << initialParameters.size() - << " seeds."); - auto results = trackFinderFunction(sourceLinks, initialParameters, options); - // Loop over the track finding results for all initial parameters - for (std::size_t iseed = 0; iseed < initialParameters.size(); ++iseed) { - // The result for this seed - auto& result = results[iseed]; - if (result.ok()) { - // Get the track finding output object - const auto& trackFindingOutput = result.value(); - std::unique_ptr<Trk::Track> track = makeTrack(geoContext, result,sps); - m_ntracks++; - if(track!=nullptr) { - outputTracks->push_back(std::move(track)); - } else { - ATH_MSG_DEBUG("No Trk::Track is created" ); - } - // Create a Trajectories result struct - trajectories.emplace_back(std::move(trackFindingOutput.fittedStates), - std::move(trackFindingOutput.lastMeasurementIndices), - std::move(trackFindingOutput.fittedParameters)); - } else { - ATH_MSG_WARNING("Track finding failed for seed " << iseed << " with error" - << result.error()); - // Track finding failed. Add an empty result so the output container has - // the same number of entries as the input. - trajectories.push_back(FaserActsRecMultiTrajectory()); - } - } - - m_trajectoryWriterTool->writeout(trajectories, geoContext,initialParameters); -// } -// } - - if(outputTracks->size()>0) { - ATH_MSG_DEBUG("Found " << outputTracks->size() << " tracks"); - } else { - ATH_MSG_WARNING("No track is found"); - } - - ATH_CHECK(trackContainer.record(std::move(outputTracks))); - return StatusCode::SUCCESS; -} - - -StatusCode CombinatorialKalmanFilterAlg::finalize() { - ATH_MSG_INFO("CombinatorialKalmanFilterAlg::finalize"); - ATH_MSG_INFO("Summary info"); - ATH_MSG_INFO("In total, "<<m_nevents<<" events, and "<<m_nseeds<<" seeds, and "<<m_ntracks<<" tracks"); - ATH_MSG_INFO("In total, "<<m_nsp1<<" , "<<m_nsp2<<" , "<<m_nsp3<<" ,"<<m_nsp10<<" , "<<m_nsp11<<" , "<<m_ncom); - - return StatusCode::SUCCESS; -} - - -Acts::MagneticFieldContext CombinatorialKalmanFilterAlg::getMagneticFieldContext(const EventContext& ctx) const { - SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; - if (!readHandle.isValid()) { - std::stringstream msg; - msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << "."; - throw std::runtime_error(msg.str()); - } - const FaserFieldCacheCondObj* fieldCondObj{*readHandle}; - - return Acts::MagneticFieldContext(fieldCondObj); -} - -std::unique_ptr<Trk::Track> -CombinatorialKalmanFilterAlg::makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult, std::vector<Tracker::FaserSCT_SpacePoint> sps) const { - std::unique_ptr<Trk::Track> newtrack = nullptr; - //Get the fit output object - const auto& fitOutput = fitResult.value(); - if (fitOutput.fittedParameters.size()>0) { - DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; - std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; - ATH_MSG_DEBUG("makeTrack : trackTip "<<fitOutput.lastMeasurementIndices.size()); - // Loop over all the output state to create track state - fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndices.front(), [&](const auto &state) { - auto flag = state.typeFlags(); - if (state.referenceSurface().associatedDetectorElement() != nullptr) { - // const auto* actsElement = dynamic_cast<const FaserActsDetectorElement*>(state.referenceSurface().associatedDetectorElement()); - // if (actsElement != nullptr ){ - // We need to determine the type of state - std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; - const Trk::TrackParameters *parm; - - // State is a hole (no associated measurement), use predicted para meters - if (flag[Acts::TrackStateFlag::HoleFlag] == true) { - const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), - state.predicted(), - state.predictedCovariance()); - parm = ConvertActsTrackParameterToATLAS(actsParam, tgContext); - // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); - typePattern.set(Trk::TrackStateOnSurface::Hole); - } - // The state was tagged as an outlier, use filtered parameters - else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { - const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), - state.filtered(), state.filteredCovariance()); - parm = ConvertActsTrackParameterToATLAS(actsParam, tgContext); - typePattern.set(Trk::TrackStateOnSurface::Outlier); - } - // The state is a measurement state, use smoothed parameters - else { - const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), - state.smoothed(), state.smoothedCovariance()); - actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); - // const auto& psurface=actsParam.referenceSurface(); - Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); - // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); - // auto pos=actsParam.position(tgContext); - parm = ConvertActsTrackParameterToATLAS(actsParam, tgContext); - typePattern.set(Trk::TrackStateOnSurface::Measurement); - } - Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; - if (state.hasUncalibrated()) { - auto sp= sps.at(state.uncalibrated().index()); - //const Tracker::FaserSCT_Cluster* fitCluster=&sp; - const Tracker::FaserSCT_Cluster* fitCluster=sp.clusterList().first; - if(fitCluster !=nullptr) { - measState = new Tracker::FaserSCT_ClusterOnTrack{ fitCluster, Trk::LocalParameters { Trk::DefinedParameter { fitCluster->localPosition()[0], Trk::loc1 }, Trk::DefinedParameter { fitCluster->localPosition()[1], Trk::loc2 } }, fitCluster->localCovariance(), m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())}; - } - } - double nDoF = state.calibratedSize(); - const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); - const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); - // If a state was succesfully created add it to the trajectory - if (perState) { - finalTrajectory->insert(finalTrajectory->begin(), perState); - } - } - return; - }); - - // Create the track using the states - const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); - // Trk::FitQuality* q = nullptr; - // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter - newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); - } - return newtrack; -} - -const Trk::TrackParameters* -CombinatorialKalmanFilterAlg ::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const { - using namespace Acts::UnitLiterals; - std::optional<AmgSymMatrix(5)> cov = std::nullopt; - if (actsParameter.covariance()){ - AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5)); - // Convert the covariance matrix to GeV - for(int i=0; i < newcov.rows(); i++){ - newcov(i, 4) = newcov(i, 4)*1_MeV; - } - for(int i=0; i < newcov.cols(); i++){ - newcov(4, i) = newcov(4, i)*1_MeV; - } - cov = std::optional<AmgSymMatrix(5)>(newcov); - } - const Amg::Vector3D& pos=actsParameter.position(gctx); - double tphi=actsParameter.get<Acts::eBoundPhi>(); - double ttheta=actsParameter.get<Acts::eBoundTheta>(); - double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV; - double p = std::abs(1. / tqOverP); - Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta)); - const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov); - return curv; -} - diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..514fe5407c1585e1a0884a60f2dc5d039ebe92ae --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx @@ -0,0 +1,40 @@ +#include "FaserActsKalmanFilter/EffPlotTool.h" +#include "Acts/Utilities/Helpers.hpp" + +void EffPlotTool::book(EffPlotTool::EffPlotCache &effPlotCache) const { + PlotHelpers::Binning bPhi = m_varBinning.at("Phi"); + PlotHelpers::Binning bEta = m_varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_varBinning.at("Pt"); + // efficiency vs pT + effPlotCache.trackEff_vs_pT = PlotHelpers::bookEff( + "trackeff_vs_pT", "Tracking efficiency;Truth pT [GeV/c];Efficiency", bPt); + // efficiency vs eta + effPlotCache.trackEff_vs_eta = PlotHelpers::bookEff( + "trackeff_vs_eta", "Tracking efficiency;Truth #eta;Efficiency", bEta); + // efficiency vs phi + effPlotCache.trackEff_vs_phi = PlotHelpers::bookEff( + "trackeff_vs_phi", "Tracking efficiency;Truth #phi;Efficiency", bPhi); +} + +void EffPlotTool::fill(EffPlotTool::EffPlotCache &effPlotCache, + const HepMC::GenParticle* truthParticle, bool status) const { + const auto t_phi = truthParticle->momentum().phi(); + const auto t_eta = truthParticle->momentum().eta(); + const auto t_pT = truthParticle->momentum().perp() * m_MeV2GeV; + + PlotHelpers::fillEff(effPlotCache.trackEff_vs_pT, t_pT, status); + PlotHelpers::fillEff(effPlotCache.trackEff_vs_eta, t_eta, status); + PlotHelpers::fillEff(effPlotCache.trackEff_vs_phi, t_phi, status); +} + +void EffPlotTool::write(const EffPlotTool::EffPlotCache &effPlotCache) const { + effPlotCache.trackEff_vs_pT->Write(); + effPlotCache.trackEff_vs_eta->Write(); + effPlotCache.trackEff_vs_phi->Write(); +} + +void EffPlotTool::clear(EffPlotTool::EffPlotCache &effPlotCache) const { + delete effPlotCache.trackEff_vs_pT; + delete effPlotCache.trackEff_vs_eta; + delete effPlotCache.trackEff_vs_phi; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx index c9427a0f8f9940f6d181e4f4775bcb9a8e2ae527..673524123467db8461bb25da2157bfa00eb6755a 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx @@ -7,7 +7,7 @@ // ATHENA #include "GaudiKernel/EventContext.h" #include "GaudiKernel/ISvcLocator.h" -#include "GaudiKernel/PhysicalConstants.h" +//#include "GaudiKernel/PhysicalConstants.h" #include "TrackerReadoutGeometry/SCT_DetectorManager.h" #include "TrackerReadoutGeometry/SiDetectorDesign.h" #include "TrackerReadoutGeometry/SiLocalPosition.h" @@ -18,14 +18,8 @@ #include "FaserDetDescr/FaserDetectorID.h" // ACTS -#include "Acts/TrackFitting/GainMatrixSmoother.hpp" -#include "Acts/TrackFitting/GainMatrixUpdater.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/MagneticField/ConstantBField.hpp" -#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -#include "Acts/MagneticField/SharedBField.hpp" #include "Acts/MagneticField/MagneticFieldContext.hpp" -#include "Acts/Propagator/EigenStepper.hpp" #include "Acts/Propagator/Navigator.hpp" #include "Acts/Propagator/Propagator.hpp" #include "Acts/Surfaces/Surface.hpp" @@ -43,7 +37,6 @@ #include "Acts/EventData/TrackParameters.hpp" #include "Acts/EventData/MultiTrajectoryHelpers.hpp" #include "Acts/EventData/Measurement.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" // PACKAGE @@ -52,6 +45,9 @@ #include "FaserActsGeometry/FaserActsGeometryContext.h" #include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h" #include "FaserActsGeometry/FaserActsDetectorElement.h" +#include "FaserActsKalmanFilter/IdentifierLink.h" + +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" //ROOT #include <TTree.h> @@ -65,7 +61,6 @@ #include <string> #include <fstream> #include <cmath> -#include <random> using TrajectoryContainer = std::vector<FaserActsRecMultiTrajectory>; @@ -75,476 +70,99 @@ using Acts::VectorHelpers::perp; using Acts::VectorHelpers::phi; using Acts::VectorHelpers::theta; using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, 2>; -using Updater = Acts::GainMatrixUpdater; -using Smoother = Acts::GainMatrixSmoother; -using Stepper = Acts::EigenStepper<FASERMagneticFieldWrapper>; -using Propagator = Acts::Propagator<Stepper, Acts::DirectNavigator>; -using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>; - -namespace ActsExtrapolationDetail { - using VariantPropagatorBase = boost::variant< - Acts::Propagator<Acts::EigenStepper<>, Acts::DirectNavigator>, - Acts::Propagator<Acts::EigenStepper<>, Acts::DirectNavigator> - >; +using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; - class VariantPropagator : public VariantPropagatorBase - { - public: - using VariantPropagatorBase::VariantPropagatorBase; - }; +FaserActsKalmanFilterAlg::FaserActsKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator) {} -} - -using ActsExtrapolationDetail::VariantPropagator; - -FaserActsKalmanFilterAlg::FaserActsKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator) - : AthAlgorithm(name, pSvcLocator) , m_thistSvc("THistSvc", name) -{ -} - -// FixMe the Identifier to GeometryIdentfier mapping should not be hardcoded. -int FaserActsKalmanFilterAlg::getGeometryIdentifierVolume(int station) -{ - switch(station) - { - case 1: - return 2; - case 2: - return 3; - case 3: - return 4; - default: - ATH_MSG_ERROR("Received unexpected station. Check detector geometry"); - return 0; - } -} - -int FaserActsKalmanFilterAlg::getGeometryIdentifierLayer(int layer) -{ - switch(layer) - { - case 0: - return 2; - case 1: - return 4; - case 2: - return 6; - default: - ATH_MSG_ERROR("Received unexpected layer. Check detector geometry"); - return 0; - } -} - -int FaserActsKalmanFilterAlg::getGeometryIdentifierSensitive(int row, int column) -{ - if (row == 0 && column == -1) - return 2; - else if (row == 0 && column == 1) - return 4; - else if (row == 1 && column == -1) - return 5; - else if (row == 1 && column == 1) - return 7; - else if (row == 2 && column == -1) - return 10; - else if (row == 2 && column == 1) - return 12; - else if (row == 3 && column == -1) - return 13; - else if (row ==3 && column == 1) - return 15; - else - { - ATH_MSG_ERROR("Received unexpected row or column. Check detector geometry"); - return 0; - } -} - -Acts::GeometryIdentifier FaserActsKalmanFilterAlg::getGeometryIdentifier(const Identifier id) -{ - Acts::GeometryIdentifier geoId = Acts::GeometryIdentifier(); - geoId.setVolume(getGeometryIdentifierVolume(m_idHelper->station(id))); - geoId.setLayer(getGeometryIdentifierLayer(m_idHelper->layer(id))); - geoId.setSensitive(getGeometryIdentifierSensitive(m_idHelper->phi_module(id), m_idHelper->eta_module(id))); - return geoId; -} StatusCode FaserActsKalmanFilterAlg::initialize() { - - ATH_MSG_DEBUG(name() << "::" << __FUNCTION__); - - ATH_MSG_INFO("Initializing ACTS kalman filter"); - - ATH_CHECK( m_fieldCondObjInputKey.initialize() ); - - ATH_CHECK( m_extrapolationTool.retrieve() ); - - if ( m_seed_spcollectionKey.key().empty()){ - ATH_MSG_FATAL( "SCTs selected and no name set for SCT clusters"); - return StatusCode::FAILURE; + ATH_CHECK(m_fieldCondObjInputKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackFinderTool.retrieve()); + ATH_CHECK(m_trajectoryWriterTool.retrieve()); + ATH_CHECK(m_trajectoryStatesWriterTool.retrieve()); +// ATH_CHECK(m_protoTrackWriterTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + m_fit = makeTrackFitterFunction(m_trackingGeometryTool->trackingGeometry()); + if (m_actsLogging == "VERBOSE") { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE); + } else if (m_actsLogging == "DEBUG") { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG); + } else { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO); } - - ATH_CHECK( m_seed_spcollectionKey.initialize() ); - - ATH_CHECK( m_mcEventKey.initialize() ); - - ATH_CHECK( m_sctMap.initialize()); - - ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); - - ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); - - ATH_CHECK(m_thistSvc.retrieve()); - - m_trackTree = new TTree("tracks", ""); - - ATH_CHECK(m_thistSvc->regTree("/KalmanTracks/tracks", m_trackTree)); - - if (m_trackTree) { - initializeTree(); - } - else { - ATH_MSG_ERROR("No tree found!"); - } - - ATH_MSG_INFO("ACTS kalman filter successfully initialized"); return StatusCode::SUCCESS; } -//StatusCode FaserActsKalmanFilterAlg::execute(const EventContext& ctx) const -StatusCode FaserActsKalmanFilterAlg::execute() -{ - ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__); +//StatusCode FaserActsKalmanFilterAlg::execute(const EventContext& ctx) const { +StatusCode FaserActsKalmanFilterAlg::execute() { + const EventContext& ctx = Gaudi::Hive::currentContext(); - m_eventNr++; + //make TrackCollection + ATH_CHECK(m_trackCollection.initialize()); + SG::WriteHandle<TrackCollection> trackContainer{m_trackCollection,ctx}; + std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>(); - //SG::ReadHandle<SpacePointForSeedCollection> seed_spcollection( m_seed_spcollectionKey, ctx ); - SG::ReadHandle<SpacePointForSeedCollection> seed_spcollection( m_seed_spcollectionKey ); - if (!seed_spcollection.isValid()){ - msg(MSG:: FATAL) << "Could not find the data object "<< seed_spcollection.name() << " !" << endmsg; - return StatusCode::RECOVERABLE; - } + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry + = m_trackingGeometryTool->trackingGeometry(); - const FaserActsGeometryContext& gctx - = m_extrapolationTool->trackingGeometryTool()->getNominalGeometryContext(); + const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext(); auto geoctx = gctx.context(); - Acts::MagneticFieldContext magctx = getMagneticFieldContext(); + Acts::MagneticFieldContext magctx = getMagneticFieldContext(ctx); Acts::CalibrationContext calctx; - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry - = m_extrapolationTool->trackingGeometryTool()->trackingGeometry(); - - std::shared_ptr<const Acts::Surface> pSurface; - - // Get SiDetectorElements - const TrackerDD::SiDetectorElementCollection* elCollection{m_detManager->getDetectorElementCollection()}; - if (elCollection == nullptr) { - ATH_MSG_FATAL("Null pointer is returned by getDetectorElementCollection()"); - return StatusCode::FAILURE; - } - + CHECK(m_trackFinderTool->run()); + std::shared_ptr<const Acts::Surface> initialSurface = + m_trackFinderTool->initialSurface(); + std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters = + m_trackFinderTool->initialTrackParameters(); + std::shared_ptr<std::vector<std::vector<IndexSourceLink>>> sourceLinks = + m_trackFinderTool->sourceLinks(); + std::shared_ptr<std::vector<IdentifierLink>> idLinks = m_trackFinderTool->idLinks(); + std::shared_ptr<std::vector<std::vector<Measurement>>> measurements = + m_trackFinderTool->measurements(); + std::shared_ptr<std::vector<std::vector<Tracker::FaserSCT_SpacePoint>>> spacePoints = + m_trackFinderTool->spacePoints(); + std::shared_ptr<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>> clusters = + m_trackFinderTool->clusters(); - static const TrackerDD::SCT_DetectorManager *s_sct; - if(detStore()->retrieve(s_sct,"SCT").isFailure()) s_sct = 0; - int N_1_0=0, N_1_1=0, N_1_2=0, N_2_0=0, N_2_1=0, N_2_2=0; - Acts::Vector3 pos1_0(0., 0., 0.); - Acts::Vector3 pos1_1(0., 0., 0.); - Acts::Vector3 pos1_2(0., 0., 0.); - Acts::Vector3 pos2_0(0., 0., 0.); - Acts::Vector3 pos2_1(0., 0., 0.); - Acts::Vector3 pos2_2(0., 0., 0.); - HepMC::FourVector truthmom; - HepMC::FourVector pv; +// ATH_CHECK(m_protoTrackWriterTool->write(initialTrackParameters, measurements, geoctx)); - // create source links and measurements - std::vector<IndexSourceLink> sourceLinks; - std::vector<const Acts::Surface*> surfSequence; - MeasurementContainer measurements; + int n_trackSeeds = initialTrackParameters->size(); - SpacePointForSeedCollection::const_iterator it = seed_spcollection->begin(); - SpacePointForSeedCollection::const_iterator itend = seed_spcollection->end(); - for (; it != itend; ++it){ - const Tracker::FaserSCT_SpacePoint *sp = (&(**it))->SpacePoint(); + TrajectoryContainer trajectories; + trajectories.reserve(1); - const Identifier id = sp->clusterList().first->identify(); - const TrackerDD::SiDetectorElement* siSpElement = m_detManager->getDetectorElement(id); - auto spElement = static_cast<const FaserActsDetectorElement>(siSpElement); - // Acts::GeometryIdentifier geoId = getGeometryIdentifier(id); - Acts::GeometryIdentifier geoId; + for (int i = 0; i < n_trackSeeds; ++i) { - const Acts::TrackingVolume* tVolume = trackingGeometry->highestTrackingVolume(); - if (tVolume->confinedVolumes()) { - for (auto volume : tVolume->confinedVolumes()->arrayObjects()) { - if (volume->confinedLayers()) { - for (const auto& layer : volume->confinedLayers()->arrayObjects()) { - if (layer->layerType() == Acts::navigation) continue; - for (auto surface : layer->surfaceArray()->surfaces()) { - if (surface) { - const Acts::DetectorElementBase *detElement = surface->associatedDetectorElement(); - const auto *faserDetElement = dynamic_cast<const FaserActsDetectorElement*>(detElement); - auto* tmp = const_cast<FaserActsDetectorElement*>(faserDetElement); - if (*tmp == spElement) { - geoId = surface->geometryId(); - } - } - } - } - } - } - } - - const Acts::Surface* surfacePtr = trackingGeometry->findSurface(geoId); - surfSequence.push_back(surfacePtr); - if (not surfacePtr) { - ATH_MSG_ERROR("Could not find surface " << geoId); - return StatusCode::FAILURE; - } - - Index spIdx = measurements.size(); - IndexSourceLink sourceLink(geoId, spIdx); - - - auto par = sp->localParameters(); - auto cov = sp->localCovariance(); - std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; - ThisMeasurement meas(sourceLink, indices, par, cov); - sourceLinks.push_back(std::move(sourceLink)); - measurements.emplace_back(std::move(meas)); - - - // Get the truth position and momentum - SG::ReadHandle<McEventCollection> h_mcEvents(m_mcEventKey); - SG::ReadHandle<TrackerSimDataCollection> h_collectionMap(m_sctMap); - const auto& simdata = h_collectionMap->find(id)->second; - const auto& deposits = simdata.getdeposits(); - for( const auto& depositPair : deposits) - { - if (depositPair.first->pdg_id() == -13) { - pv = depositPair.first->production_vertex()->position(); - truthmom = depositPair.first->momentum(); - } - } - - // Get the measurements - Amg::Vector3D gloPos=sp->globalPosition(); - int station = m_idHelper->station(id); - int plane = m_idHelper->layer(id); - if (station==1 && plane==0) { - N_1_0++; - pos1_0 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - - // Construct a plane surface as the target surface - const TrackerDD::SiDetectorDesign &design = siSpElement->design(); - double hlX = design.width()/2. * 1_mm; - double hlY = design.length()/2. * 1_mm; - auto rectangleBounds = std::make_shared<const Acts::RectangleBounds>(hlX, hlY); - Amg::Transform3D g2l = siSpElement->getMaterialGeom()->getDefAbsoluteTransform() - * Amg::CLHEPTransformToEigen(siSpElement->recoToHitTransform()); - pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( g2l, rectangleBounds ); - } - if (station==1 && plane==1) { - N_1_1++; - pos1_1 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - } - if (station==1 && plane==2) { - N_1_2++; - pos1_2 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - } - if (station==2 && plane==0) { - N_2_0++; - pos2_0 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - } - if (station==2 && plane==1) { - N_2_1++; - pos2_1 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - } - if (station==2 && plane==2) { - N_2_2++; - pos2_2 = Acts::Vector3(gloPos.x(), gloPos.y(), gloPos.z()); - } - } - - for (auto sl : sourceLinks) - { - std::cout << "??volume=" << sl.geometryId().volume() << std::endl; - std::cout << "??layer=" << sl.geometryId().layer() << std::endl; - std::cout << "??sensitive=" << sl.geometryId().sensitive() << std::endl; - } - - // Calculate the initial track parameters - if ( (N_1_0==1) && (N_1_1==1) && (N_1_2==1) && (N_2_0==1) && (N_2_1==1) && (N_2_2==1)) { - std::cout<<"!!!!!!!!!!! pos1_0 = ("<<pos1_0.x()<<", "<<pos1_0.y()<<", "<<pos1_0.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos1_1 = ("<<pos1_1.x()<<", "<<pos1_1.y()<<", "<<pos1_1.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos1_2 = ("<<pos1_2.x()<<", "<<pos1_2.y()<<", "<<pos1_2.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_0 = ("<<pos2_0.x()<<", "<<pos2_0.y()<<", "<<pos2_0.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_1 = ("<<pos2_1.x()<<", "<<pos2_1.y()<<", "<<pos2_1.z()<<") "<<std::endl; - std::cout<<"!!!!!!!!!!! pos2_2 = ("<<pos2_2.x()<<", "<<pos2_2.y()<<", "<<pos2_2.z()<<") "<<std::endl; - //@FIXME: change the hard codes in future - double charge = 1; - double B = 0.55; - //const Acts::Vector3 pos = pos1_0; - const Acts::Vector3 pos(pos1_0.x(), pos1_0.y(), pos1_0.z()-1); - Acts::Vector3 d1 = pos1_2 - pos1_0; - Acts::Vector3 d2 = pos2_2 - pos2_0; - // the direction of momentum in the first station - Acts::Vector3 direct1 = d1.normalized(); - // the direction of momentum in the second station - Acts::Vector3 direct2 = d2.normalized(); - // the vector pointing from the center of circle to the particle at layer 2 in Y-Z plane - double R1_z = charge * direct1.y() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - // double R1_y = -charge * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - // the vector pointing from the center of circle to the particle at layer 3 in Y-Z plane - double R2_z = charge * direct2.y() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z()); - // double R2_y = -charge * direct2.z() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z()); - // the norm of radius - double R = (pos2_0.z() - pos1_2.z()) / (R2_z - R1_z); - // the norm of momentum in Y-Z plane - double p_yz = 0.3*B*R / 1000.0; // R(mm), p(GeV), B(T) - double p_z = p_yz * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - double p_y = p_yz * direct1.y() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z()); - double p_x = direct1.x() * p_z / direct1.z(); - // total momentum at the layer 0 - const Acts::Vector3 mom(p_x, p_y, p_z); - double p = mom.norm(); - std::cout<<"!!!!!!!!!!! InitTrack momentum on layer 0: ( "<<mom.x()*1000<<", "<<mom.y()*1000<<", "<<mom.z()*1000<<", "<<p*1000<<") "<<std::endl; - // build the track covariance matrix using the smearing sigmas - double sigmaU = 200_um; - double sigmaV = 200_um; - double sigmaPhi = 1_degree; - double sigmaTheta = 1_degree; - double sigmaQOverP = 0.01*p / (p*p); - double sigmaT0 = 1_ns; - Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = sigmaU * sigmaU; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = sigmaV * sigmaV; - cov(Acts::eBoundPhi, Acts::eBoundPhi) = sigmaPhi * sigmaPhi; - cov(Acts::eBoundTheta, Acts::eBoundTheta) = sigmaTheta * sigmaTheta; - cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = sigmaQOverP * sigmaQOverP; - cov(Acts::eBoundTime, Acts::eBoundTime) = sigmaT0 * sigmaT0; - double time =0; - //Acts::CurvilinearTrackParameters InitTrackParam(std::make_optional(std::move(cov)), pos, mom, charge, time); // calculated initial parameters - - // Smearing truth parameters as initial parameters - Acts::Vector3 pPos(pv.x(), pv.y(), pv.z()); - Acts::Vector3 pMom(truthmom.x()/1000., truthmom.y()/1000., truthmom.z()/1000.); - std::random_device rd; - std::default_random_engine rng {rd()}; - std::normal_distribution<> norm; // mu: 0 sigma: 1 - Acts::Vector3 deltaPos(sigmaU*norm(rng), sigmaU*norm(rng), sigmaU*norm(rng)); - auto theta = Acts::VectorHelpers::theta(pMom.normalized()); - auto phi = Acts::VectorHelpers::phi(pMom.normalized()); - auto angles = Acts::detail::normalizePhiTheta(phi + sigmaPhi*norm(rng), theta + sigmaTheta*norm(rng)); - Acts::Vector3 dir(std::sin(angles.second) * std::cos(angles.first), - std::sin(angles.second) * std::sin(angles.first), - std::cos(angles.second)); - const Acts::Vector3 deltaMom = ( pMom.norm()*(1 + 0.01*norm(rng)) ) * dir - pMom; - std::cout << "deltaPos: " << deltaPos << std::endl; - std::cout << "deltaMom: " << deltaMom << std::endl; - const Acts::Vector4 posTime ((pPos+deltaPos).x(), (pPos+deltaPos).y(), (pPos+deltaPos).z(), time); - const Acts::Vector3 momentum = pMom+deltaMom; - const Acts::Vector3 momentum_dir = momentum.normalized(); - double momentum_abs = momentum.norm(); - Acts::CurvilinearTrackParameters InitTrackParam(posTime, momentum_dir, momentum_abs, charge, std::make_optional(std::move(cov))); - - // the surface which the production point is bound to - Acts::Vector3 center(0, 0, pPos.z()); - Acts::Vector3 normal(0, 0, 1); - std::shared_ptr<const Acts::Surface> initSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(center, normal); - // extrapolate the particle from production point to the first layer - const Acts::Vector4 truthPosTime (pPos.x(), pPos.y(), pPos.z(), time); -// const Acts::Vector3 truthMomentum_dir = pMom.normalized(); -// double truthMomentum_abs = pMom.norm(); - - BoundVector params = BoundVector::Zero(); - params[Acts::eBoundLoc0] = pPos.x(); - params[Acts::eBoundLoc1] = pPos.y(); - params[Acts::eBoundPhi] = Acts::VectorHelpers::phi(pMom.normalized()); - params[Acts::eBoundTheta] = Acts::VectorHelpers::theta(pMom.normalized()); - params[Acts::eBoundQOverP] = charge/p; - params[Acts::eBoundTime] = time; - - Acts::BoundTrackParameters startParameters(initSurface, params, charge, std::nullopt); - auto truthParam = m_extrapolationTool->propagate(Gaudi::Hive::currentContext(), startParameters, *pSurface); - std::cout << "truth pos on 1st layer: " << truthParam->position(geoctx) << std::endl; - std::cout << "truth mom on 1st layer: " << truthParam->momentum() << std::endl; - std::cout << "truth parameters on 1st layer: " << truthParam->parameters() << std::endl; - - - // Call the Acts Kalman Filter - // Prepare the output data with MultiTrajectory - TrajectoryContainer trajectories; - trajectories.reserve(1); - - // Construct a perigee surface as the target surface - //auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>( - // Acts::Vector3{0., 0., 0.}); - - // Set the KalmanFitter options - std::unique_ptr<const Acts::Logger> logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE); - Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder> kfOptions( + Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic> kfOptions( geoctx, magctx, calctx, - MeasurementCalibrator(measurements), + MeasurementCalibrator(measurements->at(i)), Acts::VoidOutlierFinder(), - Acts::LoggerWrapper{*logger}, + Acts::VoidReverseFilteringLogic(), + Acts::LoggerWrapper{*m_logger}, Acts::PropagatorPlainOptions(), - &(*pSurface), - true, // scattering - true, // energy loss - false // backward filtering + &(*initialSurface) ); + kfOptions.multipleScattering = false; + kfOptions.energyLoss = false; ATH_MSG_DEBUG("Invoke fitter"); - - // Acts::Navigator navigator(trackingGeometry); - Acts::DirectNavigator navigator; - // navigator.resolvePassive = false; - // navigator.resolveMaterial = true; - // navigator.resolveSensitive = true; - - std::unique_ptr<ActsExtrapolationDetail::VariantPropagator> varProp; - - if (m_fieldMode == "FASER") { - ATH_MSG_INFO("Using FASER magnetic field service"); - ATH_CHECK( m_fieldCondObjInputKey.initialize() ); - auto bField = std::make_shared<FASERMagneticFieldWrapper>(); - auto stepper = Acts::EigenStepper<>(std::move(bField)); - auto propagator = Acts::Propagator<decltype(stepper), Acts::DirectNavigator>(std::move(stepper), - std::move(navigator)); - varProp = std::make_unique<VariantPropagator>(propagator); - } - else if (m_fieldMode == "Constant") { - if (m_constantFieldVector.value().size() != 3) - { - ATH_MSG_ERROR("Incorrect field vector size. Using empty field."); - return StatusCode::FAILURE; - } - - Acts::Vector3 constantFieldVector = Acts::Vector3(m_constantFieldVector[0], - m_constantFieldVector[1], - m_constantFieldVector[2]); - - ATH_MSG_INFO("Using constant magnetic field: (Bx, By, Bz) = (" << m_constantFieldVector[0] << ", " - << m_constantFieldVector[1] << ", " - << m_constantFieldVector[2] << ")"); - auto bField = std::make_shared<Acts::ConstantBField>(constantFieldVector); - auto stepper = Acts::EigenStepper<>(std::move(bField)); - auto propagator = Acts::Propagator<decltype(stepper), Acts::DirectNavigator>(std::move(stepper), - std::move(navigator)); - varProp = std::make_unique<VariantPropagator>(propagator); - } - - auto fit = makeFitterFunction(varProp.get()); - auto result = fit(sourceLinks, InitTrackParam, kfOptions, surfSequence); - - ATH_MSG_VERBOSE("Size of sourceLinks: " << sourceLinks.size()); + auto result = (*m_fit)(sourceLinks->at(i), initialTrackParameters->at(i), kfOptions); int itrack = 0; if (result.ok()) { // Get the fit output object const auto& fitOutput = result.value(); + std::unique_ptr<Trk::Track> track = makeTrack(geoctx, result, clusters->at(i)); + if (track) { + outputTracks->push_back(std::move(track)); + } // The track entry indices container. One element here. std::vector<size_t> trackTips; @@ -568,752 +186,142 @@ StatusCode FaserActsKalmanFilterAlg::execute() trajectories.emplace_back(std::move(fitOutput.fittedStates), std::move(trackTips), std::move(indexedParams)); } else { - ATH_MSG_WARNING("Fit failed for track " << itrack << " with error" - << result.error()); + ATH_MSG_WARNING("Fit failed for track " << itrack << " with error" << result.error()); // Fit failed, but still create a empty truth fit track trajectories.push_back(FaserActsRecMultiTrajectory()); } + } - fillFitResult(geoctx, trajectories, *truthParam); +// std::vector<Acts::CurvilinearTrackParameters> initialTrackParametersVector {*initialTrackParameters}; +// m_trajectoryWriterTool->writeout(trajectories, geoctx, initialTrackParametersVector); +// ATH_CHECK(m_trajectoryStatesWriterTool->write(trajectories, geoctx, *idLinks)); - } - return StatusCode::SUCCESS; -} + ATH_CHECK(trackContainer.record(std::move(outputTracks))); -StatusCode FaserActsKalmanFilterAlg::finalize() -{ return StatusCode::SUCCESS; } -namespace { - - template <typename Fitter> - struct FitterFunctionImpl - { - Fitter fitter; - - FitterFunctionImpl(Fitter&& f) : fitter(std::move(f)) {} - - FaserActsKalmanFilterAlg::FitterResult - operator()( - const std::vector<IndexSourceLink>& sourceLinks, - const Acts::CurvilinearTrackParameters& initialParameters, - const Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder>& options, - const std::vector<const Acts::Surface*>& sSequence) const - { - return fitter.fit(sourceLinks, initialParameters, options, sSequence); - }; - }; +StatusCode FaserActsKalmanFilterAlg::finalize() { + return StatusCode::SUCCESS; } -FaserActsKalmanFilterAlg::FitterFunction -FaserActsKalmanFilterAlg::makeFitterFunction( - ActsExtrapolationDetail::VariantPropagator* varProp) -{ - - return boost::apply_visitor([&](const auto& propagator) -> FitterFunction { - using Updater = Acts::GainMatrixUpdater; - using Smoother = Acts::GainMatrixSmoother; - using Fitter = Acts::KalmanFitter<typename std::decay_t<decltype(propagator)>, Updater, Smoother>; - - Fitter fitter(std::move(propagator)); - // build the fitter functions. owns the fitter object. - return FitterFunctionImpl<Fitter>(std::move(fitter)); - }, *varProp); -} - -//Acts::MagneticFieldContext FaserActsKalmanFilterAlg::getMagneticFieldContext(const EventContext& ctx) const { -//SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; -Acts::MagneticFieldContext FaserActsKalmanFilterAlg::getMagneticFieldContext() const { - SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey}; +Acts::MagneticFieldContext FaserActsKalmanFilterAlg::getMagneticFieldContext(const EventContext& ctx) const { + SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; if (!readHandle.isValid()) { std::stringstream msg; msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << "."; throw std::runtime_error(msg.str()); } const FaserFieldCacheCondObj* fieldCondObj{*readHandle}; - return Acts::MagneticFieldContext(fieldCondObj); } -void FaserActsKalmanFilterAlg::initializeTree() -{ - m_trackTree->Branch("event_nr", &m_eventNr); - m_trackTree->Branch("traj_nr", &m_trajNr); - m_trackTree->Branch("track_nr", &m_trackNr); - m_trackTree->Branch("t_barcode", &m_t_barcode, "t_barcode/l"); - m_trackTree->Branch("t_charge", &m_t_charge); - m_trackTree->Branch("t_eT", &m_t_eT); - m_trackTree->Branch("t_eLOC0", &m_t_eLOC0); - m_trackTree->Branch("t_eLOC1", &m_t_eLOC1); - m_trackTree->Branch("t_x", &m_t_x); - m_trackTree->Branch("t_y", &m_t_y); - m_trackTree->Branch("t_z", &m_t_z); - m_trackTree->Branch("t_px", &m_t_px); - m_trackTree->Branch("t_py", &m_t_py); - m_trackTree->Branch("t_pz", &m_t_pz); - m_trackTree->Branch("t_eTHETA", &m_t_eTHETA); - m_trackTree->Branch("t_ePHI", &m_t_ePHI); - m_trackTree->Branch("t_eQOP", &m_t_eQOP); - - m_trackTree->Branch("hasFittedParams", &m_hasFittedParams); - m_trackTree->Branch("chi2_fit", &m_chi2_fit); - m_trackTree->Branch("ndf_fit", &m_ndf_fit); - m_trackTree->Branch("eLOC0_fit", &m_eLOC0_fit); - m_trackTree->Branch("eLOC1_fit", &m_eLOC1_fit); - m_trackTree->Branch("ePHI_fit", &m_ePHI_fit); - m_trackTree->Branch("eTHETA_fit", &m_eTHETA_fit); - m_trackTree->Branch("eQOP_fit", &m_eQOP_fit); - m_trackTree->Branch("eT_fit", &m_eT_fit); - m_trackTree->Branch("charge_fit", &m_charge_fit); - m_trackTree->Branch("err_eLOC0_fit", &m_err_eLOC0_fit); - m_trackTree->Branch("err_eLOC1_fit", &m_err_eLOC1_fit); - m_trackTree->Branch("err_ePHI_fit", &m_err_ePHI_fit); - m_trackTree->Branch("err_eTHETA_fit", &m_err_eTHETA_fit); - m_trackTree->Branch("err_eQOP_fit", &m_err_eQOP_fit); - m_trackTree->Branch("err_eT_fit", &m_err_eT_fit); - m_trackTree->Branch("g_px_fit", &m_px_fit); - m_trackTree->Branch("g_py_fit", &m_py_fit); - m_trackTree->Branch("g_pz_fit", &m_pz_fit); - m_trackTree->Branch("g_x_fit" , &m_x_fit); - m_trackTree->Branch("g_y_fit" , &m_y_fit); - m_trackTree->Branch("g_z_fit" , &m_z_fit); - - m_trackTree->Branch("nHoles", &m_nHoles); - m_trackTree->Branch("nOutliers", &m_nOutliers); - m_trackTree->Branch("nStates", &m_nStates); - m_trackTree->Branch("nMeasurements", &m_nMeasurements); - m_trackTree->Branch("volume_id", &m_volumeID); - m_trackTree->Branch("layer_id", &m_layerID); - m_trackTree->Branch("module_id", &m_moduleID); - m_trackTree->Branch("l_x_hit", &m_lx_hit); - m_trackTree->Branch("l_y_hit", &m_ly_hit); - m_trackTree->Branch("g_x_hit", &m_x_hit); - m_trackTree->Branch("g_y_hit", &m_y_hit); - m_trackTree->Branch("g_z_hit", &m_z_hit); - m_trackTree->Branch("res_x_hit", &m_res_x_hit); - m_trackTree->Branch("res_y_hit", &m_res_y_hit); - m_trackTree->Branch("err_x_hit", &m_err_x_hit); - m_trackTree->Branch("err_y_hit", &m_err_y_hit); - m_trackTree->Branch("pull_x_hit", &m_pull_x_hit); - m_trackTree->Branch("pull_y_hit", &m_pull_y_hit); - m_trackTree->Branch("dim_hit", &m_dim_hit); - m_trackTree->Branch("nPredicted", &m_nPredicted); - m_trackTree->Branch("predicted", &m_prt); - m_trackTree->Branch("eLOC0_prt", &m_eLOC0_prt); - m_trackTree->Branch("eLOC1_prt", &m_eLOC1_prt); - m_trackTree->Branch("ePHI_prt", &m_ePHI_prt); - m_trackTree->Branch("eTHETA_prt", &m_eTHETA_prt); - m_trackTree->Branch("eQOP_prt", &m_eQOP_prt); - m_trackTree->Branch("eT_prt", &m_eT_prt); - m_trackTree->Branch("res_eLOC0_prt", &m_res_eLOC0_prt); - m_trackTree->Branch("res_eLOC1_prt", &m_res_eLOC1_prt); - m_trackTree->Branch("err_eLOC0_prt", &m_err_eLOC0_prt); - m_trackTree->Branch("err_eLOC1_prt", &m_err_eLOC1_prt); - m_trackTree->Branch("err_ePHI_prt", &m_err_ePHI_prt); - m_trackTree->Branch("err_eTHETA_prt", &m_err_eTHETA_prt); - m_trackTree->Branch("err_eQOP_prt", &m_err_eQOP_prt); - m_trackTree->Branch("err_eT_prt", &m_err_eT_prt); - m_trackTree->Branch("pull_eLOC0_prt", &m_pull_eLOC0_prt); - m_trackTree->Branch("pull_eLOC1_prt", &m_pull_eLOC1_prt); - m_trackTree->Branch("g_x_prt", &m_x_prt); - m_trackTree->Branch("g_y_prt", &m_y_prt); - m_trackTree->Branch("g_z_prt", &m_z_prt); - m_trackTree->Branch("px_prt", &m_px_prt); - m_trackTree->Branch("py_prt", &m_py_prt); - m_trackTree->Branch("pz_prt", &m_pz_prt); - m_trackTree->Branch("eta_prt", &m_eta_prt); - m_trackTree->Branch("pT_prt", &m_pT_prt); - - m_trackTree->Branch("nFiltered", &m_nFiltered); - m_trackTree->Branch("filtered", &m_flt); - m_trackTree->Branch("eLOC0_flt", &m_eLOC0_flt); - m_trackTree->Branch("eLOC1_flt", &m_eLOC1_flt); - m_trackTree->Branch("ePHI_flt", &m_ePHI_flt); - m_trackTree->Branch("eTHETA_flt", &m_eTHETA_flt); - m_trackTree->Branch("eQOP_flt", &m_eQOP_flt); - m_trackTree->Branch("eT_flt", &m_eT_flt); - m_trackTree->Branch("res_eLOC0_flt", &m_res_eLOC0_flt); - m_trackTree->Branch("res_eLOC1_flt", &m_res_eLOC1_flt); - m_trackTree->Branch("err_eLOC0_flt", &m_err_eLOC0_flt); - m_trackTree->Branch("err_eLOC1_flt", &m_err_eLOC1_flt); - m_trackTree->Branch("err_ePHI_flt", &m_err_ePHI_flt); - m_trackTree->Branch("err_eTHETA_flt", &m_err_eTHETA_flt); - m_trackTree->Branch("err_eQOP_flt", &m_err_eQOP_flt); - m_trackTree->Branch("err_eT_flt", &m_err_eT_flt); - m_trackTree->Branch("pull_eLOC0_flt", &m_pull_eLOC0_flt); - m_trackTree->Branch("pull_eLOC1_flt", &m_pull_eLOC1_flt); - m_trackTree->Branch("g_x_flt", &m_x_flt); - m_trackTree->Branch("g_y_flt", &m_y_flt); - m_trackTree->Branch("g_z_flt", &m_z_flt); - m_trackTree->Branch("px_flt", &m_px_flt); - m_trackTree->Branch("py_flt", &m_py_flt); - m_trackTree->Branch("pz_flt", &m_pz_flt); - m_trackTree->Branch("eta_flt", &m_eta_flt); - m_trackTree->Branch("pT_flt", &m_pT_flt); - m_trackTree->Branch("chi2", &m_chi2); - - m_trackTree->Branch("nSmoothed", &m_nSmoothed); - m_trackTree->Branch("smoothed", &m_smt); - m_trackTree->Branch("eLOC0_smt", &m_eLOC0_smt); - m_trackTree->Branch("eLOC1_smt", &m_eLOC1_smt); - m_trackTree->Branch("ePHI_smt", &m_ePHI_smt); - m_trackTree->Branch("eTHETA_smt", &m_eTHETA_smt); - m_trackTree->Branch("eQOP_smt", &m_eQOP_smt); - m_trackTree->Branch("eT_smt", &m_eT_smt); - m_trackTree->Branch("res_eLOC0_smt", &m_res_eLOC0_smt); - m_trackTree->Branch("res_eLOC1_smt", &m_res_eLOC1_smt); - m_trackTree->Branch("err_eLOC0_smt", &m_err_eLOC0_smt); - m_trackTree->Branch("err_eLOC1_smt", &m_err_eLOC1_smt); - m_trackTree->Branch("err_ePHI_smt", &m_err_ePHI_smt); - m_trackTree->Branch("err_eTHETA_smt", &m_err_eTHETA_smt); - m_trackTree->Branch("err_eQOP_smt", &m_err_eQOP_smt); - m_trackTree->Branch("err_eT_smt", &m_err_eT_smt); - m_trackTree->Branch("pull_eLOC0_smt", &m_pull_eLOC0_smt); - m_trackTree->Branch("pull_eLOC1_smt", &m_pull_eLOC1_smt); - m_trackTree->Branch("g_x_smt", &m_x_smt); - m_trackTree->Branch("g_y_smt", &m_y_smt); - m_trackTree->Branch("g_z_smt", &m_z_smt); - m_trackTree->Branch("px_smt", &m_px_smt); - m_trackTree->Branch("py_smt", &m_py_smt); - m_trackTree->Branch("pz_smt", &m_pz_smt); - m_trackTree->Branch("eta_smt", &m_eta_smt); - m_trackTree->Branch("pT_smt", &m_pT_smt); +std::unique_ptr<Trk::Track> +FaserActsKalmanFilterAlg::makeTrack(Acts::GeometryContext& geoCtx, TrackFitterResult& fitResult, std::vector<const Tracker::FaserSCT_Cluster*> clusters) const { + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + std::unique_ptr<Trk::Track> newtrack = nullptr; + //Get the fit output object + const auto& fitOutput = fitResult.value(); + if (fitOutput.fittedParameters) { + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; + // Loop over all the output state to create track state + fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndex, [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + // We need to determine the type of state + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + // State is a hole (no associated measurement), use predicted para meters + if (flag[Acts::TrackStateFlag::HoleFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), + state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + // The state was tagged as an outlier, use filtered parameters + else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + // The state is a measurement state, use smoothed parameters + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); + // const auto& psurface=actsParam.referenceSurface(); + Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); + // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); + // auto pos=actsParam.position(tgContext); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* fitCluster = clusters.at(state.uncalibrated().index()); + if (fitCluster->detectorElement() != nullptr) { + measState = new Tracker::FaserSCT_ClusterOnTrack{ + fitCluster, + Trk::LocalParameters{ + Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2} + }, + fitCluster->localCovariance(), + m_idHelper->wafer_hash(fitCluster->detectorElement()->identify()) + }; + } + } + double nDoF = state.calibratedSize(); + const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); + // If a state was succesfully created add it to the trajectory + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + // Create the track using the states + const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + // Trk::FitQuality* q = nullptr; + // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter + newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); + } + return newtrack; } -void FaserActsKalmanFilterAlg::fillFitResult( - const Acts::GeometryContext& geoctx, - const TrajectoryContainer& trajectories, - const Acts::BoundTrackParameters& truthParam -) -{ - m_t_eLOC0 = truthParam.parameters()[Acts::eBoundLoc0]; - m_t_eLOC1 = truthParam.parameters()[Acts::eBoundLoc1]; - m_t_ePHI = truthParam.parameters()[Acts::eBoundPhi]; - m_t_eTHETA = truthParam.parameters()[Acts::eBoundTheta]; - m_t_eQOP = truthParam.parameters()[Acts::eBoundQOverP]; - m_t_eT = truthParam.parameters()[Acts::eBoundTime]; - m_t_x = truthParam.position(geoctx)(0); - m_t_y = truthParam.position(geoctx)(1); - m_t_z = truthParam.position(geoctx)(2); - m_t_px = truthParam.momentum()(0); - m_t_py = truthParam.momentum()(1); - m_t_pz = truthParam.momentum()(2); - std::cout<<"truth global position on the first layer = "<<m_t_x<<" "<<m_t_y<<" "<<m_t_z<<" "<<std::endl; - std::cout<<"truth momentum on the first layer = "<<m_t_px<<" "<<m_t_py<<" "<<m_t_pz<<" "<<std::endl; - std::cout<<"truth local parameters on the first layer = "<<m_t_eLOC0<<" "<<m_t_eLOC1<<" "<<m_t_ePHI<<" "<<m_t_eTHETA<<" "<<m_t_eQOP<<" "<<std::endl; - - // Loop over the trajectories - int iTraj = 0; - for (const auto& traj : trajectories) { - m_trajNr = iTraj; - - // The trajectory entry indices and the multiTrajectory - const auto& [trackTips, mj] = traj.trajectory(); - if (trackTips.empty()) { - ATH_MSG_WARNING("Empty multiTrajectory."); - continue; +const Trk::TrackParameters* +FaserActsKalmanFilterAlg ::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const { + using namespace Acts::UnitLiterals; + std::optional<AmgSymMatrix(5)> cov = std::nullopt; + if (actsParameter.covariance()){ + AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5)); + // Convert the covariance matrix to GeV + for(int i=0; i < newcov.rows(); i++){ + newcov(i, 4) = newcov(i, 4)*1_MeV; } - - // Get the entry index for the single trajectory - auto& trackTip = trackTips.front(); - std::cout<<"trackTip = "<<trackTip<<std::endl; - - // Collect the trajectory summary info - auto trajState = - Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); - - m_nMeasurements = trajState.nMeasurements; - m_nStates = trajState.nStates; - m_nOutliers = trajState.nOutliers; - m_nHoles = trajState.nHoles; - m_chi2_fit = trajState.chi2Sum; - m_ndf_fit = trajState.NDF; - std::cout << "Track has " << trajState.nMeasurements - << " measurements and " << trajState.nHoles - << " holes and " << trajState.nOutliers - << " outliers and " << trajState.nStates - << " states " << std::endl; - - /// If it has track parameters, fill the values - if (traj.hasTrackParameters(trackTip)) - { - m_hasFittedParams = true; - const auto &boundParam = traj.trackParameters(trackTip); - const auto ¶meter = boundParam.parameters(); - const auto &covariance = *boundParam.covariance(); - m_charge_fit = boundParam.charge(); - m_eLOC0_fit = parameter[Acts::eBoundLoc0]; - m_eLOC1_fit = parameter[Acts::eBoundLoc1]; - m_ePHI_fit = parameter[Acts::eBoundPhi]; - m_eTHETA_fit = parameter[Acts::eBoundTheta]; - m_eQOP_fit = parameter[Acts::eBoundQOverP]; - m_eT_fit = parameter[Acts::eBoundTime]; - m_err_eLOC0_fit = - sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)); - m_err_eLOC1_fit = - sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)); - m_err_ePHI_fit = sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)); - m_err_eTHETA_fit = - sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)); - m_err_eQOP_fit = sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)); - m_err_eT_fit = sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime)); - - m_px_fit = boundParam.momentum()(0); - m_py_fit = boundParam.momentum()(1); - m_pz_fit = boundParam.momentum()(2); - m_x_fit = boundParam.position(geoctx)(0); - m_y_fit = boundParam.position(geoctx)(1); - m_z_fit = boundParam.position(geoctx)(2); + for(int i=0; i < newcov.cols(); i++){ + newcov(4, i) = newcov(4, i)*1_MeV; } - - m_nPredicted = 0; - m_nFiltered = 0; - m_nSmoothed = 0; - - mj.visitBackwards(trackTip, [&](const auto &state) { - /// Only fill the track states with non-outlier measurement - auto typeFlags = state.typeFlags(); - if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) - { - return true; - } - - const auto& surface = state.referenceSurface(); - - /// Get the geometry ID - auto geoID = state.referenceSurface().geometryId(); - m_volumeID.push_back(geoID.volume()); - m_layerID.push_back(geoID.layer()); - m_moduleID.push_back(geoID.sensitive()); - - // expand the local measurements into the full bound space - Acts::BoundVector meas = - state.projector().transpose() * state.calibrated(); - - // extract local and global position - Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); - Acts::Vector3 mom(1, 1, 1); - Acts::Vector3 global = - surface.localToGlobal(geoctx, local, mom); - - // fill the measurement info - m_lx_hit.push_back(local[Acts::ePos0]); - m_ly_hit.push_back(local[Acts::ePos1]); - m_x_hit.push_back(global[Acts::ePos0]); - m_y_hit.push_back(global[Acts::ePos1]); - m_z_hit.push_back(global[Acts::ePos2]); - - /// Get the predicted parameter for this state - bool predicted = false; - if (state.hasPredicted()) - { - predicted = true; - m_nPredicted++; - Acts::BoundTrackParameters parameter( - state.referenceSurface().getSharedPtr(), - state.predicted(), - state.predictedCovariance()); - auto covariance = state.predictedCovariance(); - - /// Local hit residual info - auto H = state.effectiveProjector(); - auto resCov = state.effectiveCalibratedCovariance() + - H * covariance * H.transpose(); - auto residual = state.effectiveCalibrated() - H * state.predicted(); - - /// Predicted residual - m_res_eLOC0_prt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_prt.push_back(residual(Acts::eBoundLoc1)); - - /// Predicted parameter pulls - m_pull_eLOC0_prt.push_back( - residual(Acts::eBoundLoc0) / - sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_prt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); - - - /// Predicted parameter - m_eLOC0_prt.push_back(parameter.parameters()[Acts::eBoundLoc0]); - m_eLOC1_prt.push_back(parameter.parameters()[Acts::eBoundLoc1]); - m_ePHI_prt.push_back(parameter.parameters()[Acts::eBoundPhi]); - m_eTHETA_prt.push_back(parameter.parameters()[Acts::eBoundTheta]); - m_eQOP_prt.push_back(parameter.parameters()[Acts::eBoundQOverP]); - m_eT_prt.push_back(parameter.parameters()[Acts::eBoundTime]); - - /// Predicted parameter Uncertainties - m_err_eLOC0_prt.push_back( - sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_err_eLOC1_prt.push_back( - sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); - m_err_ePHI_prt.push_back( - sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); - m_err_eTHETA_prt.push_back( - sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); - m_err_eQOP_prt.push_back( - sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); - m_err_eT_prt.push_back( - sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); - - m_x_prt.push_back(parameter.position(geoctx).x()); - m_y_prt.push_back(parameter.position(geoctx).y()); - m_z_prt.push_back(parameter.position(geoctx).z()); - m_px_prt.push_back(parameter.momentum().x()); - m_py_prt.push_back(parameter.momentum().y()); - m_pz_prt.push_back(parameter.momentum().z()); - m_pT_prt.push_back(parameter.transverseMomentum()); - m_eta_prt.push_back(eta(parameter.position(geoctx))); - } - else - { - /// Push bad values if no predicted parameter - m_eLOC0_prt.push_back(-9999); - m_eLOC1_prt.push_back(-9999); - m_ePHI_prt.push_back(-9999); - m_eTHETA_prt.push_back(-9999); - m_eQOP_prt.push_back(-9999); - m_eT_prt.push_back(-9999); - m_res_eLOC0_prt.push_back(-9999); - m_res_eLOC1_prt.push_back(-9999); - m_err_eLOC0_prt.push_back(-9999); - m_err_eLOC1_prt.push_back(-9999); - m_err_ePHI_prt.push_back(-9999); - m_err_eTHETA_prt.push_back(-9999); - m_err_eQOP_prt.push_back(-9999); - m_err_eT_prt.push_back(-9999); - m_pull_eLOC0_prt.push_back(-9999); - m_pull_eLOC1_prt.push_back(-9999); - m_x_prt.push_back(-9999); - m_y_prt.push_back(-9999); - m_z_prt.push_back(-9999); - m_px_prt.push_back(-9999); - m_py_prt.push_back(-9999); - m_pz_prt.push_back(-9999); - m_pT_prt.push_back(-9999); - m_eta_prt.push_back(-9999); - } - - bool filtered = false; - if (state.hasFiltered()) - { - filtered = true; - m_nFiltered++; - Acts::BoundTrackParameters parameter( - state.referenceSurface().getSharedPtr(), - state.filtered(), - state.filteredCovariance()); - auto covariance = state.filteredCovariance(); - - /// Local hit residual info - auto H = state.effectiveProjector(); - auto resCov = state.effectiveCalibratedCovariance() + - H * covariance * H.transpose(); - auto residual = state.effectiveCalibrated() - H * state.filtered(); - - /// Filtered residual - m_res_eLOC0_flt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_flt.push_back(residual(Acts::eBoundLoc1)); - - /// Filtered parameter pulls - m_pull_eLOC0_flt.push_back( - residual(Acts::eBoundLoc0) / - sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_flt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); - - /// Filtered parameter - m_eLOC0_flt.push_back(parameter.parameters()[Acts::eBoundLoc0]); - m_eLOC1_flt.push_back(parameter.parameters()[Acts::eBoundLoc1]); - m_ePHI_flt.push_back(parameter.parameters()[Acts::eBoundPhi]); - m_eTHETA_flt.push_back(parameter.parameters()[Acts::eBoundTheta]); - m_eQOP_flt.push_back(parameter.parameters()[Acts::eBoundQOverP]); - m_eT_flt.push_back(parameter.parameters()[Acts::eBoundTime]); - - /// Filtered parameter uncertainties - m_err_eLOC0_flt.push_back( - sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_err_eLOC1_flt.push_back( - sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); - m_err_ePHI_flt.push_back( - sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); - m_err_eTHETA_flt.push_back( - sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); - m_err_eQOP_flt.push_back( - sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); - m_err_eT_flt.push_back( - sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); - - /// Other filtered parameter info - m_x_flt.push_back(parameter.position(geoctx).x()); - m_y_flt.push_back(parameter.position(geoctx).y()); - m_z_flt.push_back(parameter.position(geoctx).z()); - m_px_flt.push_back(parameter.momentum().x()); - m_py_flt.push_back(parameter.momentum().y()); - m_pz_flt.push_back(parameter.momentum().z()); - m_pT_flt.push_back(parameter.transverseMomentum()); - m_eta_flt.push_back(eta(parameter.position(geoctx))); - m_chi2.push_back(state.chi2()); - - } - else - { - /// Push bad values if no filtered parameter - m_eLOC0_flt.push_back(-9999); - m_eLOC1_flt.push_back(-9999); - m_ePHI_flt.push_back(-9999); - m_eTHETA_flt.push_back(-9999); - m_eQOP_flt.push_back(-9999); - m_eT_flt.push_back(-9999); - m_res_eLOC0_flt.push_back(-9999); - m_res_eLOC1_flt.push_back(-9999); - m_err_eLOC0_flt.push_back(-9999); - m_err_eLOC1_flt.push_back(-9999); - m_err_ePHI_flt.push_back(-9999); - m_err_eTHETA_flt.push_back(-9999); - m_err_eQOP_flt.push_back(-9999); - m_err_eT_flt.push_back(-9999); - m_pull_eLOC0_flt.push_back(-9999); - m_pull_eLOC1_flt.push_back(-9999); - m_x_flt.push_back(-9999); - m_y_flt.push_back(-9999); - m_z_flt.push_back(-9999); - m_py_flt.push_back(-9999); - m_pz_flt.push_back(-9999); - m_pT_flt.push_back(-9999); - m_eta_flt.push_back(-9999); - m_chi2.push_back(-9999); - } - - bool smoothed = false; - if (state.hasSmoothed()) - { - smoothed = true; - m_nSmoothed++; - Acts::BoundTrackParameters parameter( - state.referenceSurface().getSharedPtr(), - state.smoothed(), - state.smoothedCovariance()); - auto covariance = state.smoothedCovariance(); - - /// Local hit residual info - auto H = state.effectiveProjector(); - auto resCov = state.effectiveCalibratedCovariance() + - H * covariance * H.transpose(); - auto residual = state.effectiveCalibrated() - H * state.smoothed(); - - m_res_x_hit.push_back(residual(Acts::eBoundLoc0)); - m_res_y_hit.push_back(residual(Acts::eBoundLoc1)); - m_err_x_hit.push_back( - sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_err_y_hit.push_back( - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); - m_pull_x_hit.push_back( - residual(Acts::eBoundLoc0) / - sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_y_hit.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); - m_dim_hit.push_back(state.calibratedSize()); - - /// Smoothed residual - m_res_eLOC0_smt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_smt.push_back(residual(Acts::eBoundLoc1)); - - /// Smoothed parameter pulls - m_pull_eLOC0_smt.push_back( - residual(Acts::eBoundLoc0) / - sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_smt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); - - /// Smoothed parameter - m_eLOC0_smt.push_back(parameter.parameters()[Acts::eBoundLoc0]); - m_eLOC1_smt.push_back(parameter.parameters()[Acts::eBoundLoc1]); - m_ePHI_smt.push_back(parameter.parameters()[Acts::eBoundPhi]); - m_eTHETA_smt.push_back(parameter.parameters()[Acts::eBoundTheta]); - m_eQOP_smt.push_back(parameter.parameters()[Acts::eBoundQOverP]); - m_eT_smt.push_back(parameter.parameters()[Acts::eBoundTime]); - - /// Smoothed parameter uncertainties - m_err_eLOC0_smt.push_back( - sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_err_eLOC1_smt.push_back( - sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); - m_err_ePHI_smt.push_back( - sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); - m_err_eTHETA_smt.push_back( - sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); - m_err_eQOP_smt.push_back( - sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); - m_err_eT_smt.push_back( - sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); - - m_x_smt.push_back(parameter.position(geoctx).x()); - m_y_smt.push_back(parameter.position(geoctx).y()); - m_z_smt.push_back(parameter.position(geoctx).z()); - m_px_smt.push_back(parameter.momentum().x()); - m_py_smt.push_back(parameter.momentum().y()); - m_pz_smt.push_back(parameter.momentum().z()); - m_pT_smt.push_back(parameter.transverseMomentum()); - m_eta_smt.push_back(eta(parameter.position(geoctx))); - } - else - { - /// Push bad values if no smoothed parameter - m_eLOC0_smt.push_back(-9999); - m_eLOC1_smt.push_back(-9999); - m_ePHI_smt.push_back(-9999); - m_eTHETA_smt.push_back(-9999); - m_eQOP_smt.push_back(-9999); - m_eT_smt.push_back(-9999); - m_res_eLOC0_smt.push_back(-9999); - m_res_eLOC1_smt.push_back(-9999); - m_err_eLOC0_smt.push_back(-9999); - m_err_eLOC1_smt.push_back(-9999); - m_err_ePHI_smt.push_back(-9999); - m_err_eTHETA_smt.push_back(-9999); - m_err_eQOP_smt.push_back(-9999); - m_err_eT_smt.push_back(-9999); - m_pull_eLOC0_smt.push_back(-9999); - m_pull_eLOC1_smt.push_back(-9999); - m_x_smt.push_back(-9999); - m_y_smt.push_back(-9999); - m_z_smt.push_back(-9999); - m_px_smt.push_back(-9999); - m_py_smt.push_back(-9999); - m_pz_smt.push_back(-9999); - m_pT_smt.push_back(-9999); - m_eta_smt.push_back(-9999); - m_res_x_hit.push_back(-9999); - m_res_y_hit.push_back(-9999); - m_err_x_hit.push_back(-9999); - m_err_y_hit.push_back(-9999); - m_pull_x_hit.push_back(-9999); - m_pull_y_hit.push_back(-9999); - m_dim_hit.push_back(-9999); - } - - /// Save whether or not states had various KF steps - m_prt.push_back(predicted); - m_flt.push_back(filtered); - m_smt.push_back(smoothed); - - return true; - } /// Finish lambda function - ); /// Finish multi trajectory visitBackwards call - - iTraj++; - - } // all trajectories - - m_trackTree->Fill(); - - clearTrackVariables(); + cov = std::optional<AmgSymMatrix(5)>(newcov); + } + const Amg::Vector3D& pos=actsParameter.position(gctx); + double tphi=actsParameter.get<Acts::eBoundPhi>(); + double ttheta=actsParameter.get<Acts::eBoundTheta>(); + double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV; + double p = std::abs(1. / tqOverP); + Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta)); + const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov); + return curv; } -void FaserActsKalmanFilterAlg::clearTrackVariables() -{ - m_volumeID.clear(); - m_layerID.clear(); - m_moduleID.clear(); - m_lx_hit.clear(); - m_ly_hit.clear(); - m_x_hit.clear(); - m_y_hit.clear(); - m_z_hit.clear(); - m_res_x_hit.clear(); - m_res_y_hit.clear(); - m_err_x_hit.clear(); - m_err_y_hit.clear(); - m_pull_x_hit.clear(); - m_pull_y_hit.clear(); - m_dim_hit.clear(); - - m_prt.clear(); - m_eLOC0_prt.clear(); - m_eLOC1_prt.clear(); - m_ePHI_prt.clear(); - m_eTHETA_prt.clear(); - m_eQOP_prt.clear(); - m_eT_prt.clear(); - m_res_eLOC0_prt.clear(); - m_res_eLOC1_prt.clear(); - m_err_eLOC0_prt.clear(); - m_err_eLOC1_prt.clear(); - m_err_ePHI_prt.clear(); - m_err_eTHETA_prt.clear(); - m_err_eQOP_prt.clear(); - m_err_eT_prt.clear(); - m_pull_eLOC0_prt.clear(); - m_pull_eLOC1_prt.clear(); - m_x_prt.clear(); - m_y_prt.clear(); - m_z_prt.clear(); - m_px_prt.clear(); - m_py_prt.clear(); - m_pz_prt.clear(); - m_eta_prt.clear(); - m_pT_prt.clear(); - - m_flt.clear(); - m_eLOC0_flt.clear(); - m_eLOC1_flt.clear(); - m_ePHI_flt.clear(); - m_eTHETA_flt.clear(); - m_eQOP_flt.clear(); - m_eT_flt.clear(); - m_res_eLOC0_flt.clear(); - m_res_eLOC1_flt.clear(); - m_err_eLOC0_flt.clear(); - m_err_eLOC1_flt.clear(); - m_err_ePHI_flt.clear(); - m_err_eTHETA_flt.clear(); - m_err_eQOP_flt.clear(); - m_err_eT_flt.clear(); - m_pull_eLOC0_flt.clear(); - m_pull_eLOC1_flt.clear(); - m_x_flt.clear(); - m_y_flt.clear(); - m_z_flt.clear(); - m_px_flt.clear(); - m_py_flt.clear(); - m_pz_flt.clear(); - m_eta_flt.clear(); - m_pT_flt.clear(); - m_chi2.clear(); - - m_smt.clear(); - m_eLOC0_smt.clear(); - m_eLOC1_smt.clear(); - m_ePHI_smt.clear(); - m_eTHETA_smt.clear(); - m_eQOP_smt.clear(); - m_eT_smt.clear(); - m_res_eLOC0_smt.clear(); - m_res_eLOC1_smt.clear(); - m_err_eLOC0_smt.clear(); - m_err_eLOC1_smt.clear(); - m_err_ePHI_smt.clear(); - m_err_eTHETA_smt.clear(); - m_err_eQOP_smt.clear(); - m_err_eT_smt.clear(); - m_pull_eLOC0_smt.clear(); - m_pull_eLOC1_smt.clear(); - m_x_smt.clear(); - m_y_smt.clear(); - m_z_smt.clear(); - m_px_smt.clear(); - m_py_smt.clear(); - m_pz_smt.clear(); - m_eta_smt.clear(); - m_pT_smt.clear(); - - return; -} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6cfb07d143b8b49652ad54ee768a1af2b0671fae --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx @@ -0,0 +1,114 @@ +#include "FaserActsKalmanFilter/GhostBusters.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" + + +GhostBusters::GhostBusters(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name) {} + + +StatusCode GhostBusters::initialize() { + ATH_CHECK(m_trackCollection.initialize()); + // ATH_CHECK(m_simDataCollectionKey.initialize()); + ATH_CHECK(m_outputTrackCollection.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + m_tree = new TTree("tree", "tree"); + m_tree->Branch("event_number", &m_event_number, "event_number/I"); + m_tree->Branch("station", &m_station, "station/I"); + m_tree->Branch("x", &m_x, "x/D"); + m_tree->Branch("y", &m_y, "y/D"); + m_tree->Branch("z", &m_z, "z/D"); + m_tree->Branch("chi2", &m_chi2, "chi2/D"); + // m_tree->Branch("majorityHits", &m_majorityHits, "majorityHits/I"); + m_tree->Branch("size", &m_size, "size/I"); + m_tree->Branch("isGhost", &m_isGhost, "isGhost/B"); + ATH_CHECK(histSvc()->regTree("/HIST2/tree", m_tree)); + + return StatusCode::SUCCESS; +} + + +StatusCode GhostBusters::execute(const EventContext &ctx) const { + m_event_number = ctx.eventID().event_number(); + + SG::WriteHandle outputTrackCollection {m_outputTrackCollection, ctx}; + std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>(); + + // SG::ReadHandle<TrackerSimDataCollection> simData {m_simDataCollectionKey, ctx}; + // ATH_CHECK(simData.isValid()); + + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection, ctx}; + ATH_CHECK(trackCollection.isValid()); + + std::map<int, std::vector<Segment>> segments {}; + for (const Trk::Track* track : *trackCollection) { + auto segment = Segment(track, m_idHelper); + segments[segment.station()].push_back(segment); + } + + for (const auto &station : segments) { + double nGoodSegments = 0; + std::vector<Segment> stationSegments = station.second; + std::sort(stationSegments.begin(), stationSegments.end(), [](const Segment &lhs, const Segment &rhs) { return lhs.y() > rhs.y(); }); + double maxX = stationSegments.front().x(); + double maxY = stationSegments.front().y(); + double minX = stationSegments.back().x(); + double minY = stationSegments.back().y(); + double deltaY = maxY - minY; + double meanX = 0.5 * (minX + maxX); + double meanY = 0.5 * (minY + maxY); + double deltaX = deltaY / (2 * std::tan(0.02)); + for (Segment &segment : stationSegments) { + bool isGhost = (segment.y() > meanY - m_yTolerance * deltaY) && (segment.y() < meanY + m_yTolerance * deltaY) && ( + ((segment.x() > meanX - (1 + m_xTolerance) * deltaX) && + (segment.x() < meanX - (1 - m_xTolerance) * deltaX)) || + ((segment.x() > meanX + (1 - m_xTolerance) * deltaX) && (segment.x() < meanX + (1 + m_xTolerance) * deltaX))); + if (isGhost) segment.setGhost(); + if (not isGhost && segment.size() >= 5) nGoodSegments++; + } + for (const Segment &segment : stationSegments) { + m_x = segment.x(); + m_y = segment.y(); + m_z = segment.z(); + m_chi2 = segment.chi2(); + m_station = segment.station(); + m_size = segment.size(); + // m_majorityHits = segment.majorityHits(); + m_isGhost = segment.isGhost(); + if (nGoodSegments >= 2 && segment.size() == 4) m_isGhost = true; + m_tree->Fill(); + if (segment.isGhost()) continue; + if (nGoodSegments >= 2 && segment.size() == 4) continue; + outputTracks->push_back(new Trk::Track(*segment.track())); + } + } + + ATH_CHECK(outputTrackCollection.record(std::move(outputTracks))); + return StatusCode::SUCCESS; +} + + +StatusCode GhostBusters::finalize() { + return StatusCode::SUCCESS; +} + + +GhostBusters::Segment::Segment(const Trk::Track *track, const FaserSCT_ID *idHelper) { + m_track = track; + m_position = track->trackParameters()->front()->position(); + m_chi2 = track->fitQuality()->chiSquared(); + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + clusters.emplace_back(clusterOnTrack->prepRawData()); + m_station = idHelper->station(clusterOnTrack->identify()); + } + } + m_size = clusters.size(); + // identifyContributingParticles(simDataCollection, clusters, m_particleHitCounts); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..52aae1d0f2a06e728df5f8f63767836c009cfa45 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx @@ -0,0 +1,354 @@ +#include "FaserActsKalmanFilter/KalmanFitterTool.h" + +#include "FaserActsGeometry/FASERMagneticFieldWrapper.h" + +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "TrackerIdentifier/FaserSCT_ID.h" + +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" + + +KalmanFitterTool::KalmanFitterTool(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent) {} + + +StatusCode KalmanFitterTool::initialize() { + ATH_CHECK(m_fieldCondObjInputKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + if (m_statesWriter && !m_noDiagnostics) ATH_CHECK(m_trajectoryStatesWriterTool.retrieve()); + if (m_summaryWriter && !m_noDiagnostics) ATH_CHECK(m_trajectorySummaryWriterTool.retrieve()); + m_fit = makeTrackFitterFunction(m_trackingGeometryTool->trackingGeometry()); + if (m_actsLogging == "VERBOSE" && !m_noDiagnostics) { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE); + } else if (m_actsLogging == "DEBUG" && !m_noDiagnostics) { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG); + } else { + m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO); + } + return StatusCode::SUCCESS; +} + + +StatusCode KalmanFitterTool::finalize() { + return StatusCode::SUCCESS; +} + +std::unique_ptr<Trk::Track> +KalmanFitterTool::fit(const EventContext &ctx, const Acts::GeometryContext &gctx, const Trk::Track &inputTrack, + std::vector<FaserActsRecMultiTrajectory> & /*trajectories*/, + const Acts::BoundVector& inputVector, bool isMC, double origin) const { + std::unique_ptr<Trk::Track> newTrack = nullptr; + std::vector<FaserActsRecMultiTrajectory> myTrajectories; + + if (!inputTrack.measurementsOnTrack() || inputTrack.measurementsOnTrack()->size() < m_minMeasurements) { + ATH_MSG_DEBUG("Input track has no or too little measurements and cannot be fitted"); + return nullptr; + } + + if (!inputTrack.trackParameters() || inputTrack.trackParameters()->empty()) { + ATH_MSG_DEBUG("Input track has no track parameters and cannot be fitted"); + return nullptr; + } + + + auto pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1}); + + Acts::MagneticFieldContext mfContext = getMagneticFieldContext(ctx); + Acts::CalibrationContext calibContext = Acts::CalibrationContext(); + + auto [sourceLinks, measurements] = getMeasurementsFromTrack(inputTrack); + auto trackParameters = getParametersFromTrack(inputTrack.trackParameters()->front(), inputVector, origin); + ATH_MSG_DEBUG("trackParameters: " << trackParameters.parameters().transpose()); + ATH_MSG_DEBUG("position: " << trackParameters.position(gctx).transpose()); + ATH_MSG_DEBUG("momentum: " << trackParameters.momentum().transpose()); + ATH_MSG_DEBUG("charge: " << trackParameters.charge()); + + Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic> + kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements), + Acts::VoidOutlierFinder(), Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger}, + Acts::PropagatorPlainOptions(), &(*pSurface)); + kfOptions.multipleScattering = false; + kfOptions.energyLoss = false; + + ATH_MSG_DEBUG("Invoke fitter"); + auto result = (*m_fit)(sourceLinks, trackParameters, kfOptions); + + if (result.ok()) { + const auto& fitOutput = result.value(); + if (fitOutput.fittedParameters) { + const auto& params = fitOutput.fittedParameters.value(); + ATH_MSG_DEBUG("ReFitted parameters"); + ATH_MSG_DEBUG(" params: " << params.parameters().transpose()); + ATH_MSG_DEBUG(" position: " << params.position(gctx).transpose()); + ATH_MSG_DEBUG(" momentum: " << params.momentum().transpose()); + ATH_MSG_DEBUG(" charge: " << params.charge()); + using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>; + IndexedParams indexedParams; + indexedParams.emplace(fitOutput.lastMeasurementIndex, std::move(params)); + std::vector<size_t> trackTips; + trackTips.reserve(1); + trackTips.emplace_back(fitOutput.lastMeasurementIndex); + // trajectories.emplace_back(std::move(fitOutput.fittedStates), + // std::move(trackTips), + // std::move(indexedParams)); + myTrajectories.emplace_back(std::move(fitOutput.fittedStates), + std::move(trackTips), + std::move(indexedParams)); + } else { + ATH_MSG_DEBUG("No fitted parameters for track"); + } + newTrack = makeTrack(gctx, result); + } + + if (m_statesWriter && !m_noDiagnostics) { + StatusCode statusStatesWriterTool = m_trajectoryStatesWriterTool->write(gctx, myTrajectories, isMC); + } + if (m_summaryWriter && !m_noDiagnostics) { + StatusCode statusSummaryWriterTool = m_trajectorySummaryWriterTool->write(gctx, myTrajectories, isMC); + } + + return newTrack; +} + + +namespace { + +using Updater = Acts::GainMatrixUpdater; +using Smoother = Acts::GainMatrixSmoother; +using Stepper = Acts::EigenStepper<>; +using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; +using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>; + +struct TrackFitterFunctionImpl + : public KalmanFitterTool::TrackFitterFunction { + Fitter trackFitter; + + TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {} + + KalmanFitterTool::TrackFitterResult operator()( + const std::vector<IndexSourceLink> &sourceLinks, + const KalmanFitterTool::TrackParameters &initialParameters, + const KalmanFitterTool::TrackFitterOptions &options) + const override { + return trackFitter.fit(sourceLinks, initialParameters, options); + }; +}; + +} // namespace + + +std::shared_ptr<KalmanFitterTool::TrackFitterFunction> +KalmanFitterTool::makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) { + auto magneticField = std::make_shared<FASERMagneticFieldWrapper>(); + auto stepper = Stepper(std::move(magneticField)); + Acts::Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + Fitter trackFitter(std::move(propagator)); + return std::make_shared<TrackFitterFunctionImpl>(std::move(trackFitter)); +} + + +Acts::MagneticFieldContext KalmanFitterTool::getMagneticFieldContext(const EventContext& ctx) const { + SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx}; + if (!readHandle.isValid()) { + std::stringstream msg; + msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << "."; + throw std::runtime_error(msg.str()); + } + const FaserFieldCacheCondObj* fieldCondObj{*readHandle}; + return Acts::MagneticFieldContext(fieldCondObj); +} + + +std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>> +KalmanFitterTool::getMeasurementsFromTrack(const Trk::Track &track) const { + const int kSize = 1; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + for (const Trk::MeasurementBase *meas : *track.measurementsOnTrack()) { + const auto* clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(meas); + const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + if (clusterOnTrack) { + Identifier id = clusterOnTrack->identify(); + Identifier waferId = m_idHelper->wafer_id(id); + if (identifierMap->count(waferId) != 0) { + Acts::GeometryIdentifier geoId = identifierMap->at(waferId); + IndexSourceLink sourceLink(geoId, measurements.size(), cluster); + Eigen::Matrix<double, 1, 1> pos {meas->localParameters()[Trk::locX],}; + Eigen::Matrix<double, 1, 1> cov {0.08 * 0.08 / 12}; + ThisMeasurement actsMeas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(actsMeas)); + } + } + } + return std::make_tuple(sourceLinks, measurements); +} + + +Acts::BoundTrackParameters +KalmanFitterTool::getParametersFromTrack(const Trk::TrackParameters *inputParameters, + const Acts::BoundVector& inputVector, double origin) const { + using namespace Acts::UnitLiterals; + std::shared_ptr<const Acts::Surface> pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1}); + + auto atlasParam = inputParameters->parameters(); + auto center = inputParameters->associatedSurface().center(); + // Acts::BoundVector params {center[Trk::locY], center[Trk::locX], + // atlasParam[Trk::phi0], atlasParam[Trk::theta], + // charge / (inputParameters->momentum().norm() * 1_MeV), + // 0.}; + Acts::BoundVector params; + if (inputVector == Acts::BoundVector::Zero()) { + params(0.0) = center[Trk::locY]; + params(1.0) = center[Trk::locX]; + params(2.0) = atlasParam[Trk::phi0]; + params(3.0) = atlasParam[Trk::theta]; + // input charge is 1 for positively charged particles and 0 for negatively charged particles! + double charge = 2 * inputParameters->charge() - 1; + params(4.0) = charge / (inputParameters->momentum().norm() * 1_MeV); + params(5.0) = 0.; + } else { + params = inputVector; + } + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Identity(); + cov.topLeftCorner(5, 5) = *inputParameters->covariance(); + + for(int i=0; i < cov.rows(); i++){ + cov(i, 4) = cov(i, 4)/1_MeV; + } + for(int i=0; i < cov.cols(); i++){ + cov(4, i) = cov(4, i)/1_MeV; + } + for (int i = 0; i < 6; ++i) { + cov(i,i) = m_seedCovarianceScale * cov(i,i); + } + + return Acts::BoundTrackParameters(pSurface, params, inputParameters->charge(), cov); +} + + +std::unique_ptr<Trk::Track> +KalmanFitterTool::makeTrack(const Acts::GeometryContext &geoCtx, TrackFitterResult& fitResult) const { + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + std::unique_ptr<Trk::Track> newtrack = nullptr; + //Get the fit output object + const auto& fitOutput = fitResult.value(); + if (fitOutput.fittedParameters) { + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam; + // Loop over all the output state to create track state + fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndex, [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + // We need to determine the type of state + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + // State is a hole (no associated measurement), use predicted para meters + if (flag[Acts::TrackStateFlag::HoleFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), + state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + // The state was tagged as an outlier, use filtered parameters + else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + // The state is a measurement state, use smoothed parameters + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam))); + // const auto& psurface=actsParam.referenceSurface(); + // Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]); + // const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]); + // auto pos=actsParam.position(tgContext); + parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* measState = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit(); + if (fitCluster->detectorElement() != nullptr) { + measState = new Tracker::FaserSCT_ClusterOnTrack{ + fitCluster, + Trk::LocalParameters{ + Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2} + }, + fitCluster->localCovariance(), + m_idHelper->wafer_hash(fitCluster->detectorElement()->identify()) + }; + } + } + double nDoF = state.calibratedSize(); + const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF); + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern); + // If a state was successfully created add it to the trajectory + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + // Create the track using the states + const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + // Trk::FitQuality* q = nullptr; + // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter ); //Mark the fitter as KalmanFitter + newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr); + } + return newtrack; +} + + +const Trk::TrackParameters* +KalmanFitterTool::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const { + using namespace Acts::UnitLiterals; + std::optional<AmgSymMatrix(5)> cov = std::nullopt; + if (actsParameter.covariance()){ + AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5)); + // Convert the covariance matrix to GeV + for(int i=0; i < newcov.rows(); i++){ + newcov(i, 4) = newcov(i, 4)*1_MeV; + } + for(int i=0; i < newcov.cols(); i++){ + newcov(4, i) = newcov(4, i)*1_MeV; + } + cov = std::optional<AmgSymMatrix(5)>(newcov); + } + const Amg::Vector3D& pos=actsParameter.position(gctx); + double tphi=actsParameter.get<Acts::eBoundPhi>(); + double ttheta=actsParameter.get<Acts::eBoundTheta>(); + double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV; + double p = std::abs(1. / tqOverP); + Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta)); + const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov); + return curv; +} + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f10448452d2a9161dab5207963a514135475efce --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.cxx @@ -0,0 +1,120 @@ +#include "FaserActsKalmanFilter/MultiTrackFinderTool.h" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrkTrack/Track.h" +#include "TrkTrack/TrackStateOnSurface.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +//#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include <algorithm> +#include <vector> + + +MultiTrackFinderTool::MultiTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode MultiTrackFinderTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode MultiTrackFinderTool::run() { + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + std::map<int, std::vector<Tracklet>> tracklets; + for (const Trk::Track* track : *trackCollection) { + std::vector<Identifier> ids; + std::vector<Acts::GeometryIdentifier> geoIds; + std::vector<double> positions; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + auto fitParameters = track->trackParameters()->front(); + const Amg::Vector3D fitPosition = fitParameters->position(); + const Amg::Vector3D fitMomentum = fitParameters->momentum(); + ATH_MSG_DEBUG(fitPosition.x() << ", " << fitPosition.y() << fitPosition.z()); + for (const Trk::TrackStateOnSurface* state : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> ( state->measurementOnTrack()); + if (clusterOnTrack) { + const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + clusters.push_back(cluster); + Identifier id = cluster->detectorElement()->identify(); + ids.push_back(id); + Acts::GeometryIdentifier geoId = identifierMap->at(id); + geoIds.push_back(geoId); + const auto& par = cluster->localPosition(); + positions.push_back(par.x()); + } + } + auto tracklet = Tracklet(ids, geoIds, positions, fitPosition, clusters); + int station = m_idHelper->station(ids.front()); + tracklets[station].push_back(tracklet); + } + + // create all combinations of tracklets + std::vector<ProtoTrack> protoTracks {}; + for (const Tracklet& t1 : tracklets[1]) { + for (const Tracklet& t2 : tracklets[2]) { + for (const Tracklet& t3 : tracklets[3]) { + protoTracks.push_back(ProtoTrack(t1, t2, t3)); + } + } + } + + // sort proto tracks by their chi2 value and select best two tracks + std::sort(protoTracks.begin(), protoTracks.end(), sort_chi2()); + + std::vector<std::vector<IndexSourceLink>> sourceLinkVector; + std::vector<std::vector<Measurement>> measurementVector; + std::vector<std::map<Index, Identifier>> idLinkVector; + std::vector<Acts::CurvilinearTrackParameters> paramVector; + std::vector<std::vector<const Tracker::FaserSCT_Cluster*>> clusterVector; + int n_protoTracks = std::min((int)protoTracks.size(), 2); + for (int i = 0; i < n_protoTracks; ++i) { + // FIXME check if protoTrack exists + ProtoTrack track = protoTracks[i]; + auto [measurements, sourceLinks, idLinks, clusters] = track.run(); + auto params = track.initialTrackParameters(m_covLoc0, m_covLoc1, m_covPhi, m_covTheta, m_covQOverP, m_covTime); + sourceLinkVector.push_back(sourceLinks); + measurementVector.push_back(measurements); + idLinkVector.push_back(idLinks); + paramVector.push_back(params); + clusterVector.push_back(clusters); + } + + m_sourceLinks = std::make_shared<std::vector<std::vector<IndexSourceLink>>>(sourceLinkVector); + m_measurements = std::make_shared<std::vector<std::vector<Measurement>>>(measurementVector); + m_idLinks = std::make_shared<std::vector<std::map<Index, Identifier>>>(idLinkVector); + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(paramVector); + m_clusters = std::make_shared<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>>(clusterVector); + + // create initial surface + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, 0}, Acts::Vector3{0, 0, 1}); + + return StatusCode::SUCCESS; +} + + +StatusCode MultiTrackFinderTool::finalize() { + return StatusCode::SUCCESS; +} + + + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.cxx new file mode 100644 index 0000000000000000000000000000000000000000..998269a83cf6228092dd3b31987696f929820e4e --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.cxx @@ -0,0 +1,3 @@ +#include "FaserActsKalmanFilter/MyAmbiguitySolver.h" + + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c2648161b595230fc626544d4e9dd11fdf4118e5 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx @@ -0,0 +1,143 @@ +#include "FaserActsKalmanFilter/MyTrackSeedTool.h" + +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" + + +MyTrackSeedTool::MyTrackSeedTool( const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) {} + + +StatusCode MyTrackSeedTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_clusterContainerKey.initialize()); + ATH_CHECK(m_spacePointContainerKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode MyTrackSeedTool::run() { + + // create track seeds for multiple tracks + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey}; + ATH_CHECK(clusterContainer.isValid()); + + SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey}; + ATH_CHECK(spacePointContainer.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + std::map<Identifier, const Tracker::FaserSCT_SpacePoint*> spacePointMap {}; + for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) { + for (const Tracker::FaserSCT_SpacePoint *spacePoint: *spacePointCollection) { + Identifier id1 = spacePoint->cluster1()->identify(); + spacePointMap[id1] = spacePoint; + Identifier id2 = spacePoint->cluster2()->identify(); + spacePointMap[id2] = spacePoint; + } + } + + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::map<Index, Identifier> identifierLinkMap; + std::vector<const Tracker::FaserSCT_SpacePoint*> spacePoints {}; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) { + for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) { + Identifier id = cluster->detectorElement()->identify(); + identifierLinkMap[measurements.size()] = id; + if (identifierMap->count(id) != 0) { + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size(), cluster); + // create measurement + const auto& par = cluster->localPosition(); + Eigen::Matrix<double, 1, 1> pos {par.x(),}; + Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,}; + ThisMeasurement meas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + clusters.push_back(cluster); + if (spacePointMap.count(cluster->identify()) > 0) { + spacePoints.push_back(spacePointMap[cluster->identify()]); + } else { + spacePoints.push_back(nullptr); + } + } + } + } + + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + std::map<int, std::vector<Amg::Vector3D>> stationHitMap {}; + for (const Trk::Track* track : *trackCollection) { + const Amg::Vector3D position = track->trackParameters()->front()->position(); + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + int station = m_idHelper->station(clusterOnTrack->identify()); + stationHitMap[station].push_back(position); + break; + } + } + } + + + std::vector<Acts::CurvilinearTrackParameters> initParams {}; + for (size_t i = 0; i < stationHitMap.size(); ++i) { + for (size_t j = i+1; j < stationHitMap.size(); ++j) { + for (const auto &p1 : stationHitMap[i]) { + for (const auto &p2 : stationHitMap[j]) { + initParams.push_back(get_params(p1, p2, cov, m_origin)); + } + } + } + } + + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams); + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1}); + m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters); + m_spacePoints = std::make_shared<std::vector<const Tracker::FaserSCT_SpacePoint*>>(spacePoints); + // m_seedClusters = std::make_shared<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>({}); + return StatusCode::SUCCESS; +} + + +StatusCode MyTrackSeedTool::finalize() { + return StatusCode::SUCCESS; +} + + +Acts::CurvilinearTrackParameters MyTrackSeedTool::get_params(const Amg::Vector3D& p1, const Amg::Vector3D& p2, const Acts::BoundSymMatrix& cov, double origin) { + Acts::Vector3 dir = p2 - p1; + Acts::Vector3 pos = p1 - (p1.z() - origin)/dir.z() * dir; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + return Acts::CurvilinearTrackParameters(pos4, dir, 10000000, 1, cov); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c545c551adeb640a985ab4999d0864ecd817fb7c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx @@ -0,0 +1,183 @@ +#include "FaserActsKalmanFilter/PerformanceWriterTool.h" +#include "FaserActsKalmanFilter/TrackClassification.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "TFile.h" + + +PerformanceWriterTool::PerformanceWriterTool( + const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent) {} + + +StatusCode PerformanceWriterTool::initialize() { + ATH_CHECK(m_extrapolationTool.retrieve()); + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_simDataCollectionKey.initialize()); + + if (!m_noDiagnostics) { + std::string filePath = m_filePath; + m_outputFile = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_outputFile == nullptr) { + ATH_MSG_WARNING("Unable to open output file at " << m_filePath); + return StatusCode::RECOVERABLE; + } + } + + // initialize the residual and efficiency plots tool + m_resPlotTool.book(m_resPlotCache); + m_effPlotTool.book(m_effPlotCache); + m_summaryPlotTool.book(m_summaryPlotCache); + return StatusCode::SUCCESS; +} + + +StatusCode PerformanceWriterTool::finalize() { + if (!m_noDiagnostics) { + // fill residual and pull details into additional hists + m_resPlotTool.refinement(m_resPlotCache); + if (m_outputFile) { + m_outputFile->cd(); + m_resPlotTool.write(m_resPlotCache); + m_effPlotTool.write(m_effPlotCache); + m_summaryPlotTool.write(m_summaryPlotCache); + ATH_MSG_VERBOSE("Wrote performance plots to '" << m_outputFile->GetPath() << "'"); + } + + m_resPlotTool.clear(m_resPlotCache); + m_effPlotTool.clear(m_effPlotCache); + m_summaryPlotTool.clear(m_summaryPlotCache); + if (m_outputFile) { + m_outputFile->Close(); + } + } + return StatusCode::SUCCESS; +} + + +StatusCode PerformanceWriterTool::write(const Acts::GeometryContext& geoContext, const TrajectoriesContainer& trajectories) { + const EventContext& ctx = Gaudi::Hive::currentContext(); + + SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey, ctx}; + ATH_CHECK(mcEvents.isValid()); + if (mcEvents->size() != 1) { + ATH_MSG_ERROR("There should be exactly one event in the McEventCollection."); + return StatusCode::FAILURE; + } + + std::map<int, const HepMC::GenParticle*> particles {}; + for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) { + particles[particle->barcode()] = particle; + } + + SG::ReadHandle<TrackerSimDataCollection> simData {m_simDataCollectionKey, ctx}; + ATH_CHECK(simData.isValid()); + + // Truth particles with corresponding reconstructed tracks + std::vector<int> reconParticleIds; + reconParticleIds.reserve(particles.size()); + // For each particle within a track, how many hits did it contribute + std::vector<ParticleHitCount> particleHitCounts; + + + // Loop over all trajectories + for (size_t itraj = 0; itraj < trajectories.size(); ++itraj) { + const auto& traj = trajectories[itraj]; + + if (traj.empty()) { + ATH_MSG_WARNING("Empty trajectories object " << itraj); + continue; + } + + // The trajectory entry indices and the multiTrajectory + const auto& trackTips = traj.tips(); + const auto& mj = traj.multiTrajectory(); + + // Check the size of the trajectory entry indices. For track fitting, there + // should be at most one trajectory + if (trackTips.size() > 1) { + ATH_MSG_ERROR("Track fitting should not result in multiple trajectories."); + return StatusCode::FAILURE; + } + // Get the entry index for the single trajectory + auto trackTip = trackTips.front(); + + // Select reco track with fitted parameters + if (not traj.hasTrackParameters(trackTip)) { + ATH_MSG_WARNING("No fitted track parameters."); + continue; + } + const auto& fittedParameters = traj.trackParameters(trackTip); + + // Get the majority truth particle for this trajectory + identifyContributingParticles(*simData, traj, trackTip, particleHitCounts); + if (particleHitCounts.empty()) { + ATH_MSG_WARNING("No truth particle associated with this trajectory."); + continue; + } + // Find the truth particle for the majority barcode + const auto ip = particles.find(particleHitCounts.front().particleId); + if (ip == particles.end()) { + ATH_MSG_WARNING("Majority particle not found in the particles collection."); + continue; + } + + // Record this majority particle ID of this trajectory + reconParticleIds.push_back(ip->first); + const HepMC::GenParticle* truthParticle = ip->second; + std::unique_ptr<const Acts::BoundTrackParameters> truthParameters + = extrapolateToReferenceSurface(ctx, truthParticle); + // Fill the residual plots + if (truthParameters) { + m_resPlotTool.fill(m_resPlotCache, geoContext, std::move(truthParameters), fittedParameters); + } else { + ATH_MSG_WARNING("Can not extrapolate truth parameters to reference surface."); + } + // Collect the trajectory summary info + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); + // Fill the trajectory summary info + m_summaryPlotTool.fill(m_summaryPlotCache, fittedParameters, trajState.nStates, trajState.nMeasurements, + trajState.nOutliers, trajState.nHoles, trajState.nSharedHits); + } + + // Fill the efficiency, defined as the ratio between number of tracks with fitted parameter and total truth tracks + // (assumes one truth partilce has one truth track) + for (const auto& particle : particles) { + bool isReconstructed = false; + // Find if the particle has been reconstructed + auto it = std::find(reconParticleIds.begin(), reconParticleIds.end(), particle.first); + if (it != reconParticleIds.end()) { + isReconstructed = true; + } + m_effPlotTool.fill(m_effPlotCache, particle.second, isReconstructed); + } + + return StatusCode::SUCCESS; +} + +std::unique_ptr<const Acts::BoundTrackParameters> PerformanceWriterTool::extrapolateToReferenceSurface( + const EventContext& ctx, const HepMC::GenParticle* particle) const { + const HepMC::FourVector &vertex = particle->production_vertex()->position(); + const HepMC::FourVector &momentum = particle->momentum(); + + // The coordinate system of the Acts::PlaneSurface is defined as + // T = Z = normal, U = X x T = -Y, V = T x U = x + auto startSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, vertex.z()), Acts::Vector3(0, 0, 1)); + auto targetSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, 0), Acts::Vector3(0, 0, -1)); + Acts::BoundVector params = Acts::BoundVector::Zero(); + params[Acts::eBoundLoc0] = -vertex.y(); + params[Acts::eBoundLoc1] = vertex.x(); + params[Acts::eBoundPhi] = momentum.phi(); + params[Acts::eBoundTheta] = momentum.theta(); + // FIXME get charge of HepMC::GenParticle, the following does not work, e.g. for pions + double charge = particle->pdg_id() > 0 ? -1 : 1; + double MeV2GeV = 1e-3; + params[Acts::eBoundQOverP] = charge / (momentum.rho() * MeV2GeV); + params[Acts::eBoundTime] = vertex.t(); + Acts::BoundTrackParameters startParameters(std::move(startSurface), params, charge); + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters = + m_extrapolationTool->propagate(ctx, startParameters, *targetSurface); + return targetParameters; +} \ No newline at end of file diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0d50d843ea075ab3d3799dccdc6e2ba46cd74127 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.cxx @@ -0,0 +1,92 @@ +#include "FaserActsKalmanFilter/PlotHelpers.h" +#include <cassert> + +namespace PlotHelpers { + +TH1F* bookHisto(const char* histName, const char* histTitle, + const Binning& varBinning) { + TH1F* hist = new TH1F(histName, histTitle, varBinning.nBins, varBinning.min, + varBinning.max); + hist->GetXaxis()->SetTitle(varBinning.title.c_str()); + hist->GetYaxis()->SetTitle("Entries"); + hist->Sumw2(); + return hist; +} + +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TH2F* hist = new TH2F(histName, histTitle, varXBinning.nBins, varXBinning.min, + varXBinning.max, varYBinning.nBins, varYBinning.min, + varYBinning.max); + hist->GetXaxis()->SetTitle(varXBinning.title.c_str()); + hist->GetYaxis()->SetTitle(varYBinning.title.c_str()); + hist->Sumw2(); + return hist; +} + +void fillHisto(TH1F* hist, float value, float weight) { + assert(hist != nullptr); + hist->Fill(value, weight); +} + +void fillHisto(TH2F* hist, float xValue, float yValue, float weight) { + assert(hist != nullptr); + hist->Fill(xValue, yValue, weight); +} + +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist) { + // evaluate mean and width via the Gauss fit + assert(inputHist != nullptr); + if (inputHist->GetEntries() > 0) { + TFitResultPtr r = inputHist->Fit("gaus", "QS0"); + if (r.Get() and ((r->Status() % 1000) == 0)) { + // fill the mean and width into 'j'th bin of the meanHist and widthHist, + // respectively + meanHist->SetBinContent(j, r->Parameter(1)); + meanHist->SetBinError(j, r->ParError(1)); + widthHist->SetBinContent(j, r->Parameter(2)); + widthHist->SetBinError(j, r->ParError(2)); + } + } +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, const Binning& varBinning) { + TEfficiency* efficiency = new TEfficiency(effName, effTitle, varBinning.nBins, + varBinning.min, varBinning.max); + return efficiency; +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TEfficiency* efficiency = new TEfficiency( + effName, effTitle, varXBinning.nBins, varXBinning.min, varXBinning.max, + varYBinning.nBins, varYBinning.min, varYBinning.max); + return efficiency; +} + +void fillEff(TEfficiency* efficiency, float value, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, value); +} + +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, xValue, yValue); +} + +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TProfile* prof = + new TProfile(profName, profTitle, varXBinning.nBins, varXBinning.min, + varXBinning.max, varYBinning.min, varYBinning.max); + prof->GetXaxis()->SetTitle(varXBinning.title.c_str()); + prof->GetYaxis()->SetTitle(varYBinning.title.c_str()); + return prof; +} + +void fillProf(TProfile* profile, float xValue, float yValue, float weight) { + assert(profile != nullptr); + profile->Fill(xValue, yValue, weight); +} + +} // namespace PlotHelpers diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5ec0dfc1a1d430208b10c14a7c368ac89ac08ff3 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.cxx @@ -0,0 +1,108 @@ +#include "FaserActsKalmanFilter/ProtoTrackWriterTool.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include <TFile.h> +#include <TTree.h> + + +ProtoTrackWriterTool::ProtoTrackWriterTool( + const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent) {} + + +StatusCode ProtoTrackWriterTool::initialize() { + + ATH_CHECK(m_trackFinderTool.retrieve()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + std::string filePath = m_filePath; + m_file = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_file == nullptr) { + ATH_MSG_ERROR("Unable to open output file at " << m_filePath); + return StatusCode::FAILURE; + } + m_file->cd(); + + m_params = new TTree("parameters", "parameters"); + m_params->Branch("run_number", &m_run_number, "run_number/I"); + m_params->Branch("event_number", &m_event_number, "event_number/I"); + m_params->Branch("x", &m_x, "x/D"); + m_params->Branch("y", &m_y, "y/D"); + m_params->Branch("z", &m_z, "z/D"); + m_params->Branch("px", &m_px, "px/D"); + m_params->Branch("py", &m_py, "py/D"); + m_params->Branch("pz", &m_pz, "pz/D"); + + m_meas = new TTree("measurements", "measurements"); + m_meas->Branch("run_number", &m_run_number, "run_number/I"); + m_meas->Branch("event_number", &m_event_number, "event_number/I"); + m_meas->Branch("station", &m_station, "station/I"); + m_meas->Branch("layer", &m_layer, "layer/I"); + m_meas->Branch("phi", &m_phi, "phi/I"); + m_meas->Branch("eta", &m_eta, "eta/I"); + m_meas->Branch("side", &m_side, "side/I"); + m_meas->Branch("meas_eLOC0", &m_meas_eLOC0, "meas_eLOC0/D"); + m_meas->Branch("meas_eLOC1", &m_meas_eLOC1, "meas_eLOC1/D"); + + return StatusCode::SUCCESS; +} + + +StatusCode ProtoTrackWriterTool::finalize() { + m_file->cd(); + m_params->Write(); + m_meas->Write(); + return StatusCode::SUCCESS; +} + + +StatusCode ProtoTrackWriterTool::write( + std::shared_ptr<const Acts::CurvilinearTrackParameters> protoTrackParameters, + std::shared_ptr<std::vector<Measurement>> measurements, + const Acts::GeometryContext& geoctx) const { + + EventContext ctx = Gaudi::Hive::currentContext(); + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + // flip key-value pairs of identifier map + std::map<Acts::GeometryIdentifier, Identifier> geoIdentifierMap; + for (const std::pair<const Identifier, Acts::GeometryIdentifier>& identifierPair : *identifierMap) { + geoIdentifierMap[identifierPair.second] = identifierPair.first; + } + + Acts::Vector3 position = protoTrackParameters->position(geoctx); + Acts::Vector3 direction = protoTrackParameters->momentum(); + m_x = position.x(); + m_y = position.y(); + m_z = position.z(); + m_px = direction.x(); + m_py = direction.y(); + m_pz = direction.z(); + m_params->Fill(); + + for (const Measurement& variantMeasurement : *measurements) { + // auto meas = std::get<Acts::Measurement<IndexSourceLink, Acts::BoundIndices, 2>>(variantMeasurement); + std::visit([&](const auto& meas) { + Acts::GeometryIdentifier geoId = meas.sourceLink().geometryId(); + Identifier id = geoIdentifierMap.at(geoId); + m_station = m_idHelper->station(id); + m_layer = m_idHelper->layer(id); + m_phi = m_idHelper->phi_module(id); + m_eta = m_idHelper->eta_module(id); + m_side = m_idHelper->side(id); + auto params = meas.parameters(); + m_meas_eLOC0 = params[Acts::eBoundLoc0]; + // write out as many variables as there are + // m_meas_eLOC1 = params[Acts::eBoundLoc1]; + m_meas->Fill(); + }, variantMeasurement); + }; + + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..47922a13e99abca49446668f9f8c180a86ebecdf --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.cxx @@ -0,0 +1,201 @@ +#include "FaserActsKalmanFilter/ResPlotTool.h" +#include "Acts/Utilities/Helpers.hpp" +#include "HepMC/GenVertex.h" + +void ResPlotTool::book(ResPlotTool::ResPlotCache& resPlotCache) const { + PlotHelpers::Binning bEta = m_varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_varBinning.at("Pt"); + PlotHelpers::Binning bPull = m_varBinning.at("Pull"); + std::cout << "DEBUG: Initialize the histograms for residual and pull plots" << std::endl; + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_paramNames.at(parID); + std::string parResidual = "Residual_" + parName; + // Binning for residual is parameter dependent + PlotHelpers::Binning bResidual = m_varBinning.at(parResidual); + + + // residual distributions + resPlotCache.res[parName] = PlotHelpers::bookHisto( + Form("res_%s", parName.c_str()), + Form("Residual of %s", parName.c_str()), bResidual); + // residual vs eta scatter plots + resPlotCache.res_vs_eta[parName] = PlotHelpers::bookHisto( + Form("res_%s_vs_eta", parName.c_str()), + Form("Residual of %s vs eta", parName.c_str()), bEta, bResidual); + // residual mean in each eta bin + resPlotCache.resMean_vs_eta[parName] = PlotHelpers::bookHisto( + Form("resmean_%s_vs_eta", parName.c_str()), + Form("Residual mean of %s", parName.c_str()), bEta); + // residual width in each eta bin + resPlotCache.resWidth_vs_eta[parName] = PlotHelpers::bookHisto( + Form("reswidth_%s_vs_eta", parName.c_str()), + Form("Residual width of %s", parName.c_str()), bEta); + // residual vs pT scatter plots + resPlotCache.res_vs_pT[parName] = PlotHelpers::bookHisto( + Form("res_%s_vs_pT", parName.c_str()), + Form("Residual of %s vs pT", parName.c_str()), bPt, bResidual); + // residual mean in each pT bin + resPlotCache.resMean_vs_pT[parName] = PlotHelpers::bookHisto( + Form("resmean_%s_vs_pT", parName.c_str()), + Form("Residual mean of %s", parName.c_str()), bPt); + // residual width in each pT bin + resPlotCache.resWidth_vs_pT[parName] = PlotHelpers::bookHisto( + Form("reswidth_%s_vs_pT", parName.c_str()), + Form("Residual width of %s", parName.c_str()), bPt); + + // pull distritutions + resPlotCache.pull[parName] = PlotHelpers::bookHisto( + Form("pull_%s", parName.c_str()), + Form("Pull of %s", parName.c_str()), bPull); + // pull vs eta scatter plots + resPlotCache.pull_vs_eta[parName] = PlotHelpers::bookHisto( + Form("pull_%s_vs_eta", parName.c_str()), + Form("Pull of %s vs eta", parName.c_str()), bEta, bPull); + // pull mean in each eta bin + resPlotCache.pullMean_vs_eta[parName] = PlotHelpers::bookHisto( + Form("pullmean_%s_vs_eta", parName.c_str()), + Form("Pull mean of %s", parName.c_str()), bEta); + // pull width in each eta bin + resPlotCache.pullWidth_vs_eta[parName] = PlotHelpers::bookHisto( + Form("pullwidth_%s_vs_eta", parName.c_str()), + Form("Pull width of %s", parName.c_str()), bEta); + // pull vs pT scatter plots + resPlotCache.pull_vs_pT[parName] = PlotHelpers::bookHisto( + Form("pull_%s_vs_pT", parName.c_str()), + Form("Pull of %s vs pT", parName.c_str()), bPt, bPull); + // pull mean in each pT bin + resPlotCache.pullMean_vs_pT[parName] = PlotHelpers::bookHisto( + Form("pullmean_%s_vs_pT", parName.c_str()), + Form("Pull mean of %s", parName.c_str()), bPt); + // pull width in each pT bin + resPlotCache.pullWidth_vs_pT[parName] = PlotHelpers::bookHisto( + Form("pullwidth_%s_vs_pT", parName.c_str()), + Form("Pull width of %s", parName.c_str()), bPt); + } +} + +void ResPlotTool::write(const ResPlotCache &resPlotCache) const { + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_paramNames.at(parID); + if (resPlotCache.res.count(parName)) { + resPlotCache.res.at(parName)->Write(); + resPlotCache.res_vs_eta.at(parName)->Write(); + resPlotCache.resMean_vs_eta.at(parName)->Write(); + resPlotCache.resWidth_vs_eta.at(parName)->Write(); + resPlotCache.res_vs_pT.at(parName)->Write(); + resPlotCache.resMean_vs_pT.at(parName)->Write(); + resPlotCache.resWidth_vs_pT.at(parName)->Write(); + resPlotCache.pull.at(parName)->Write(); + resPlotCache.pull_vs_eta.at(parName)->Write(); + resPlotCache.pullMean_vs_eta.at(parName)->Write(); + resPlotCache.pullWidth_vs_eta.at(parName)->Write(); + resPlotCache.pull_vs_pT.at(parName)->Write(); + resPlotCache.pullMean_vs_pT.at(parName)->Write(); + resPlotCache.pullWidth_vs_pT.at(parName)->Write(); + } + } +} + +void ResPlotTool::clear(ResPlotCache &resPlotCache) const { + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_paramNames.at(parID); + if (resPlotCache.res.count(parName)) { + delete resPlotCache.res.at(parName); + delete resPlotCache.res_vs_eta.at(parName); + delete resPlotCache.resMean_vs_eta.at(parName); + delete resPlotCache.resWidth_vs_eta.at(parName); + delete resPlotCache.res_vs_pT.at(parName); + delete resPlotCache.resMean_vs_pT.at(parName); + delete resPlotCache.resWidth_vs_pT.at(parName); + delete resPlotCache.pull.at(parName); + delete resPlotCache.pull_vs_eta.at(parName); + delete resPlotCache.pullMean_vs_eta.at(parName); + delete resPlotCache.pullWidth_vs_eta.at(parName); + delete resPlotCache.pull_vs_pT.at(parName); + delete resPlotCache.pullMean_vs_pT.at(parName); + delete resPlotCache.pullWidth_vs_pT.at(parName); + } + } +} + +void ResPlotTool::fill( + ResPlotCache& resPlotCache, const Acts::GeometryContext& /*gctx*/, + std::unique_ptr<const Acts::BoundTrackParameters> truthParameters, + const Acts::BoundTrackParameters& fittedParameters) const { + using ParametersVector = Acts::BoundTrackParameters::ParametersVector; + using Acts::VectorHelpers::eta; + using Acts::VectorHelpers::perp; + // using Acts::VectorHelpers::phi; + // using Acts::VectorHelpers::theta; + + // get the fitted parameter (at perigee surface) and its error + auto trackParameter = fittedParameters.parameters(); + + // get the truth position and momentum + ParametersVector truthParameter = truthParameters->parameters(); + + // get the truth eta and pT + const auto truthEta = eta(truthParameters->momentum().normalized()); + const auto truthPt = truthParameters->absoluteMomentum() * perp(truthParameters->momentum().normalized()); + + // fill the histograms for residual and pull + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_paramNames.at(parID); + float residual = trackParameter[parID] - truthParameter[parID]; + PlotHelpers::fillHisto(resPlotCache.res.at(parName), residual); + PlotHelpers::fillHisto(resPlotCache.res_vs_eta.at(parName), truthEta, residual); + PlotHelpers::fillHisto(resPlotCache.res_vs_pT.at(parName), truthPt, residual); + + if (fittedParameters.covariance().has_value()) { + auto covariance = *fittedParameters.covariance(); + if (covariance(parID, parID) > 0) { + float pull = residual / sqrt(covariance(parID, parID)); + PlotHelpers::fillHisto(resPlotCache.pull[parName], pull); + PlotHelpers::fillHisto(resPlotCache.pull_vs_eta.at(parName), truthEta, pull); + PlotHelpers::fillHisto(resPlotCache.pull_vs_pT.at(parName), truthPt, pull); + } else { + std::cout << "WARNING: Fitted track parameter :" << parName << " has negative covariance = " << covariance(parID, parID) << std::endl; + } + } else { + std::cout << "WARNING: Fitted track parameter :" << parName << " has no covariance" << std::endl; + } + } +} + + +// get the mean and width of residual/pull in each eta/pT bin and fill them into histograms +void ResPlotTool::refinement(ResPlotTool::ResPlotCache& resPlotCache) const { + PlotHelpers::Binning bEta = m_varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_varBinning.at("Pt"); + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_paramNames.at(parID); + // refine the plots vs eta + for (int j = 1; j <= bEta.nBins; j++) { + TH1D* temp_res = resPlotCache.res_vs_eta.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Residual_vs_eta_Histo", j), j, j); + PlotHelpers::anaHisto(temp_res, j, + resPlotCache.resMean_vs_eta.at(parName), + resPlotCache.resWidth_vs_eta.at(parName)); + + TH1D* temp_pull = resPlotCache.pull_vs_eta.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Pull_vs_eta_Histo", j), j, j); + PlotHelpers::anaHisto(temp_pull, j, + resPlotCache.pullMean_vs_eta.at(parName), + resPlotCache.pullWidth_vs_eta.at(parName)); + } + + // refine the plots vs pT + for (int j = 1; j <= bPt.nBins; j++) { + TH1D* temp_res = resPlotCache.res_vs_pT.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Residual_vs_pT_Histo", j), j, j); + PlotHelpers::anaHisto(temp_res, j, resPlotCache.resMean_vs_pT.at(parName), + resPlotCache.resWidth_vs_pT.at(parName)); + + TH1D* temp_pull = resPlotCache.pull_vs_pT.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Pull_vs_pT_Histo", j), j, j); + PlotHelpers::anaHisto(temp_pull, j, + resPlotCache.pullMean_vs_pT.at(parName), + resPlotCache.pullWidth_vs_pT.at(parName)); + } + } +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5378fc080cb49628248d4a7eda2e9206d6c016ba --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx @@ -0,0 +1,725 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "Acts/EventData/detail/TransformationBoundToFree.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "FaserActsKalmanFilter/TrackClassification.h" +#include <TFile.h> +#include <TTree.h> + +constexpr float NaNfloat = std::numeric_limits<float>::quiet_NaN(); +constexpr float NaNint = std::numeric_limits<int>::quiet_NaN(); + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; +using Acts::VectorHelpers::theta; + +RootTrajectoryStatesWriterTool::RootTrajectoryStatesWriterTool( + const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent) {} + +StatusCode RootTrajectoryStatesWriterTool::initialize() { + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_simDataCollectionKey.initialize()); + ATH_CHECK(m_faserSiHitKey.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + + if (!m_noDiagnostics) { + std::string filePath = m_filePath; + std::string treeName = m_treeName; + m_outputFile = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_outputFile == nullptr) { + ATH_MSG_ERROR("Unable to open output file at " << m_filePath); + return StatusCode::FAILURE; + } + m_outputFile->cd(); + m_outputTree = new TTree(treeName.c_str(), treeName.c_str()); + if (m_outputTree == nullptr) { + ATH_MSG_ERROR("Unable to create TTree"); + return StatusCode::FAILURE; + } + + m_outputTree = new TTree("tree", "tree"); + + m_outputTree->Branch("event_nr", &m_eventNr); + m_outputTree->Branch("multiTraj_nr", &m_multiTrajNr); + m_outputTree->Branch("subTraj_nr", &m_subTrajNr); + + m_outputTree->Branch("t_x", &m_t_x); + m_outputTree->Branch("t_y", &m_t_y); + m_outputTree->Branch("t_z", &m_t_z); + m_outputTree->Branch("t_dx", &m_t_dx); + m_outputTree->Branch("t_dy", &m_t_dy); + m_outputTree->Branch("t_dz", &m_t_dz); + m_outputTree->Branch("t_eLOC0", &m_t_eLOC0); + m_outputTree->Branch("t_eLOC1", &m_t_eLOC1); + m_outputTree->Branch("t_ePHI", &m_t_ePHI); + m_outputTree->Branch("t_eTHETA", &m_t_eTHETA); + m_outputTree->Branch("t_eQOP", &m_t_eQOP); + m_outputTree->Branch("t_eT", &m_t_eT); + + m_outputTree->Branch("nStates", &m_nStates); + m_outputTree->Branch("nMeasurements", &m_nMeasurements); + m_outputTree->Branch("volume_id", &m_volumeID); + m_outputTree->Branch("layer_id", &m_layerID); + m_outputTree->Branch("module_id", &m_moduleID); + m_outputTree->Branch("station", &m_station); + m_outputTree->Branch("layer", &m_layer); + m_outputTree->Branch("phi_module", &m_phi_module); + m_outputTree->Branch("eta_module", &m_eta_module); + m_outputTree->Branch("side", &m_side); + m_outputTree->Branch("pathLength", &m_pathLength); + m_outputTree->Branch("l_x_hit", &m_lx_hit); + m_outputTree->Branch("l_y_hit", &m_ly_hit); + m_outputTree->Branch("g_x_hit", &m_x_hit); + m_outputTree->Branch("g_y_hit", &m_y_hit); + m_outputTree->Branch("g_z_hit", &m_z_hit); + m_outputTree->Branch("res_x_hit", &m_res_x_hit); + m_outputTree->Branch("res_y_hit", &m_res_y_hit); + m_outputTree->Branch("err_x_hit", &m_err_x_hit); + m_outputTree->Branch("err_y_hit", &m_err_y_hit); + m_outputTree->Branch("pull_x_hit", &m_pull_x_hit); + m_outputTree->Branch("pull_y_hit", &m_pull_y_hit); + m_outputTree->Branch("dim_hit", &m_dim_hit); + + m_outputTree->Branch("nPredicted", &m_nParams[0]); + m_outputTree->Branch("predicted", &m_hasParams[0]); + m_outputTree->Branch("eLOC0_prt", &m_eLOC0[0]); + m_outputTree->Branch("eLOC1_prt", &m_eLOC1[0]); + m_outputTree->Branch("ePHI_prt", &m_ePHI[0]); + m_outputTree->Branch("eTHETA_prt", &m_eTHETA[0]); + m_outputTree->Branch("eQOP_prt", &m_eQOP[0]); + m_outputTree->Branch("eT_prt", &m_eT[0]); + m_outputTree->Branch("res_eLOC0_prt", &m_res_eLOC0[0]); + m_outputTree->Branch("res_eLOC1_prt", &m_res_eLOC1[0]); + m_outputTree->Branch("res_ePHI_prt", &m_res_ePHI[0]); + m_outputTree->Branch("res_eTHETA_prt", &m_res_eTHETA[0]); + m_outputTree->Branch("res_eQOP_prt", &m_res_eQOP[0]); + m_outputTree->Branch("res_eT_prt", &m_res_eT[0]); + m_outputTree->Branch("err_eLOC0_prt", &m_err_eLOC0[0]); + m_outputTree->Branch("err_eLOC1_prt", &m_err_eLOC1[0]); + m_outputTree->Branch("err_ePHI_prt", &m_err_ePHI[0]); + m_outputTree->Branch("err_eTHETA_prt", &m_err_eTHETA[0]); + m_outputTree->Branch("err_eQOP_prt", &m_err_eQOP[0]); + m_outputTree->Branch("err_eT_prt", &m_err_eT[0]); + m_outputTree->Branch("pull_eLOC0_prt", &m_pull_eLOC0[0]); + m_outputTree->Branch("pull_eLOC1_prt", &m_pull_eLOC1[0]); + m_outputTree->Branch("pull_ePHI_prt", &m_pull_ePHI[0]); + m_outputTree->Branch("pull_eTHETA_prt", &m_pull_eTHETA[0]); + m_outputTree->Branch("pull_eQOP_prt", &m_pull_eQOP[0]); + m_outputTree->Branch("pull_eT_prt", &m_pull_eT[0]); + m_outputTree->Branch("g_x_prt", &m_x[0]); + m_outputTree->Branch("g_y_prt", &m_y[0]); + m_outputTree->Branch("g_z_prt", &m_z[0]); + m_outputTree->Branch("px_prt", &m_px[0]); + m_outputTree->Branch("py_prt", &m_py[0]); + m_outputTree->Branch("pz_prt", &m_pz[0]); + m_outputTree->Branch("eta_prt", &m_eta[0]); + m_outputTree->Branch("pT_prt", &m_pT[0]); + + m_outputTree->Branch("nFiltered", &m_nParams[1]); + m_outputTree->Branch("filtered", &m_hasParams[1]); + m_outputTree->Branch("eLOC0_flt", &m_eLOC0[1]); + m_outputTree->Branch("eLOC1_flt", &m_eLOC1[1]); + m_outputTree->Branch("ePHI_flt", &m_ePHI[1]); + m_outputTree->Branch("eTHETA_flt", &m_eTHETA[1]); + m_outputTree->Branch("eQOP_flt", &m_eQOP[1]); + m_outputTree->Branch("eT_flt", &m_eT[1]); + m_outputTree->Branch("res_eLOC0_flt", &m_res_eLOC0[1]); + m_outputTree->Branch("res_eLOC1_flt", &m_res_eLOC1[1]); + m_outputTree->Branch("res_ePHI_flt", &m_res_ePHI[1]); + m_outputTree->Branch("res_eTHETA_flt", &m_res_eTHETA[1]); + m_outputTree->Branch("res_eQOP_flt", &m_res_eQOP[1]); + m_outputTree->Branch("res_eT_flt", &m_res_eT[1]); + m_outputTree->Branch("err_eLOC0_flt", &m_err_eLOC0[1]); + m_outputTree->Branch("err_eLOC1_flt", &m_err_eLOC1[1]); + m_outputTree->Branch("err_ePHI_flt", &m_err_ePHI[1]); + m_outputTree->Branch("err_eTHETA_flt", &m_err_eTHETA[1]); + m_outputTree->Branch("err_eQOP_flt", &m_err_eQOP[1]); + m_outputTree->Branch("err_eT_flt", &m_err_eT[1]); + m_outputTree->Branch("pull_eLOC0_flt", &m_pull_eLOC0[1]); + m_outputTree->Branch("pull_eLOC1_flt", &m_pull_eLOC1[1]); + m_outputTree->Branch("pull_ePHI_flt", &m_pull_ePHI[1]); + m_outputTree->Branch("pull_eTHETA_flt", &m_pull_eTHETA[1]); + m_outputTree->Branch("pull_eQOP_flt", &m_pull_eQOP[1]); + m_outputTree->Branch("pull_eT_flt", &m_pull_eT[1]); + m_outputTree->Branch("g_x_flt", &m_x[1]); + m_outputTree->Branch("g_y_flt", &m_y[1]); + m_outputTree->Branch("g_z_flt", &m_z[1]); + m_outputTree->Branch("px_flt", &m_px[1]); + m_outputTree->Branch("py_flt", &m_py[1]); + m_outputTree->Branch("pz_flt", &m_pz[1]); + m_outputTree->Branch("eta_flt", &m_eta[1]); + m_outputTree->Branch("pT_flt", &m_pT[1]); + + m_outputTree->Branch("nSmoothed", &m_nParams[2]); + m_outputTree->Branch("smoothed", &m_hasParams[2]); + m_outputTree->Branch("eLOC0_smt", &m_eLOC0[2]); + m_outputTree->Branch("eLOC1_smt", &m_eLOC1[2]); + m_outputTree->Branch("ePHI_smt", &m_ePHI[2]); + m_outputTree->Branch("eTHETA_smt", &m_eTHETA[2]); + m_outputTree->Branch("eQOP_smt", &m_eQOP[2]); + m_outputTree->Branch("eT_smt", &m_eT[2]); + m_outputTree->Branch("res_eLOC0_smt", &m_res_eLOC0[2]); + m_outputTree->Branch("res_eLOC1_smt", &m_res_eLOC1[2]); + m_outputTree->Branch("res_ePHI_smt", &m_res_ePHI[2]); + m_outputTree->Branch("res_eTHETA_smt", &m_res_eTHETA[2]); + m_outputTree->Branch("res_eQOP_smt", &m_res_eQOP[2]); + m_outputTree->Branch("res_eT_smt", &m_res_eT[2]); + m_outputTree->Branch("err_eLOC0_smt", &m_err_eLOC0[2]); + m_outputTree->Branch("err_eLOC1_smt", &m_err_eLOC1[2]); + m_outputTree->Branch("err_ePHI_smt", &m_err_ePHI[2]); + m_outputTree->Branch("err_eTHETA_smt", &m_err_eTHETA[2]); + m_outputTree->Branch("err_eQOP_smt", &m_err_eQOP[2]); + m_outputTree->Branch("err_eT_smt", &m_err_eT[2]); + m_outputTree->Branch("pull_eLOC0_smt", &m_pull_eLOC0[2]); + m_outputTree->Branch("pull_eLOC1_smt", &m_pull_eLOC1[2]); + m_outputTree->Branch("pull_ePHI_smt", &m_pull_ePHI[2]); + m_outputTree->Branch("pull_eTHETA_smt", &m_pull_eTHETA[2]); + m_outputTree->Branch("pull_eQOP_smt", &m_pull_eQOP[2]); + m_outputTree->Branch("pull_eT_smt", &m_pull_eT[2]); + m_outputTree->Branch("g_x_smt", &m_x[2]); + m_outputTree->Branch("g_y_smt", &m_y[2]); + m_outputTree->Branch("g_z_smt", &m_z[2]); + m_outputTree->Branch("px_smt", &m_px[2]); + m_outputTree->Branch("py_smt", &m_py[2]); + m_outputTree->Branch("pz_smt", &m_pz[2]); + m_outputTree->Branch("eta_smt", &m_eta[2]); + m_outputTree->Branch("pT_smt", &m_pT[2]); + + m_outputTree->Branch("chi2", &m_chi2); + } + + return StatusCode::SUCCESS; +} + + +StatusCode RootTrajectoryStatesWriterTool::finalize() { + if (!m_noDiagnostics) { + m_outputFile->cd(); + m_outputTree->Write(); + m_outputFile->Close(); + } + return StatusCode::SUCCESS; +} + +StatusCode RootTrajectoryStatesWriterTool::write(const Acts::GeometryContext& gctx, const TrajectoriesContainer& trajectories, bool isMC) const { + + if (m_outputFile == nullptr) + return StatusCode::SUCCESS; + + // Get the event number + const EventContext& ctx = Gaudi::Hive::currentContext(); + m_eventNr = ctx.eventID().event_number(); + + std::vector<ParticleHitCount> particleHitCounts; + std::map<int, const HepMC::GenParticle*> particles {}; + std::map<std::pair<int, Identifier>, const FaserSiHit*> siHitMap; + + std::shared_ptr<TrackerSimDataCollection> simData {nullptr}; + + if (isMC) { + SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey, ctx}; + ATH_CHECK(mcEvents.isValid()); + if (mcEvents->size() != 1) { + ATH_MSG_ERROR("There should be exactly one event in the McEventCollection."); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("Found " << mcEvents->front()->particles_size() << " particles."); + for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) { + particles[particle->barcode()] = particle; + } + + SG::ReadHandle<TrackerSimDataCollection> simDataHandle {m_simDataCollectionKey, ctx}; + ATH_CHECK(simDataHandle.isValid()); + simData = std::make_shared<TrackerSimDataCollection>(*simDataHandle); + + SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_faserSiHitKey, ctx}; + ATH_CHECK(siHitCollection.isValid()); + for (const FaserSiHit& hit : *siHitCollection) { + int barcode = hit.trackNumber(); + Identifier id = m_idHelper->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor()); + siHitMap[std::make_pair(barcode, id)] = &hit; + } + } + + + // Loop over the trajectories + for (size_t itraj = 0; itraj < trajectories.size(); ++itraj) { + const auto& traj = trajectories[itraj]; + + if (traj.empty()) { + ATH_MSG_WARNING("Empty trajectories object " << itraj); + continue; + } + + // The trajectory index + m_multiTrajNr = itraj; + + // The trajectory entry indices and the multiTrajectory + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + + // Loop over the entry indices for the subtrajectories + for (unsigned int isubtraj = 0; isubtraj < trackTips.size(); ++isubtraj) { + // The subtrajectory index + m_subTrajNr = isubtraj; + // The entry index for this subtrajectory + const auto& trackTip = trackTips[isubtraj]; + // Collect the trajectory summary info + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); + m_nMeasurements = trajState.nMeasurements; + m_nStates = trajState.nStates; + + // Get the majority truth particle to this track + int barcode = NaNint; + int truthQ = NaNint; + float truthMomentum = NaNfloat; + float truthLOC0 = NaNfloat; + float truthLOC1 = NaNfloat; + float truthPHI = NaNfloat; + float truthTHETA = NaNfloat; + float truthQOP = NaNfloat; + float truthTIME = NaNfloat; + + if (isMC) { + truthQ = 1; + truthMomentum = 1; + identifyContributingParticles(*simData, traj, trackTip, particleHitCounts); + if (not particleHitCounts.empty()) { + // Get the barcode of the majority truth particle + barcode = particleHitCounts.front().particleId; + // Find the truth particle via the barcode + auto ip = particles.find(barcode); + if (ip != particles.end()) { + const auto& particle = ip->second; + ATH_MSG_DEBUG("Find the truth particle with barcode = " << barcode); + // Get the truth particle charge + // FIXME find better way to access charge of simulated particle, this does not work for + // pions which have a positive pdg code (211) and positive charge + truthQ = particle->pdg_id() > 0 ? -1 : 1; + truthMomentum = particle->momentum().rho() * m_MeV2GeV; + } else { + ATH_MSG_WARNING("Truth particle with barcode = " << barcode << " not found!"); + } + } + } + + // Get the trackStates on the trajectory + m_nParams = {0, 0, 0}; + using ConstTrackStateProxy = + Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + mj.visitBackwards(trackTip, [&](const ConstTrackStateProxy& state) { + // we only fill the track states with non-outlier measurement + auto typeFlags = state.typeFlags(); + if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + + const auto& surface = state.referenceSurface(); + + // get the truth hits corresponding to this trackState + Identifier id = state.uncalibrated().hit()->identify(); + Identifier waferId = m_idHelper->wafer_id(id); + // if (siHitMap.count(std::make_pair(barcode, waferId)) == 0) { + // ATH_MSG_WARNING("no FaserSiHit for hit with id " << id << " from particle " << barcode); + // return true; + // } + + if (isMC && siHitMap.count(std::make_pair(barcode, waferId)) != 0) { + const FaserSiHit* siHit = siHitMap.find(std::make_pair(barcode, waferId))->second; + HepGeom::Point3D localStartPos = siHit->localStartPosition(); + HepGeom::Point3D localEndPos = siHit->localEndPosition(); + HepGeom::Point3D<double> localPos = 0.5 * (localEndPos + localStartPos); + auto truthLocal = Acts::Vector2(localPos.y(), localPos.z()); + const TrackerDD::SiDetectorElement* element = m_detMgr->getDetectorElement(id); + const HepGeom::Point3D<double> globalStartPosition = + Amg::EigenTransformToCLHEP(element->transformHit()) * localStartPos; + const HepGeom::Point3D<double> globalEndPosition = + Amg::EigenTransformToCLHEP(element->transformHit()) * localEndPos; + auto globalPosition = 0.5 * (globalStartPosition + globalEndPosition); + auto globalDirection = globalEndPosition - globalStartPosition; + auto truthUnitDir = Acts::Vector3(globalDirection.x(), globalDirection.y(), globalDirection.z()).normalized(); + auto truthPos = Acts::Vector3(globalPosition.x() , globalPosition.y(), globalPosition.z()); + // FIXME get truthQOP for each state + + // fill the truth hit info + m_t_x.push_back(truthPos[Acts::ePos0]); + m_t_y.push_back(truthPos[Acts::ePos1]); + m_t_z.push_back(truthPos[Acts::ePos2]); + m_t_dx.push_back(truthUnitDir[Acts::eMom0]); + m_t_dy.push_back(truthUnitDir[Acts::eMom1]); + m_t_dz.push_back(truthUnitDir[Acts::eMom2]); + + // get the truth track parameter at this track State + float truthLOC0 = truthLocal[Acts::ePos0]; + float truthLOC1 = truthLocal[Acts::ePos1]; + float truthTIME = siHit->meanTime(); + float truthPHI = phi(truthUnitDir); + float truthTHETA = theta(truthUnitDir); + + // fill the truth track parameter at this track State + m_t_eLOC0.push_back(truthLOC0); + m_t_eLOC1.push_back(truthLOC1); + m_t_ePHI.push_back(truthPHI); + m_t_eTHETA.push_back(truthTHETA); + m_t_eQOP.push_back(truthQOP); + m_t_eT.push_back(truthTIME); + } else { + m_t_x.push_back(NaNfloat); + m_t_y.push_back(NaNfloat); + m_t_z.push_back(NaNfloat); + m_t_dx.push_back(NaNfloat); + m_t_dy.push_back(NaNfloat); + m_t_dz.push_back(NaNfloat); + m_t_eLOC0.push_back(NaNfloat); + m_t_eLOC1.push_back(NaNfloat); + m_t_ePHI.push_back(NaNfloat); + m_t_eTHETA.push_back(NaNfloat); + m_t_eT.push_back(NaNfloat); + } + + // get the geometry ID + auto geoID = surface.geometryId(); + m_volumeID.push_back(geoID.volume()); + m_layerID.push_back(geoID.layer()); + m_moduleID.push_back(geoID.sensitive()); + + // get wafer information + m_station.push_back(m_idHelper->station(id)); + m_layer.push_back(m_idHelper->layer(id)); + m_phi_module.push_back(m_idHelper->phi_module(id)); + m_eta_module.push_back(m_idHelper->eta_module(id)); + m_side.push_back(m_idHelper->side(id)); + + // get the path length + m_pathLength.push_back(state.pathLength()); + + // expand the local measurements into the full bound space + Acts::BoundVector meas = state.projector().transpose() * state.calibrated(); + // extract local and global position + Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); + Acts::Vector3 mom(1, 1, 1); + Acts::Vector3 global = surface.localToGlobal(gctx, local, mom); + + // fill the measurement info + m_lx_hit.push_back(local[Acts::ePos0]); + m_ly_hit.push_back(local[Acts::ePos1]); + m_x_hit.push_back(global[Acts::ePos0]); + m_y_hit.push_back(global[Acts::ePos1]); + m_z_hit.push_back(global[Acts::ePos2]); + + // status of the fitted track parameters + std::array<bool, 3> hasParams = {false, false, false}; + // optional fitted track parameters + std::optional<std::pair<Acts::BoundVector, Acts::BoundMatrix>> + trackParamsOpt = std::nullopt; + // lambda to get the fitted track parameters + auto getTrackParams = [&](unsigned int ipar) { + if (ipar == 0 && state.hasPredicted()) { + hasParams[0] = true; + m_nParams[0]++; + trackParamsOpt = + std::make_pair(state.predicted(), state.predictedCovariance()); + } else if (ipar == 1 && state.hasFiltered()) { + hasParams[1] = true; + m_nParams[1]++; + trackParamsOpt = + std::make_pair(state.filtered(), state.filteredCovariance()); + } else if (ipar == 2 && state.hasSmoothed()) { + hasParams[2] = true; + m_nParams[2]++; + trackParamsOpt = + std::make_pair(state.smoothed(), state.smoothedCovariance()); + } + }; + + // fill the fitted track parameters + for (unsigned int ipar = 0; ipar < 3; ++ipar) { + // get the fitted track parameters + getTrackParams(ipar); + if (trackParamsOpt) { + const auto& [parameters, covariance] = *trackParamsOpt; + if (ipar == 0) { + // + // local hit residual info + auto H = state.effectiveProjector(); + auto resCov = state.effectiveCalibratedCovariance() + + H * covariance * H.transpose(); + auto res = state.effectiveCalibrated() - H * parameters; + m_res_x_hit.push_back(res[Acts::eBoundLoc0]); +// m_res_y_hit.push_back(res[Acts::eBoundLoc1]); + m_res_y_hit.push_back(NaNfloat); + m_err_x_hit.push_back( + sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); +// m_err_y_hit.push_back( +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_err_x_hit.push_back(NaNfloat); + m_res_y_hit.push_back(NaNfloat); + m_pull_x_hit.push_back( + res[Acts::eBoundLoc0] / + sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); +// m_pull_y_hit.push_back( +// res[Acts::eBoundLoc1] / +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_pull_y_hit.push_back(NaNfloat); + m_dim_hit.push_back(state.calibratedSize()); + } + + // track parameters + m_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0]); + m_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1]); + m_ePHI[ipar].push_back(parameters[Acts::eBoundPhi]); + m_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta]); + m_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP]); + m_eT[ipar].push_back(parameters[Acts::eBoundTime]); + + // track parameters residual + float resPhi; + if (isMC) { + m_res_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0] - truthLOC0); + m_res_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1] - truthLOC1); + resPhi = Acts::detail::difference_periodic<float>( parameters[Acts::eBoundPhi], truthPHI, + static_cast<float>(2 * M_PI)); + m_res_ePHI[ipar].push_back(resPhi); + m_res_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta] - truthTHETA); + m_res_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP] - truthQOP); + m_res_eT[ipar].push_back(parameters[Acts::eBoundTime] - truthTIME); + + // track parameters error + m_err_eLOC0[ipar].push_back( + sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_err_eLOC1[ipar].push_back( + sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_err_ePHI[ipar].push_back( + sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); + m_err_eTHETA[ipar].push_back( + sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); + m_err_eQOP[ipar].push_back( + sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); + m_err_eT[ipar].push_back( + sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); + + // track parameters pull + m_pull_eLOC0[ipar].push_back( + (parameters[Acts::eBoundLoc0] - truthLOC0) / + sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_pull_eLOC1[ipar].push_back( + (parameters[Acts::eBoundLoc1] - truthLOC1) / + sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_pull_ePHI[ipar].push_back( + resPhi / sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); + m_pull_eTHETA[ipar].push_back( + (parameters[Acts::eBoundTheta] - truthTHETA) / + sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); + m_pull_eQOP[ipar].push_back( + (parameters[Acts::eBoundQOverP] - truthQOP) / + sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); + m_pull_eT[ipar].push_back( + (parameters[Acts::eBoundTime] - truthTIME) / + sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); + } else { + if (ipar == 0) { + // push default values if no track parameters + m_res_x_hit.push_back(NaNfloat); + m_res_y_hit.push_back(NaNfloat); + m_err_x_hit.push_back(NaNfloat); + m_err_y_hit.push_back(NaNfloat); + m_pull_x_hit.push_back(NaNfloat); + m_pull_y_hit.push_back(NaNfloat); + m_dim_hit.push_back(NaNint); + } + // push default values if no track parameters + // m_eLOC0[ipar].push_back(NaNfloat); + // m_eLOC1[ipar].push_back(NaNfloat); + // m_ePHI[ipar].push_back(NaNfloat); + // m_eTHETA[ipar].push_back(NaNfloat); + // m_eQOP[ipar].push_back(NaNfloat); + // m_eT[ipar].push_back(NaNfloat); + m_res_eLOC0[ipar].push_back(NaNfloat); + m_res_eLOC1[ipar].push_back(NaNfloat); + m_res_ePHI[ipar].push_back(NaNfloat); + m_res_eTHETA[ipar].push_back(NaNfloat); + m_res_eQOP[ipar].push_back(NaNfloat); + m_res_eT[ipar].push_back(NaNfloat); + m_err_eLOC0[ipar].push_back(NaNfloat); + m_err_eLOC1[ipar].push_back(NaNfloat); + m_err_ePHI[ipar].push_back(NaNfloat); + m_err_eTHETA[ipar].push_back(NaNfloat); + m_err_eQOP[ipar].push_back(NaNfloat); + m_err_eT[ipar].push_back(NaNfloat); + m_pull_eLOC0[ipar].push_back(NaNfloat); + m_pull_eLOC1[ipar].push_back(NaNfloat); + m_pull_ePHI[ipar].push_back(NaNfloat); + m_pull_eTHETA[ipar].push_back(NaNfloat); + m_pull_eQOP[ipar].push_back(NaNfloat); + m_pull_eT[ipar].push_back(NaNfloat); + // m_x[ipar].push_back(NaNfloat); + // m_y[ipar].push_back(NaNfloat); + // m_z[ipar].push_back(NaNfloat); + // m_px[ipar].push_back(NaNfloat); + // m_py[ipar].push_back(NaNfloat); + // m_pz[ipar].push_back(NaNfloat); + // m_pT[ipar].push_back(NaNfloat); + // m_eta[ipar].push_back(NaNfloat); + } + + // further track parameter info + Acts::FreeVector freeParams = + Acts::detail::transformBoundToFreeParameters(surface, gctx, + parameters); + m_x[ipar].push_back(freeParams[Acts::eFreePos0]); + m_y[ipar].push_back(freeParams[Acts::eFreePos1]); + m_z[ipar].push_back(freeParams[Acts::eFreePos2]); + auto p = std::abs(1 / freeParams[Acts::eFreeQOverP]); + m_px[ipar].push_back(p * freeParams[Acts::eFreeDir0]); + m_py[ipar].push_back(p * freeParams[Acts::eFreeDir1]); + m_pz[ipar].push_back(p * freeParams[Acts::eFreeDir2]); + m_pT[ipar].push_back(p * std::hypot(freeParams[Acts::eFreeDir0], + freeParams[Acts::eFreeDir1])); + m_eta[ipar].push_back(Acts::VectorHelpers::eta( + freeParams.segment<3>(Acts::eFreeDir0))); + } else { + if (ipar == 0) { + // push default values if no track parameters + m_res_x_hit.push_back(NaNfloat); + m_res_y_hit.push_back(NaNfloat); + m_err_x_hit.push_back(NaNfloat); + m_err_y_hit.push_back(NaNfloat); + m_pull_x_hit.push_back(NaNfloat); + m_pull_y_hit.push_back(NaNfloat); + m_dim_hit.push_back(NaNint); + } + // push default values if no track parameters + m_eLOC0[ipar].push_back(NaNfloat); + m_eLOC1[ipar].push_back(NaNfloat); + m_ePHI[ipar].push_back(NaNfloat); + m_eTHETA[ipar].push_back(NaNfloat); + m_eQOP[ipar].push_back(NaNfloat); + m_eT[ipar].push_back(NaNfloat); + m_res_eLOC0[ipar].push_back(NaNfloat); + m_res_eLOC1[ipar].push_back(NaNfloat); + m_res_ePHI[ipar].push_back(NaNfloat); + m_res_eTHETA[ipar].push_back(NaNfloat); + m_res_eQOP[ipar].push_back(NaNfloat); + m_res_eT[ipar].push_back(NaNfloat); + m_err_eLOC0[ipar].push_back(NaNfloat); + m_err_eLOC1[ipar].push_back(NaNfloat); + m_err_ePHI[ipar].push_back(NaNfloat); + m_err_eTHETA[ipar].push_back(NaNfloat); + m_err_eQOP[ipar].push_back(NaNfloat); + m_err_eT[ipar].push_back(NaNfloat); + m_pull_eLOC0[ipar].push_back(NaNfloat); + m_pull_eLOC1[ipar].push_back(NaNfloat); + m_pull_ePHI[ipar].push_back(NaNfloat); + m_pull_eTHETA[ipar].push_back(NaNfloat); + m_pull_eQOP[ipar].push_back(NaNfloat); + m_pull_eT[ipar].push_back(NaNfloat); + m_x[ipar].push_back(NaNfloat); + m_y[ipar].push_back(NaNfloat); + m_z[ipar].push_back(NaNfloat); + m_px[ipar].push_back(NaNfloat); + m_py[ipar].push_back(NaNfloat); + m_pz[ipar].push_back(NaNfloat); + m_pT[ipar].push_back(NaNfloat); + m_eta[ipar].push_back(NaNfloat); + } + // fill the track parameters status + m_hasParams[ipar].push_back(hasParams[ipar]); + } + + // fill the chi2 + m_chi2.push_back(state.chi2()); + + return true; + }); // all states + + // fill the variables for one track to tree + m_outputTree->Fill(); + + // now reset + m_t_x.clear(); + m_t_y.clear(); + m_t_z.clear(); + m_t_dx.clear(); + m_t_dy.clear(); + m_t_dz.clear(); + m_t_eLOC0.clear(); + m_t_eLOC1.clear(); + m_t_ePHI.clear(); + m_t_eTHETA.clear(); + m_t_eQOP.clear(); + m_t_eT.clear(); + + m_volumeID.clear(); + m_layerID.clear(); + m_moduleID.clear(); + m_station.clear(); + m_layer.clear(); + m_phi_module.clear(); + m_eta_module.clear(); + m_side.clear(); + m_pathLength.clear(); + m_lx_hit.clear(); + m_ly_hit.clear(); + m_x_hit.clear(); + m_y_hit.clear(); + m_z_hit.clear(); + m_res_x_hit.clear(); + m_res_y_hit.clear(); + m_err_x_hit.clear(); + m_err_y_hit.clear(); + m_pull_x_hit.clear(); + m_pull_y_hit.clear(); + m_dim_hit.clear(); + + for (unsigned int ipar = 0; ipar < 3; ++ipar) { + m_hasParams[ipar].clear(); + m_eLOC0[ipar].clear(); + m_eLOC1[ipar].clear(); + m_ePHI[ipar].clear(); + m_eTHETA[ipar].clear(); + m_eQOP[ipar].clear(); + m_eT[ipar].clear(); + m_res_eLOC0[ipar].clear(); + m_res_eLOC1[ipar].clear(); + m_res_ePHI[ipar].clear(); + m_res_eTHETA[ipar].clear(); + m_res_eQOP[ipar].clear(); + m_res_eT[ipar].clear(); + m_err_eLOC0[ipar].clear(); + m_err_eLOC1[ipar].clear(); + m_err_ePHI[ipar].clear(); + m_err_eTHETA[ipar].clear(); + m_err_eQOP[ipar].clear(); + m_err_eT[ipar].clear(); + m_pull_eLOC0[ipar].clear(); + m_pull_eLOC1[ipar].clear(); + m_pull_ePHI[ipar].clear(); + m_pull_eTHETA[ipar].clear(); + m_pull_eQOP[ipar].clear(); + m_pull_eT[ipar].clear(); + m_x[ipar].clear(); + m_y[ipar].clear(); + m_z[ipar].clear(); + m_px[ipar].clear(); + m_py[ipar].clear(); + m_pz[ipar].clear(); + m_eta[ipar].clear(); + m_pT[ipar].clear(); + } + + m_chi2.clear(); + } // all subtrajectories + } // all trajectories + + return StatusCode::SUCCESS; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..76d76029674dcccbe48c41f5cf31b82b7292ba1b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx @@ -0,0 +1,466 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "Acts/EventData/detail/TransformationBoundToFree.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "FaserActsKalmanFilter/TrackClassification.h" +#include "HepMC/GenParticle.h" +#include "HepMC/GenVertex.h" +#include <TFile.h> +#include <TTree.h> + +/// NaN values for TTree variables +constexpr float NaNfloat = std::numeric_limits<float>::quiet_NaN(); +constexpr float NaNint = std::numeric_limits<int>::quiet_NaN(); + +using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; +using Acts::VectorHelpers::theta; + +RootTrajectorySummaryWriterTool::RootTrajectorySummaryWriterTool( + const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent) {} + + +StatusCode RootTrajectorySummaryWriterTool::initialize() { + ATH_CHECK(m_simDataCollectionKey.initialize()); + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + if (!m_noDiagnostics) { + std::string filePath = m_filePath; + std::string treeName = m_treeName; + m_outputFile = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_outputFile == nullptr) { + ATH_MSG_WARNING("Unable to open output file at " << m_filePath); + return StatusCode::RECOVERABLE; + } + m_outputFile->cd(); + m_outputTree = new TTree(treeName.c_str(), treeName.c_str()); + if (m_outputTree == nullptr) { + ATH_MSG_ERROR("Unable to create TTree"); + return StatusCode::FAILURE; + } + + m_outputTree = new TTree("tree", "tree"); + + m_outputTree->Branch("event_nr", &m_eventNr); + m_outputTree->Branch("multiTraj_nr", &m_multiTrajNr); + m_outputTree->Branch("subTraj_nr", &m_subTrajNr); + + m_outputTree->Branch("nStates", &m_nStates); + m_outputTree->Branch("nMeasurements", &m_nMeasurements); + m_outputTree->Branch("nOutliers", &m_nOutliers); + m_outputTree->Branch("nHoles", &m_nHoles); + m_outputTree->Branch("nSharedHits", &m_nSharedHits); + m_outputTree->Branch("chi2Sum", &m_chi2Sum); + m_outputTree->Branch("NDF", &m_NDF); + m_outputTree->Branch("measurementChi2", &m_measurementChi2); + m_outputTree->Branch("outlierChi2", &m_outlierChi2); + m_outputTree->Branch("measurementVolume", &m_measurementVolume); + m_outputTree->Branch("measurementLayer", &m_measurementLayer); + m_outputTree->Branch("outlierVolume", &m_outlierVolume); + m_outputTree->Branch("outlierLayer", &m_outlierLayer); + + m_outputTree->Branch("nMajorityHits", &m_nMajorityHits); + m_outputTree->Branch("majorityParticleId", &m_majorityParticleId); + m_outputTree->Branch("t_charge", &m_t_charge); + m_outputTree->Branch("t_time", &m_t_time); + m_outputTree->Branch("t_vx", &m_t_vx); + m_outputTree->Branch("t_vy", &m_t_vy); + m_outputTree->Branch("t_vz", &m_t_vz); + m_outputTree->Branch("t_px", &m_t_px); + m_outputTree->Branch("t_py", &m_t_py); + m_outputTree->Branch("t_pz", &m_t_pz); + m_outputTree->Branch("t_theta", &m_t_theta); + m_outputTree->Branch("t_phi", &m_t_phi); + m_outputTree->Branch("t_eta", &m_t_eta); + m_outputTree->Branch("t_p", &m_t_p); + m_outputTree->Branch("t_pT", &m_t_pT); + + m_outputTree->Branch("hasFittedParams", &m_hasFittedParams); + m_outputTree->Branch("eLOC0_fit", &m_eLOC0_fit); + m_outputTree->Branch("eLOC1_fit", &m_eLOC1_fit); + m_outputTree->Branch("ePHI_fit", &m_ePHI_fit); + m_outputTree->Branch("eTHETA_fit", &m_eTHETA_fit); + m_outputTree->Branch("eQOP_fit", &m_eQOP_fit); + m_outputTree->Branch("eT_fit", &m_eT_fit); + m_outputTree->Branch("err_eLOC0_fit", &m_err_eLOC0_fit); + m_outputTree->Branch("err_eLOC1_fit", &m_err_eLOC1_fit); + m_outputTree->Branch("err_ePHI_fit", &m_err_ePHI_fit); + m_outputTree->Branch("err_eTHETA_fit", &m_err_eTHETA_fit); + m_outputTree->Branch("err_eQOP_fit", &m_err_eQOP_fit); + m_outputTree->Branch("err_eT_fit", &m_err_eT_fit); + m_outputTree->Branch("res_eLOC0_fit", &m_res_eLOC0_fit); + m_outputTree->Branch("res_eLOC1_fit", &m_res_eLOC1_fit); + m_outputTree->Branch("res_ePHI_fit", &m_res_ePHI_fit); + m_outputTree->Branch("res_eTHETA_fit", &m_res_eTHETA_fit); + m_outputTree->Branch("res_eQOP_fit", &m_res_eQOP_fit); + m_outputTree->Branch("res_eT_fit", &m_res_eT_fit); + m_outputTree->Branch("pull_eLOC0_fit", &m_pull_eLOC0_fit); + m_outputTree->Branch("pull_eLOC1_fit", &m_pull_eLOC1_fit); + m_outputTree->Branch("pull_ePHI_fit", &m_pull_ePHI_fit); + m_outputTree->Branch("pull_eTHETA_fit", &m_pull_eTHETA_fit); + m_outputTree->Branch("pull_eQOP_fit", &m_pull_eQOP_fit); + m_outputTree->Branch("pull_eT_fit", &m_pull_eT_fit); + } + + return StatusCode::SUCCESS; +} + + +StatusCode RootTrajectorySummaryWriterTool::finalize() { + if (!m_noDiagnostics) { + m_outputFile->cd(); + m_outputTree->Write(); + m_outputFile->Close(); + } + return StatusCode::SUCCESS; +} + + +StatusCode RootTrajectorySummaryWriterTool::write( + const Acts::GeometryContext& geoContext, const TrajectoriesContainer& trajectories, bool isMC) const { + EventContext ctx = Gaudi::Hive::currentContext(); + + std::shared_ptr<TrackerSimDataCollection> simData {nullptr}; + std::map<int, const HepMC::GenParticle*> particles {}; + + if (isMC) { + SG::ReadHandle<TrackerSimDataCollection> simDataHandle {m_simDataCollectionKey, ctx}; + ATH_CHECK(simDataHandle.isValid()); + simData = std::make_shared<TrackerSimDataCollection>(*simDataHandle); + + SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey, ctx}; + ATH_CHECK(mcEvents.isValid()); + if (mcEvents->size() != 1) { + ATH_MSG_ERROR("There should be exactly one event in the McEventCollection."); + return StatusCode::FAILURE; + } + + for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) { + particles[particle->barcode()] = particle; + } + } + + // For each particle within a track, how many hits did it contribute + std::vector<ParticleHitCount> particleHitCounts; + + // Get the event number + m_eventNr = ctx.eventID().event_number(); + + // Loop over the trajectories + for (size_t itraj = 0; itraj < trajectories.size(); ++itraj) { + const auto& traj = trajectories[itraj]; + + if (traj.empty()) { + ATH_MSG_WARNING("Empty trajectories object " << itraj); + continue; + } + + // The trajectory index + m_multiTrajNr.push_back(itraj); + + // The trajectory entry indices and the multiTrajectory + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + + // Loop over the entry indices for the subtrajectories + for (unsigned int isubtraj = 0; isubtraj < trackTips.size(); ++isubtraj) { + // The subtrajectory index + m_subTrajNr.push_back(isubtraj); + // The entry index for this subtrajectory + const auto& trackTip = trackTips[isubtraj]; + + // Collect the trajectory summary info + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); + m_nStates.push_back(trajState.nStates); + m_nMeasurements.push_back(trajState.nMeasurements); + m_nOutliers.push_back(trajState.nOutliers); + m_nHoles.push_back(trajState.nHoles); + m_nSharedHits.push_back(trajState.nSharedHits); + m_chi2Sum.push_back(trajState.chi2Sum); + m_NDF.push_back(trajState.NDF); + m_measurementChi2.push_back(trajState.measurementChi2); + m_outlierChi2.push_back(trajState.measurementChi2); + // They are stored as double (as the vector of vector of int is not known to ROOT) + m_measurementVolume.emplace_back(trajState.measurementVolume.begin(), trajState.measurementVolume.end()); + m_measurementLayer.emplace_back(trajState.measurementLayer.begin(), trajState.measurementLayer.end()); + m_outlierVolume.emplace_back(trajState.outlierVolume.begin(), trajState.outlierVolume.end()); + m_outlierLayer.emplace_back(trajState.outlierLayer.begin(), trajState.outlierLayer.end()); + + // Initialize the truth particle info + uint64_t majorityParticleId = NaNint; + unsigned int nMajorityHits = NaNint; + float t_charge = NaNint; + float t_time = NaNfloat; + float t_vlx = NaNfloat; + float t_vly = NaNfloat; + float t_vx = NaNfloat; + float t_vy = NaNfloat; + float t_vz = NaNfloat; + float t_px = NaNfloat; + float t_py = NaNfloat; + float t_pz = NaNfloat; + float t_theta = NaNfloat; + float t_phi = NaNfloat; + float t_eta = NaNfloat; + float t_p = NaNfloat; + float t_pT = NaNfloat; + + // Get the perigee surface + Acts::Surface* pSurface = nullptr; + if (traj.hasTrackParameters(trackTip)) { + const auto& boundParam = traj.trackParameters(trackTip); + pSurface = const_cast<Acts::Surface*>(&boundParam.referenceSurface()); + } + + if (isMC) { + // Get the majority truth particle to this track + ATH_MSG_VERBOSE("get majority truth particle"); + identifyContributingParticles(*simData, traj, trackTip, particleHitCounts); + for (const auto& particle : particleHitCounts) { + ATH_MSG_VERBOSE(particle.particleId << ": " << particle.hitCount << " hits"); + } + + bool foundMajorityParticle = false; + // Get the truth particle info + if (not particleHitCounts.empty()) { + // Get the barcode of the majority truth particle + majorityParticleId = particleHitCounts.front().particleId; + nMajorityHits = particleHitCounts.front().hitCount; + + // Find the truth particle via the barcode + auto ip = particles.find(majorityParticleId); + if (ip != particles.end()) { + foundMajorityParticle = true; + + const HepMC::GenParticle* particle = ip->second; + ATH_MSG_DEBUG("Find the truth particle with barcode = " << majorityParticleId); + + // extrapolate parameters from vertex to reference surface at origin. + std::unique_ptr<const Acts::BoundTrackParameters> truthParameters + = extrapolateToReferenceSurface(ctx, particle); + if (!truthParameters) { + continue; + } + // Get the truth particle info at vertex + // const HepMC::GenVertex* vertex = particle->production_vertex(); + t_p = truthParameters->momentum().mag(); + t_charge = truthParameters->charge(); + t_time = truthParameters->time(); + t_vx = truthParameters->position(geoContext).x(); + t_vy = truthParameters->position(geoContext).y(); + t_vz = truthParameters->position(geoContext).z(); + t_px = truthParameters->momentum().x(); + t_py = truthParameters->momentum().y(); + t_pz = truthParameters->momentum().z(); + t_theta = theta(truthParameters->momentum().normalized()); + t_phi = phi(truthParameters->momentum().normalized()); + t_eta = eta(truthParameters->momentum().normalized()); + t_pT = t_p * perp(truthParameters->momentum().normalized()); + + auto unitDirection = Acts::Vector3(t_px, t_py, t_pz).normalized(); + auto positon = Acts::Vector3 (t_vx, t_vy, t_vz); + + if (pSurface) { + // get the truth perigee parameter + auto lpResult = pSurface->globalToLocal(geoContext, positon, unitDirection); + if (lpResult.ok()) { + t_vlx = lpResult.value()[Acts::BoundIndices::eBoundLoc0]; + t_vly = lpResult.value()[Acts::BoundIndices::eBoundLoc1]; + } else { + ATH_MSG_ERROR("Global to local transformation did not succeed."); + } + } + } else { + ATH_MSG_WARNING("Truth particle with barcode = " << majorityParticleId << " not found in the input collection!"); + } + } + if (not foundMajorityParticle) { + ATH_MSG_WARNING("Truth particle for mj " << itraj << " subtraj " << isubtraj << " not found!"); + } + } + + // Push the corresponding truth particle info for the track. + // Always push back even if majority particle not found + m_majorityParticleId.push_back(majorityParticleId); + m_nMajorityHits.push_back(nMajorityHits); + m_t_charge.push_back(t_charge); + m_t_time.push_back(t_time); + m_t_vx.push_back(t_vx); + m_t_vy.push_back(t_vy); + m_t_vz.push_back(t_vz); + m_t_px.push_back(t_px); + m_t_py.push_back(t_py); + m_t_pz.push_back(t_pz); + m_t_theta.push_back(t_theta); + m_t_phi.push_back(t_phi); + m_t_eta.push_back(t_eta); + m_t_p.push_back(t_p); + m_t_pT.push_back(t_pT); + + // Initialize the fitted track parameters info + std::array<float, Acts::eBoundSize> param = {NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat}; + std::array<float, Acts::eBoundSize> res = {NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat}; + std::array<float, Acts::eBoundSize> error = {NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat}; + std::array<float, Acts::eBoundSize> pull = {NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat, NaNfloat}; + bool hasFittedParams = false; + if (traj.hasTrackParameters(trackTip)) { + hasFittedParams = true; + const auto& boundParam = traj.trackParameters(trackTip); + const auto& parameter = boundParam.parameters(); + for (unsigned int i = 0; i < Acts::eBoundSize; ++i) { + param[i] = parameter[i]; + } + + res = {param[Acts::eBoundLoc0] - t_vlx, + param[Acts::eBoundLoc1] - t_vly, + param[Acts::eBoundPhi] - t_phi, + param[Acts::eBoundTheta] - t_theta, + param[Acts::eBoundQOverP] - t_charge / t_p, + param[Acts::eBoundTime] - t_time}; + + if (boundParam.covariance().has_value()) { + const auto& covariance = *boundParam.covariance(); + for (unsigned int i = 0; i < Acts::eBoundSize; ++i) { + error[i] = std::sqrt(covariance(i, i)); + pull[i] = res[i] / error[i]; + } + } + } + + // Push the fitted track parameters. + // Always push back even if no fitted track parameters + m_eLOC0_fit.push_back(param[Acts::eBoundLoc0]); + m_eLOC1_fit.push_back(param[Acts::eBoundLoc1]); + m_ePHI_fit.push_back(param[Acts::eBoundPhi]); + m_eTHETA_fit.push_back(param[Acts::eBoundTheta]); + m_eQOP_fit.push_back(param[Acts::eBoundQOverP]); + m_eT_fit.push_back(param[Acts::eBoundTime]); + + m_res_eLOC0_fit.push_back(res[Acts::eBoundLoc0]); + m_res_eLOC1_fit.push_back(res[Acts::eBoundLoc1]); + m_res_ePHI_fit.push_back(res[Acts::eBoundPhi]); + m_res_eTHETA_fit.push_back(res[Acts::eBoundTheta]); + m_res_eQOP_fit.push_back(res[Acts::eBoundQOverP]); + m_res_eT_fit.push_back(res[Acts::eBoundTime]); + + m_err_eLOC0_fit.push_back(error[Acts::eBoundLoc0]); + m_err_eLOC1_fit.push_back(error[Acts::eBoundLoc1]); + m_err_ePHI_fit.push_back(error[Acts::eBoundPhi]); + m_err_eTHETA_fit.push_back(error[Acts::eBoundTheta]); + m_err_eQOP_fit.push_back(error[Acts::eBoundQOverP]); + m_err_eT_fit.push_back(error[Acts::eBoundTime]); + + m_pull_eLOC0_fit.push_back(pull[Acts::eBoundLoc0]); + m_pull_eLOC1_fit.push_back(pull[Acts::eBoundLoc1]); + m_pull_ePHI_fit.push_back(pull[Acts::eBoundPhi]); + m_pull_eTHETA_fit.push_back(pull[Acts::eBoundTheta]); + m_pull_eQOP_fit.push_back(pull[Acts::eBoundQOverP]); + m_pull_eT_fit.push_back(pull[Acts::eBoundTime]); + + m_hasFittedParams.push_back(hasFittedParams); + } // all subtrajectories + } // all trajectories + + + // fill the variables + m_outputTree->Fill(); + + m_multiTrajNr.clear(); + m_subTrajNr.clear(); + m_nStates.clear(); + m_nMeasurements.clear(); + m_nOutliers.clear(); + m_nHoles.clear(); + m_nSharedHits.clear(); + m_chi2Sum.clear(); + m_NDF.clear(); + m_measurementChi2.clear(); + m_outlierChi2.clear(); + m_measurementVolume.clear(); + m_measurementLayer.clear(); + m_outlierVolume.clear(); + m_outlierLayer.clear(); + + m_nMajorityHits.clear(); + m_majorityParticleId.clear(); + m_t_charge.clear(); + m_t_time.clear(); + m_t_vx.clear(); + m_t_vy.clear(); + m_t_vz.clear(); + m_t_px.clear(); + m_t_py.clear(); + m_t_pz.clear(); + m_t_theta.clear(); + m_t_phi.clear(); + m_t_p.clear(); + m_t_pT.clear(); + m_t_eta.clear(); + + m_hasFittedParams.clear(); + m_eLOC0_fit.clear(); + m_eLOC1_fit.clear(); + m_ePHI_fit.clear(); + m_eTHETA_fit.clear(); + m_eQOP_fit.clear(); + m_eT_fit.clear(); + m_err_eLOC0_fit.clear(); + m_err_eLOC1_fit.clear(); + m_err_ePHI_fit.clear(); + m_err_eTHETA_fit.clear(); + m_err_eQOP_fit.clear(); + m_err_eT_fit.clear(); + m_res_eLOC0_fit.clear(); + m_res_eLOC1_fit.clear(); + m_res_ePHI_fit.clear(); + m_res_eTHETA_fit.clear(); + m_res_eQOP_fit.clear(); + m_res_eT_fit.clear(); + m_pull_eLOC0_fit.clear(); + m_pull_eLOC1_fit.clear(); + m_pull_ePHI_fit.clear(); + m_pull_eTHETA_fit.clear(); + m_pull_eQOP_fit.clear(); + m_pull_eT_fit.clear(); + + return StatusCode::SUCCESS; +} + + +std::unique_ptr<const Acts::BoundTrackParameters> RootTrajectorySummaryWriterTool::extrapolateToReferenceSurface( + const EventContext& ctx, const HepMC::GenParticle* particle) const { + const HepMC::FourVector &vertex = particle->production_vertex()->position(); + const HepMC::FourVector &momentum = particle->momentum(); + + // The coordinate system of the Acts::PlaneSurface is defined as + // T = Z = normal, U = X x T = -Y, V = T x U = x + auto startSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, vertex.z()), Acts::Vector3(0, 0, 1)); + auto targetSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3(0, 0, 0), Acts::Vector3(0, 0, -1)); + Acts::BoundVector params = Acts::BoundVector::Zero(); + params[Acts::eBoundLoc0] = -vertex.y(); + params[Acts::eBoundLoc1] = vertex.x(); + params[Acts::eBoundPhi] = momentum.phi(); + params[Acts::eBoundTheta] = momentum.theta(); + // FIXME get charge of HepMC::GenParticle, the following does not work, e.g. for pions + double charge = particle->pdg_id() > 0 ? -1 : 1; + double MeV2GeV = 1e-3; + params[Acts::eBoundQOverP] = charge / (momentum.rho() * MeV2GeV); + params[Acts::eBoundTime] = vertex.t(); + Acts::BoundTrackParameters startParameters(std::move(startSurface), params, charge); + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters = + m_extrapolationTool->propagate(ctx, startParameters, *targetSurface); + return targetParameters; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5325703b0ba3599a1fdcdafb350850ddc621c555 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx @@ -0,0 +1,22 @@ +#include "FaserActsKalmanFilter/SeedingAlg.h" + +SeedingAlg::SeedingAlg(const std::string& name, ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator) {} + + +StatusCode SeedingAlg::initialize() { + ATH_CHECK(m_trackSeedTool.retrieve()); + return StatusCode::SUCCESS; +} + + +StatusCode SeedingAlg::execute() { + // const EventContext& ctx = Gaudi::Hive::currentContext(); + ATH_CHECK(m_trackSeedTool->run()); + return StatusCode::SUCCESS; +} + + +StatusCode SeedingAlg::finalize() { + return StatusCode::SUCCESS; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b12215257197a931266e251620f2c63ecef7b10a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.cxx @@ -0,0 +1,151 @@ +#include "FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrkTrack/Track.h" +#include "TrkTrack/TrackStateOnSurface.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +//#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include <random> + + +SegmentFitClusterTrackFinderTool::SegmentFitClusterTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode SegmentFitClusterTrackFinderTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode SegmentFitClusterTrackFinderTool::run() { + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + // create source links and measurements + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::map<int, Amg::Vector3D> positions; + std::map<int, Amg::Vector3D> directions; + std::map<Index, Identifier> identifierLinkMap; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + // TODO only take best track (most hits, smallest chi2) + // for now I assume that there is only one track in each station + for (const Trk::Track* track : *trackCollection) { + auto fitParameters = track->trackParameters()->front(); + const Amg::Vector3D fitPosition = fitParameters->position(); + const Amg::Vector3D fitMomentum = fitParameters->momentum(); + Identifier id; + for (const Trk::TrackStateOnSurface* state : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> ( + state->measurementOnTrack()); + if (clusterOnTrack) { + const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + id = cluster->detectorElement()->identify(); + // create source link + Acts::GeometryIdentifier geoId = identifierMap->at(id); + ATH_MSG_DEBUG(geoId); + ATH_MSG_DEBUG(m_idHelper->station(id) << "/" << + m_idHelper->layer(id) << "/" << + m_idHelper->phi_module(id) << "/" << + m_idHelper->eta_module(id) << "/" << + m_idHelper->side(id) + ); + identifierLinkMap[measurements.size()] = id; + IndexSourceLink sourceLink(geoId, measurements.size()); + // create measurement + const auto& par = cluster->localPosition(); + const auto& cov = cluster->localCovariance(); + Eigen::Matrix<double, 1, 1> myCov {m_sigmaCluster * m_sigmaCluster,}; + ThisMeasurement meas(sourceLink, Indices, par.head(1), myCov); +// ThisMeasurement meas(sourceLink, Indices, par.head(1), cov.block<1,1>(0,0)); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + clusters.push_back(cluster); + } + } + int station = m_idHelper->station(id); + positions[station] = fitPosition; + directions[station] = fitMomentum; + } + std::vector<std::vector<IndexSourceLink>> sourceLinkVector {sourceLinks}; + m_sourceLinks = std::make_shared<std::vector<std::vector<IndexSourceLink>>>(sourceLinkVector); + std::vector<std::vector<Measurement>> measurementVector {measurements}; + m_measurements = std::make_shared<std::vector<std::vector<Measurement>>>(measurementVector); + std::vector<std::map<Index, Identifier>> idLinkVector {identifierLinkMap}; + m_idLinks = std::make_shared<std::vector<std::map<Index, Identifier>>>(idLinkVector); + std::vector<std::vector<const Tracker::FaserSCT_Cluster*>> clusterVector {clusters}; + m_clusters = std::make_shared<std::vector<std::vector<const Tracker::FaserSCT_Cluster*>>>(clusterVector); + + // TODO how should we handle events without a track in each station? + if (positions.size() != 3) { + return StatusCode::RECOVERABLE; + } + + // create initial surface + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, 0}, Acts::Vector3{0, 0, 1}); + + // create initial parameters + Acts::Vector3 pos = positions[1] - positions[1].z()/directions[1].z() * directions[1]; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + Acts::Vector3 dir = positions[2] - positions[1]; + auto [abs_momentum, charge] = momentum(positions); +// Acts::Vector3 pos = positions[1] - positions[1].z()/directions[1].z() * directions[1]; +// Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; +// Acts::Vector3 dir = {directions[1].x(), directions[1].y(), directions[1].z()}; +// double abs_momentum = 1000; +// double charge = 1; + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + auto initialParameters = Acts::CurvilinearTrackParameters( + pos4, dir, abs_momentum, charge, cov); + std::vector<Acts::CurvilinearTrackParameters> paramVector {initialParameters}; + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(paramVector); + + return StatusCode::SUCCESS; +} + + +StatusCode SegmentFitClusterTrackFinderTool::finalize() { + return StatusCode::SUCCESS; +} + + +std::pair<double, double> SegmentFitClusterTrackFinderTool::momentum(const std::map<int, Amg::Vector3D>& pos, double B) { + Acts::Vector3 vec_l = pos.at(3) - pos.at(1); + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos.at(2).z() - pos.at(1).z()) / (pos.at(3).z() - pos.at(1).z()); + Acts::Vector3 vec_m = pos.at(1) + t * vec_l; + Acts::Vector3 vec_s = pos.at(2) - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); + double charge = vec_s.y() < 0 ? 1 : -1; + return std::make_pair(p_yz, charge); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0aa77c3e8b3f18a75b55aafb730e216e388c10f5 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.cxx @@ -0,0 +1,152 @@ +#include "FaserActsKalmanFilter/SegmentFitTrackFinderTool.h" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrkTrack/Track.h" +#include "TrkTrack/TrackStateOnSurface.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include <random> + + +SegmentFitTrackFinderTool::SegmentFitTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode SegmentFitTrackFinderTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_spacePointContainerKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode SegmentFitTrackFinderTool::run() { + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey}; + ATH_CHECK(spacePointContainer.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + // create vector of cluster identifiers which have been used by any track fit + std::vector<Identifier> trackIds; + std::map<int, Amg::Vector3D> positions; + std::map<int, Amg::Vector3D> directions; + // TODO only take best track (most hits, smallest chi2) + // for now I assume that there is only one track in each station + for (const Trk::Track* track : *trackCollection) { + auto fitParameters = track->trackParameters()->front(); + const Amg::Vector3D fitPosition = fitParameters->position(); + const Amg::Vector3D fitMomentum = fitParameters->momentum(); + Identifier id; + for (const Trk::TrackStateOnSurface* state : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> ( + state->measurementOnTrack()); + if (clusterOnTrack) { + id = clusterOnTrack->identify(); + trackIds.push_back(id); + } + } + int station = m_idHelper->station(id); + positions[station] = fitPosition; + directions[station] = fitMomentum; + } + + // create source links and measurements + const int kSize = 2; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::vector<Tracker::FaserSCT_SpacePoint> spacePoints {}; + for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) { + for (const Tracker::FaserSCT_SpacePoint *spacePoint: *spacePointCollection) { + Identifier id1 = spacePoint->cluster1()->identify(); + Identifier id2 = spacePoint->cluster2()->identify(); + // check if both clusters have been used to reconstruct track + if (std::find(trackIds.begin(), trackIds.end(), id1) != trackIds.end() && + std::find(trackIds.begin(), trackIds.end(), id2) != trackIds.end()) { + spacePoints.push_back(*spacePoint); + Identifier id = spacePoint->associatedSurface().associatedDetectorElementIdentifier(); + // create source link + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size()); + // create measurement + const auto& par = spacePoint->localParameters(); + const auto& cov = spacePoint->localCovariance(); + ThisMeasurement meas(sourceLink, Indices, par, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + } + } + } + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_spacePoints = std::make_shared<std::vector<Tracker::FaserSCT_SpacePoint>>(spacePoints); + + // TODO how should we handle events without a track in each station? + if (positions.size() != 3) { + return StatusCode::RECOVERABLE; + } + + // create initial surface + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, 0}, Acts::Vector3{0, 0, 1}); + + // create initial parameters + Acts::Vector3 pos = positions[1] - positions[1].z()/directions[1].z() * directions[1]; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + Acts::Vector3 dir = positions[2] - positions[1]; + Acts::Vector3 tmp {directions[1].x(), directions[1].y(), directions[1].z()}; + ATH_MSG_DEBUG(dir); + ATH_MSG_DEBUG(tmp); + double abs_momentum = momentum(positions); + // TODO get charge from momentum calculation + double charge = 1; + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + auto initialParameters = Acts::CurvilinearTrackParameters( + pos4, dir, abs_momentum, charge, cov); + m_initialTrackParameters = std::make_shared<const Acts::CurvilinearTrackParameters>(initialParameters); + + return StatusCode::SUCCESS; +} + + +StatusCode SegmentFitTrackFinderTool::finalize() { + return StatusCode::SUCCESS; +} + + +double SegmentFitTrackFinderTool::momentum(const std::map<int, Amg::Vector3D>& pos, double B) { + Acts::Vector3 vec_l = pos.at(3) - pos.at(1); + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos.at(2).z() - pos.at(1).z()) / (pos.at(3).z() - pos.at(1).z()); + Acts::Vector3 vec_m = pos.at(1) + t * vec_l; + Acts::Vector3 vec_s = pos.at(2) - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); + return p_yz; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f216042a6bbf915f169c41fe9ea0cc9b206f2c73 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx @@ -0,0 +1,86 @@ +#include "FaserActsKalmanFilter/SummaryPlotTool.h" +#include <iostream> + +void SummaryPlotTool::book(SummaryPlotTool::SummaryPlotCache &trackSummaryPlotCache) const { + PlotHelpers::Binning bEta = m_varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_varBinning.at("Pt"); + PlotHelpers::Binning bNum = m_varBinning.at("Num"); + // number of track states versus eta + trackSummaryPlotCache.nStates_vs_eta = PlotHelpers::bookProf( + "nStates_vs_eta", "Number of total states vs. #eta", bEta, bNum); + // number of measurements versus eta + trackSummaryPlotCache.nMeasurements_vs_eta = PlotHelpers::bookProf( + "nMeasurements_vs_eta", "Number of measurements vs. #eta", bEta, bNum); + // number of holes versus eta + trackSummaryPlotCache.nHoles_vs_eta = PlotHelpers::bookProf( + "nHoles_vs_eta", "Number of holes vs. #eta", bEta, bNum); + // number of outliers versus eta + trackSummaryPlotCache.nOutliers_vs_eta = PlotHelpers::bookProf( + "nOutliers_vs_eta", "Number of outliers vs. #eta", bEta, bNum); + // number of Shared Hits versus eta + trackSummaryPlotCache.nSharedHits_vs_eta = PlotHelpers::bookProf( + "nSharedHits_vs_eta", "Number of Shared Hits vs. #eta", bEta, bNum); + // number of track states versus pt + trackSummaryPlotCache.nStates_vs_pt = PlotHelpers::bookProf( + "nStates_vs_pT", "Number of total states vs. pT", bPt, bNum); + // number of measurements versus pt + trackSummaryPlotCache.nMeasurements_vs_pt = PlotHelpers::bookProf( + "nMeasurements_vs_pT", "Number of measurements vs. pT", bPt, bNum); + // number of holes versus pt + trackSummaryPlotCache.nHoles_vs_pt = PlotHelpers::bookProf( + "nHoles_vs_pT", "Number of holes vs. pT", bPt, bNum); + // number of outliers versus pt + trackSummaryPlotCache.nOutliers_vs_pt = PlotHelpers::bookProf( + "nOutliers_vs_pT", "Number of outliers vs. pT", bPt, bNum); + // number of Shared Hits versus pt + trackSummaryPlotCache.nSharedHits_vs_pt = PlotHelpers::bookProf( + "nSharedHits_vs_pT", "Number of Shared Hits vs. pT", bPt, bNum); +} + +void SummaryPlotTool::fill(SummaryPlotTool::SummaryPlotCache &trackSummaryPlotCache, + const Acts::BoundTrackParameters &fittedParameters, size_t nStates, size_t nMeasurements, + size_t nOutliers, size_t nHoles, size_t nSharedHits) const { + using Acts::VectorHelpers::eta; + using Acts::VectorHelpers::perp; + const auto& momentum = fittedParameters.momentum(); + const double fit_eta = eta(momentum); + const double fit_pT = perp(momentum); + + PlotHelpers::fillProf(trackSummaryPlotCache.nStates_vs_eta, fit_eta, nStates); + PlotHelpers::fillProf(trackSummaryPlotCache.nMeasurements_vs_eta, fit_eta, nMeasurements); + PlotHelpers::fillProf(trackSummaryPlotCache.nOutliers_vs_eta, fit_eta, nOutliers); + PlotHelpers::fillProf(trackSummaryPlotCache.nHoles_vs_eta, fit_eta, nHoles); + PlotHelpers::fillProf(trackSummaryPlotCache.nSharedHits_vs_eta, fit_eta, nSharedHits); + + PlotHelpers::fillProf(trackSummaryPlotCache.nStates_vs_pt, fit_pT, nStates); + PlotHelpers::fillProf(trackSummaryPlotCache.nMeasurements_vs_pt, fit_pT, nMeasurements); + PlotHelpers::fillProf(trackSummaryPlotCache.nOutliers_vs_pt, fit_pT, nOutliers); + PlotHelpers::fillProf(trackSummaryPlotCache.nHoles_vs_pt, fit_pT, nHoles); + PlotHelpers::fillProf(trackSummaryPlotCache.nSharedHits_vs_pt, fit_pT, nSharedHits); +} + +void SummaryPlotTool::write(const SummaryPlotTool::SummaryPlotCache &trackSummaryPlotCache) const { + trackSummaryPlotCache.nStates_vs_eta->Write(); + trackSummaryPlotCache.nMeasurements_vs_eta->Write(); + trackSummaryPlotCache.nOutliers_vs_eta->Write(); + trackSummaryPlotCache.nHoles_vs_eta->Write(); + trackSummaryPlotCache.nSharedHits_vs_eta->Write(); + trackSummaryPlotCache.nStates_vs_pt->Write(); + trackSummaryPlotCache.nMeasurements_vs_pt->Write(); + trackSummaryPlotCache.nOutliers_vs_pt->Write(); + trackSummaryPlotCache.nHoles_vs_pt->Write(); + trackSummaryPlotCache.nSharedHits_vs_pt->Write(); +} + +void SummaryPlotTool::clear(SummaryPlotTool::SummaryPlotCache &trackSummaryPlotCache) const { + delete trackSummaryPlotCache.nStates_vs_eta; + delete trackSummaryPlotCache.nMeasurements_vs_eta; + delete trackSummaryPlotCache.nOutliers_vs_eta; + delete trackSummaryPlotCache.nHoles_vs_eta; + delete trackSummaryPlotCache.nSharedHits_vs_eta; + delete trackSummaryPlotCache.nStates_vs_pt; + delete trackSummaryPlotCache.nMeasurements_vs_pt; + delete trackSummaryPlotCache.nOutliers_vs_pt; + delete trackSummaryPlotCache.nHoles_vs_pt; + delete trackSummaryPlotCache.nSharedHits_vs_pt; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..020c19b9cf4dfcfc1b8a5641d5e6c3765733161d --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx @@ -0,0 +1,144 @@ +#include "FaserActsKalmanFilter/ThreeStationTrackSeedTool.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" +#include "Acts/Geometry/GeometryIdentifier.hpp" + + +ThreeStationTrackSeedTool::ThreeStationTrackSeedTool( + const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode ThreeStationTrackSeedTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_clusterContainerKey.initialize()); + return StatusCode::SUCCESS; +} + + +StatusCode ThreeStationTrackSeedTool::run() { + // create track seeds for multiple tracks + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection}; + ATH_CHECK(trackCollection.isValid()); + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey}; + ATH_CHECK(clusterContainer.isValid()); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + const int kSize = 1; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0}; + std::vector<IndexSourceLink> sourceLinks; + std::vector<Measurement> measurements; + std::map<Index, Identifier> identifierLinkMap; + std::vector<const Tracker::FaserSCT_Cluster*> clusters {}; + for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) { + for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) { + Identifier id = cluster->detectorElement()->identify(); + identifierLinkMap[measurements.size()] = id; + if (identifierMap->count(id) != 0) { + Acts::GeometryIdentifier geoId = identifierMap->at(id); + IndexSourceLink sourceLink(geoId, measurements.size(), cluster); + // create measurement + const auto& par = cluster->localPosition(); + Eigen::Matrix<double, 1, 1> pos {par.x(),}; + Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,}; + ThisMeasurement meas(sourceLink, Indices, pos, cov); + sourceLinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + clusters.push_back(cluster); + } + } + } + + + std::map<int, std::vector<Tracklet>> station_tracklet_map; + for (const Trk::Track* track : *trackCollection) { + // auto momentum = track->trackParameters()->front()->momentum(); + int station = -1; + Amg::Vector3D trackletPosition {0, 0, 0}; + std::vector<const Tracker::FaserSCT_Cluster*> trackletClusters {}; + for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) { + auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack()); + if (clusterOnTrack) { + const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData(); + trackletClusters.push_back(cluster); + if (station == -1) { + Identifier id = clusterOnTrack->identify(); + station = m_idHelper->station(id); + auto fitParameters = track->trackParameters()->front(); + trackletPosition = fitParameters->position(); + } + } + } + station_tracklet_map[station].push_back(Tracklet(trackletPosition, trackletClusters)); + } + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + std::vector<Acts::CurvilinearTrackParameters> initParams {}; + std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>> seeds; + for (const auto& tracklet1 : station_tracklet_map[1]) { + for (const auto& tracklet2 : station_tracklet_map[2]) { + for (const auto& tracklet3 : station_tracklet_map[3]) { + initParams.push_back(get_params(tracklet1.position(), tracklet2.position(), tracklet3.position(), cov, m_origin)); + std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3> seed {tracklet1.clusters(), tracklet2.clusters(), tracklet3.clusters()}; + seeds.push_back(seed); + } + } + } + + m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams); + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks); + m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>( + Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1}); + m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters); + m_seedClusters = std::make_shared<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>(seeds); + + return StatusCode::SUCCESS; +} + + +StatusCode ThreeStationTrackSeedTool::finalize() { + return StatusCode::SUCCESS; +} + + +Acts::CurvilinearTrackParameters ThreeStationTrackSeedTool::get_params( + const Amg::Vector3D& position_st1, const Amg::Vector3D& position_st2, const Amg::Vector3D& position_st3, const Acts::BoundSymMatrix& cov, double origin) { + Acts::Vector3 dir = position_st2 - position_st1; + Acts::Vector3 pos = position_st1 - (position_st1.z() - origin)/dir.z() * dir; + Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0}; + auto [abs_momentum, charge] = momentum({{1, position_st1}, {2, position_st2}, {3, position_st3}}); + return Acts::CurvilinearTrackParameters(pos4, dir, abs_momentum, charge, cov); +} +std::pair<double, double> ThreeStationTrackSeedTool::momentum(const std::map<int, Amg::Vector3D>& pos, double B) { + Acts::Vector3 vec_l = pos.at(3) - pos.at(1); + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos.at(2).z() - pos.at(1).z()) / (pos.at(3).z() - pos.at(1).z()); + Acts::Vector3 vec_m = pos.at(1) + t * vec_l; + Acts::Vector3 vec_s = pos.at(2) - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); + double charge = vec_s.y() < 0 ? 1 : -1; + return std::make_pair(p_yz, charge); +} + + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6b780fc368e874f4520af430e63d1cc7c4e02575 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx @@ -0,0 +1,93 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "FaserActsKalmanFilter/TrackClassification.h" + +namespace { + +/// Increase the hit count for the given particle id by one. +inline void increaseHitCount(std::vector<ParticleHitCount> &particleHitCounts, int particleId) { + // linear search since there is no ordering + auto it = std::find_if(particleHitCounts.begin(), particleHitCounts.end(), + [=](const ParticleHitCount &phc) { + return (phc.particleId == particleId); + }); + // either increase count if we saw the particle before or add it + if (it != particleHitCounts.end()) { + it->hitCount += 1u; + } else { + particleHitCounts.push_back({particleId, 1u}); + } +} + +/// Sort hit counts by decreasing values, i.e. majority particle comes first. +inline void sortHitCount(std::vector<ParticleHitCount> &particleHitCounts) { + std::sort(particleHitCounts.begin(), particleHitCounts.end(), + [](const ParticleHitCount &lhs, const ParticleHitCount &rhs) { + return (lhs.hitCount > rhs.hitCount); + }); +} + +} // namespace + + +/// Identify all particles that contribute to a trajectory. +void identifyContributingParticles( + const TrackerSimDataCollection& simDataCollection, + const FaserActsRecMultiTrajectory& trajectories, size_t tip, + std::vector<ParticleHitCount>& particleHitCounts) { + particleHitCounts.clear(); + + if (not trajectories.hasTrajectory(tip)) { + return; + } + + trajectories.multiTrajectory().visitBackwards(tip, [&](const auto& state) { + // no truth info with non-measurement state + if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + std::vector<int> barcodes {}; + // register all particles that generated this hit + for (const Identifier &id : state.uncalibrated().hit()->rdoList()) { + if (simDataCollection.count(id) == 0) { + return true; + } + const auto &deposits = simDataCollection.find(id)->second.getdeposits(); + for (const TrackerSimData::Deposit &deposit : deposits) { + int barcode = deposit.first->barcode(); + if (std::find(barcodes.begin(), barcodes.end(), barcode) == barcodes.end()) { + barcodes.push_back(barcode); + increaseHitCount(particleHitCounts, deposit.first->barcode()); + } + } + } + return true; + }); + sortHitCount(particleHitCounts); +} + +/* Identify all particles that contribute to a trajectory. + * If a cluster consists of multiple RDOs we check for each from which particle(s) it has been created. + * And if multiple particles created a RDO we increase the hit count for each of them. + */ +void identifyContributingParticles( + const TrackerSimDataCollection& simDataCollection, + const std::vector<const Tracker::FaserSCT_Cluster*> clusters, + std::vector<ParticleHitCount>& particleHitCounts) { + particleHitCounts.clear(); + for (const Tracker::FaserSCT_Cluster *cluster : clusters) { + std::vector<int> barcodes {}; + for (const Identifier &id : cluster->rdoList()) { + if (simDataCollection.count(id) == 0) continue; + const auto &deposits = simDataCollection.find(id)->second.getdeposits(); + for (const TrackerSimData::Deposit &deposit : deposits) { + int barcode = deposit.first->barcode(); + if (std::find(barcodes.begin(), barcodes.end(), barcode) == barcodes.end()) { + barcodes.push_back(barcode); + increaseHitCount(particleHitCounts, deposit.first->barcode()); + } + } + } + } + sortHitCount(particleHitCounts); +} + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx index 954906a0f4263c6e17f17143b23d4639c5d1107a..44a86cbf06d0b10ae6aeca00bdd8bfd4e261d680 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx @@ -6,94 +6,51 @@ #include "Acts/Propagator/Propagator.hpp" #include "Acts/TrackFitting/GainMatrixSmoother.hpp" #include "Acts/TrackFitting/GainMatrixUpdater.hpp" -#include "Acts/MagneticField/ConstantBField.hpp" -#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -#include "Acts/MagneticField/SharedBField.hpp" -#include <boost/variant/variant.hpp> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> +namespace { using Updater = Acts::GainMatrixUpdater; using Smoother = Acts::GainMatrixSmoother; -using Stepper = Acts::EigenStepper<>; -using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; - -namespace ActsExtrapolationDetail { - using VariantPropagatorBase = boost::variant< - Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>, - Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator> - >; - - class VariantPropagator : public VariantPropagatorBase - { - public: - using VariantPropagatorBase::VariantPropagatorBase; - }; -} - -using ActsExtrapolationDetail::VariantPropagator; +using Stepper = Acts::EigenStepper<>; +using Navigator = Acts::Navigator; +using Propagator = Acts::Propagator<Stepper, Navigator>; +using CKF = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>; +using TrackParametersContainer = std::vector<CombinatorialKalmanFilterAlg::TrackParameters>; -template <typename TrackFinder> -struct TrackFinderFunctionImpl { - TrackFinder trackFinder; +struct TrackFinderFunctionImpl + : public CombinatorialKalmanFilterAlg::TrackFinderFunction { + CKF trackFinder; - TrackFinderFunctionImpl(TrackFinder&& f) : trackFinder(std::move(f)) {} + TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {} CombinatorialKalmanFilterAlg::TrackFinderResult operator()( - const IndexSourceLinkContainer& sourceLinks, - const std::vector<Acts::CurvilinearTrackParameters>& initialParameters, - const CombinatorialKalmanFilterAlg::TrackFinderOptions& options) const - { - return trackFinder.findTracks(sourceLinks, initialParameters, options); - } + const IndexSourceLinkContainer& sourcelinks, + const TrackParametersContainer& initialParameters, + const CombinatorialKalmanFilterAlg::TrackFinderOptions& options) + const override { + return trackFinder.findTracks(sourcelinks, initialParameters, options); + }; }; +} // namespace -CombinatorialKalmanFilterAlg::TrackFinderFunction +std::shared_ptr<CombinatorialKalmanFilterAlg::TrackFinderFunction> CombinatorialKalmanFilterAlg::makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) -{ - const std::string fieldMode = "FASER"; - const std::vector<double> constantFieldVector = {0., 0., 0.55}; - - Acts::Navigator::Config cfg{trackingGeometry}; - cfg.resolvePassive = false; - cfg.resolveMaterial = true; - cfg.resolveSensitive = true; - Acts::Navigator navigator( cfg ); - - std::unique_ptr<ActsExtrapolationDetail::VariantPropagator> varProp; - - if (fieldMode == "FASER") { - auto bField = std::make_shared<FASERMagneticFieldWrapper>(); - auto stepper = Acts::EigenStepper<>(std::move(bField)); - auto propagator = Acts::Propagator<decltype(stepper), Acts::Navigator>(std::move(stepper), - std::move(navigator)); - varProp = std::make_unique<VariantPropagator>(propagator); - } - else if (fieldMode == "Constant") { - Acts::Vector3 constantFieldVector = Acts::Vector3(constantFieldVector[0], - constantFieldVector[1], - constantFieldVector[2]); - - auto bField = std::make_shared<Acts::ConstantBField>(constantFieldVector); - auto stepper = Acts::EigenStepper<>(std::move(bField)); - auto propagator = Acts::Propagator<decltype(stepper), Acts::Navigator>(std::move(stepper), - std::move(navigator)); - varProp = std::make_unique<VariantPropagator>(propagator); - } - - return boost::apply_visitor([&](const auto& propagator) -> TrackFinderFunction { - using Updater = Acts::GainMatrixUpdater; - using Smoother = Acts::GainMatrixSmoother; - using CKF = Acts::CombinatorialKalmanFilter<typename std::decay_t<decltype(propagator)>, Updater, Smoother>; - - CKF trackFinder(std::move(propagator)); - - return TrackFinderFunctionImpl<CKF>(std::move(trackFinder)); - }, *varProp); -} \ No newline at end of file + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + bool resolvePassive, bool resolveMaterial, bool resolveSensitive) { + auto magneticField = std::make_shared<FASERMagneticFieldWrapper>(); + Stepper stepper(std::move(magneticField)); + Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = resolvePassive; + cfg.resolveMaterial = resolveMaterial; + cfg.resolveSensitive = resolveSensitive; + Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + CKF trackFinder(std::move(propagator)); + + // build the track finder functions. owns the track finder object. + return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder)); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackFittingFunction.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFittingFunction.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0ece62669f80e7863a75b191a9fc7a51d759ca6c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFittingFunction.cxx @@ -0,0 +1,118 @@ +#include "FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h" +#include "FaserActsGeometry/FASERMagneticFieldWrapper.h" + +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" + + +namespace { + +using Updater = Acts::GainMatrixUpdater; +using Smoother = Acts::GainMatrixSmoother; +using Stepper = Acts::EigenStepper<>; +using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; +using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>; + +struct TrackFitterFunctionImpl + : public FaserActsKalmanFilterAlg::TrackFitterFunction { + Fitter trackFitter; + + TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {} + + FaserActsKalmanFilterAlg::TrackFitterResult operator()( + const std::vector<IndexSourceLink> &sourceLinks, + const FaserActsKalmanFilterAlg::TrackParameters &initialParameters, + const FaserActsKalmanFilterAlg::TrackFitterOptions &options) + const override { + return trackFitter.fit(sourceLinks, initialParameters, options); + }; +}; + +} // namespace + + +std::shared_ptr<FaserActsKalmanFilterAlg::TrackFitterFunction> +FaserActsKalmanFilterAlg::makeTrackFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) { + auto magneticField = std::make_shared<FASERMagneticFieldWrapper>(); + auto stepper = Stepper(std::move(magneticField)); + Acts::Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + Fitter trackFitter(std::move(propagator)); + return std::make_shared<TrackFitterFunctionImpl>(std::move(trackFitter)); +} + +/* + +namespace ActsExtrapolationDetail { +using VariantPropagatorBase = boost::variant< + Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>, + Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>>; + +class VariantPropagator : public VariantPropagatorBase { +public: + using VariantPropagatorBase::VariantPropagatorBase; +}; +} // namespace ActsExtrapolationDetail + + +namespace { +template <typename Fitter> +struct FitterFunctionImpl { + Fitter fitter; + FitterFunctionImpl(Fitter&& f) : fitter(std::move(f)) {} + FaserActsKalmanFilterAlg::TrackFitterResult operator()( + const std::vector<IndexSourceLink>& sourceLinks, + const Acts::CurvilinearTrackParameters& initialParameters, + const Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>& options) const { + return fitter.fit(sourceLinks, initialParameters, options); + }; +}; +} // namespace + +std::shared_ptr<FaserActsKalmanFilterAlg::TrackFitterFunction> +FaserActsKalmanFilterAlg::makeTrackFitterFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) { + + const std::string fieldMode = "FASER"; + const std::vector<double> constantFieldVector = {0., 0., 0.55}; + + Acts::Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator( cfg ); + + std::unique_ptr<ActsExtrapolationDetail::VariantPropagator> varProp; + + if (fieldMode == "FASER") { + auto bField = std::make_shared<FASERMagneticFieldWrapper>(); + auto stepper = Acts::EigenStepper<>(std::move(bField)); + auto propagator = Acts::Propagator<decltype(stepper), + Acts::Navigator>(std::move(stepper), std::move(navigator)); + varProp = std::make_unique<ActsExtrapolationDetail::VariantPropagator>(propagator); + } else if (fieldMode == "Constant") { + Acts::Vector3 constantFieldVector = Acts::Vector3( + constantFieldVector[0], constantFieldVector[1], constantFieldVector[2]); + auto bField = std::make_shared<Acts::ConstantBField>(constantFieldVector); + auto stepper = Acts::EigenStepper<>(std::move(bField)); + auto propagator = Acts::Propagator<decltype(stepper), + Acts::Navigator>(std::move(stepper), std::move(navigator)); + varProp = std::make_unique<ActsExtrapolationDetail::VariantPropagator>(propagator); + } + + return boost::apply_visitor([&](const auto& propagator) -> TrackFitterFunction { + using Updater = Acts::GainMatrixUpdater; + using Smoother = Acts::GainMatrixSmoother; + using Fitter = Acts::KalmanFitter<typename std::decay_t<decltype(propagator)>, Updater, Smoother>; + Fitter fitter(std::move(propagator)); + return FitterFunctionImpl<Fitter>(std::move(fitter)); + }, *varProp); +} + */ diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..820e53cb18a6190992f3003c3df7fcd5fc751de9 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx @@ -0,0 +1,121 @@ +#include "FaserActsKalmanFilter/TrackSeedWriterTool.h" +#include "TFile.h" +#include "TTree.h" + +TrackSeedWriterTool::TrackSeedWriterTool(const std::string& type, + const std::string& name, + const IInterface* parent) + : AthAlgTool( type, name, parent ) {} + + +StatusCode TrackSeedWriterTool::initialize() { + ATH_MSG_INFO("TrackSeedWriterTool::initialize"); + + std::string filePath = m_filePath; + std::string treeName = m_treeName; + + m_file = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_file == nullptr) { + ATH_MSG_ERROR("Unable to open output file at " << m_filePath); + return StatusCode::FAILURE; + } + m_file->cd(); + m_tree = new TTree(treeName.c_str(), "tree"); + if (m_tree == nullptr) { + ATH_MSG_ERROR("Unable to create TTree"); + return StatusCode::FAILURE; + } + + TrackSeedWriterTool::initializeTree(); + + return StatusCode::SUCCESS; +} + + +StatusCode TrackSeedWriterTool::finalize() { + m_file->cd(); + m_tree->Write(); + return StatusCode::SUCCESS; +} + + +void TrackSeedWriterTool::initializeTree() { + m_tree->Branch("run_number", &m_runNumber); + m_tree->Branch("event_number", &m_eventNumber); + m_tree->Branch("eLOC0", &m_eLOC0); + m_tree->Branch("eLOC1", &m_eLOC1); + m_tree->Branch("ePHI", &m_ePHI); + m_tree->Branch("eTHETA", &m_eTHETA); + m_tree->Branch("eQOP", &m_eQOP); + m_tree->Branch("err_eLOC0", &m_err_eLOC0); + m_tree->Branch("err_eLOC1", &m_err_eLOC1); + m_tree->Branch("err_ePHI", &m_err_ePHI); + m_tree->Branch("err_eTHETA", &m_err_eTHETA); + m_tree->Branch("err_eQOP", &m_err_eQOP); + m_tree->Branch("x", &m_x); + m_tree->Branch("y", &m_y); + m_tree->Branch("z", &m_z); + m_tree->Branch("px", &m_px); + m_tree->Branch("py", &m_py); + m_tree->Branch("pz", &m_pz); +} + + +void TrackSeedWriterTool::writeout( + const Acts::GeometryContext& gctx, + const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>& initialParametersContainer) const { + m_runNumber = Gaudi::Hive::currentContext().eventID().run_number(); + m_eventNumber = Gaudi::Hive::currentContext().eventID().event_number(); + for (Acts::CurvilinearTrackParameters initialParameters : *initialParametersContainer) { + const auto& parameters = initialParameters.parameters(); + const Acts::Vector3& center = initialParameters.referenceSurface().center(gctx); + m_eLOC0.push_back(center[Acts::eBoundLoc0]); + m_eLOC1.push_back(center[Acts::eBoundLoc1]); + m_ePHI.push_back(parameters[Acts::eBoundPhi]); + m_eTHETA.push_back(parameters[Acts::eBoundTheta]); + m_eQOP.push_back(parameters[Acts::eBoundQOverP]); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + + const auto& covariance = *initialParameters.covariance(); + m_err_eLOC0.push_back(sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_err_eLOC1.push_back(sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_err_ePHI.push_back(sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); + m_err_eTHETA.push_back(sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); + m_err_eQOP.push_back(sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); + +#pragma GCC diagnostic pop + + const auto& position = initialParameters.position(gctx); + const auto& momentum = initialParameters.momentum(); + m_x.push_back(position.x()); + m_y.push_back(position.y()); + m_z.push_back(position.z()); + m_px.push_back(momentum.x()); + m_py.push_back(momentum.y()); + m_pz.push_back(momentum.z()); + } + m_tree->Fill(); + clearVariables(); +} + + +void TrackSeedWriterTool::clearVariables() const { + m_eLOC0.clear(); + m_eLOC1.clear(); + m_ePHI.clear(); + m_eTHETA.clear(); + m_eQOP.clear(); + m_err_eLOC0.clear(); + m_err_eLOC1.clear(); + m_err_ePHI.clear(); + m_err_eTHETA.clear(); + m_err_eQOP.clear(); + m_x.clear(); + m_y.clear(); + m_z.clear(); + m_px.clear(); + m_py.clear(); + m_pz.clear(); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fdc77b13a95da4e89a7ff0c869f24e781d4ed7cc --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.cxx @@ -0,0 +1,41 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "FaserActsKalmanFilter/TrackSelection.h" + +namespace { + +inline void sortTracks(std::vector<TrackQuality>& tracks) { + std::sort(tracks.begin(), tracks.end(), + [](const TrackQuality& lhs, const TrackQuality& rhs) { + if (lhs.nMeasurements != rhs.nMeasurements) { + return lhs.nMeasurements > rhs.nMeasurements; + } + return lhs.chi2 < rhs.chi2; + }); +} + +} // namespace + + +void selectTracks(TrackFinderResult& results, std::vector<TrackQuality>& trackQuality) { + for (auto& result : results) { + if (not result.ok()) { + continue; + } + auto& ckfResult = result.value(); + auto traj = FaserActsRecMultiTrajectory(ckfResult.fittedStates, ckfResult.lastMeasurementIndices, ckfResult.fittedParameters); + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + auto it = std::max_element(trackTips.begin(), trackTips.end(), + [&](const size_t& lhs, const size_t& rhs) { + auto trajState_lhs = Acts::MultiTrajectoryHelpers::trajectoryState(mj, lhs); + auto trajState_rhs = Acts::MultiTrajectoryHelpers::trajectoryState(mj, rhs); + if (trajState_lhs.nMeasurements != trajState_rhs.nMeasurements) { + return trajState_lhs.nMeasurements > trajState_rhs.nMeasurements; + } + return trajState_lhs.chi2Sum < trajState_rhs.chi2Sum; + }); + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, *it); + trackQuality.push_back({ckfResult, trajState.nMeasurements, trajState.chi2Sum}); + } + sortTracks(trackQuality); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx index aca7bd57a3df15bfbecffc5e6afb996daffb7020..55dfda762765da67bea84b219d5279ce0bf1a197 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx @@ -1,3 +1,4 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" #include "FaserActsKalmanFilter/TrajectoryWriterTool.h" #include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" #include "Acts/EventData/MultiTrajectoryHelpers.hpp" @@ -80,6 +81,15 @@ void TrajectoryWriterTool::initializeTree() { m_tree->Branch("g_x_fit" , &m_x_fit); m_tree->Branch("g_y_fit" , &m_y_fit); m_tree->Branch("g_z_fit" , &m_z_fit); + m_tree->Branch("lx_hit" , &m_lx_hit); + m_tree->Branch("ly_hit" , &m_ly_hit); + m_tree->Branch("x_hit" , &m_x_hit); + m_tree->Branch("y_hit" , &m_y_hit); + m_tree->Branch("z_hit" , &m_z_hit); + m_tree->Branch("meas_eLOC0" , &m_meas_eLOC0); + m_tree->Branch("meas_eLOC1" , &m_meas_eLOC1); + m_tree->Branch("meas_cov_eLOC0" , &m_meas_cov_eLOC0); + m_tree->Branch("meas_cov_eLOC1" , &m_meas_cov_eLOC1); m_tree->Branch("nPredicted", &m_nPredicted); m_tree->Branch("predicted", &m_prt); @@ -228,7 +238,10 @@ void TrajectoryWriterTool::writeout(TrajectoriesContainer trajectories, m_eta_ini.push_back(eta(initialparameters[iTraj].position(geoContext))); // The trajectory entry indices and the multiTrajectory - const auto& [trackTips, mj] = traj.trajectory(); + // const auto& [trackTips, mj] = traj.multiTrajectory(); + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + if (trackTips.empty()) { ATH_MSG_WARNING("Empty multiTrajectory."); m_nMeasurements = -1; @@ -308,11 +321,16 @@ void TrajectoryWriterTool::writeout(TrajectoriesContainer trajectories, // extract local and global position Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); -const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]); + const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]); Acts::Vector3 mom(1, 1, 1); Acts::Vector3 global = surface.localToGlobal(geoContext, local, dir); + m_meas_eLOC0.push_back(state.calibrated()[Acts::eBoundLoc0]); + m_meas_eLOC1.push_back(state.calibrated()[Acts::eBoundLoc1]); + m_meas_cov_eLOC0.push_back(state.calibratedCovariance()(Acts::eBoundLoc0, Acts::eBoundLoc0)); + m_meas_cov_eLOC1.push_back(state.calibratedCovariance()(Acts::eBoundLoc1, Acts::eBoundLoc1)); + // fill the measurement info m_lx_hit.push_back(local[Acts::ePos0]); m_ly_hit.push_back(local[Acts::ePos1]); @@ -340,15 +358,15 @@ const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundP /// Predicted residual m_res_eLOC0_prt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_prt.push_back(residual(Acts::eBoundLoc1)); +// m_res_eLOC1_prt.push_back(residual(Acts::eBoundLoc1)); /// Predicted parameter pulls m_pull_eLOC0_prt.push_back( residual(Acts::eBoundLoc0) / sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_prt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); +// m_pull_eLOC1_prt.push_back( +// residual(Acts::eBoundLoc1) / +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); /// Predicted parameter m_eLOC0_prt.push_back(parameter.parameters()[Acts::eBoundLoc0]); @@ -429,15 +447,15 @@ const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundP /// Filtered residual m_res_eLOC0_flt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_flt.push_back(residual(Acts::eBoundLoc1)); +// m_res_eLOC1_flt.push_back(residual(Acts::eBoundLoc1)); /// Filtered parameter pulls m_pull_eLOC0_flt.push_back( residual(Acts::eBoundLoc0) / sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_flt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); +// m_pull_eLOC1_flt.push_back( +// residual(Acts::eBoundLoc1) / +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); /// Filtered parameter m_eLOC0_flt.push_back(parameter.parameters()[Acts::eBoundLoc0]); @@ -520,30 +538,30 @@ const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundP auto residual = state.effectiveCalibrated() - H * state.smoothed(); m_res_x_hit.push_back(residual(Acts::eBoundLoc0)); - m_res_y_hit.push_back(residual(Acts::eBoundLoc1)); +// m_res_y_hit.push_back(residual(Acts::eBoundLoc1)); m_err_x_hit.push_back( sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_err_y_hit.push_back( - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); +// m_err_y_hit.push_back( +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); m_pull_x_hit.push_back( residual(Acts::eBoundLoc0) / sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_y_hit.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); +// m_pull_y_hit.push_back( +// residual(Acts::eBoundLoc1) / +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); m_dim_hit.push_back(state.calibratedSize()); /// Smoothed residual m_res_eLOC0_smt.push_back(residual(Acts::eBoundLoc0)); - m_res_eLOC1_smt.push_back(residual(Acts::eBoundLoc1)); +// m_res_eLOC1_smt.push_back(residual(Acts::eBoundLoc1)); /// Smoothed parameter pulls m_pull_eLOC0_smt.push_back( residual(Acts::eBoundLoc0) / sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); - m_pull_eLOC1_smt.push_back( - residual(Acts::eBoundLoc1) / - sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); +// m_pull_eLOC1_smt.push_back( +// residual(Acts::eBoundLoc1) / +// sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); /// Smoothed parameter m_eLOC0_smt.push_back(parameter.parameters()[Acts::eBoundLoc0]); @@ -638,6 +656,10 @@ void TrajectoryWriterTool::clearVariables() const { m_x_hit.clear(); m_y_hit.clear(); m_z_hit.clear(); + m_meas_eLOC0.clear(); + m_meas_eLOC1.clear(); + m_meas_cov_eLOC0.clear(); + m_meas_cov_eLOC1.clear(); m_res_x_hit.clear(); m_res_y_hit.clear(); m_err_x_hit.clear(); diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx index 85b1036e415fb3f28f9f6b8ee37679afb60304bd..f5b850d8a05877b9d7d48db65faadbff7cfac519 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx @@ -51,8 +51,6 @@ Acts::CurvilinearTrackParameters TruthBasedInitialParameterTool::getInitialParam } } - std::cout << "?? px = " << momentum.x() << " py = " << momentum.y() << " pz = " << momentum.z() << std::endl; - Acts::Vector3 truthVertex = {vertex.x(), vertex.y(), vertex.z()}; // in mm Acts::Vector3 truthMomentum = {momentum.x() / 1000, momentum.y() / 1000, momentum.z() / 1000}; // in GeV m_simWriterTool->writeout(truthVertex, truthMomentum); diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4a574ee970e5dc9ccc67dcdd94143b2df20d1114 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx @@ -0,0 +1,252 @@ +#include "FaserActsKalmanFilter/TruthSeededTrackFinderTool.h" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerSpacePoint/SpacePointForSeed.h" +#include <array> +#include <random> + + +TruthSeededTrackFinderTool::TruthSeededTrackFinderTool( + const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) {} + + +StatusCode TruthSeededTrackFinderTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_spacePointCollectionKey.initialize()); + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + return StatusCode::SUCCESS; +} + + +StatusCode TruthSeededTrackFinderTool::run() { +// SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_siHitCollectionKey}; +// ATH_CHECK(siHitCollection.isValid()); +// ATH_MSG_DEBUG("Read FaserSiHitCollection with " << siHitCollection->size() << " hits"); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + + SG::ReadHandle<SpacePointForSeedCollection> spacePointCollection {m_spacePointCollectionKey}; + ATH_CHECK(spacePointCollection.isValid()); + + Acts::GeometryContext geoctx = m_trackingGeometryTool->getNominalGeometryContext().context(); + + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry + = m_trackingGeometryTool->trackingGeometry(); + + const int kSize = 2; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> myIndices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; + + std::map<int, Acts::Vector3> spacePoints; + + std::vector<IndexSourceLink> sourcelinks; + std::vector<Measurement> measurements; + + for (const SpacePointForSeed* sp : *spacePointCollection) { + const Tracker::FaserSCT_SpacePoint* spacePoint = sp->SpacePoint(); + Identifier id = spacePoint->associatedSurface().associatedDetectorElementIdentifier(); + Acts::GeometryIdentifier geoId = identifierMap->at(id); + // const Acts::Surface *surface = m_trackingGeometryTool->trackingGeometry()->findSurface(geoId); + + auto par = spacePoint->localParameters(); + ATH_MSG_DEBUG("par " << par); + auto cov = spacePoint->localCovariance(); + ATH_MSG_DEBUG("cov " << cov); + ATH_MSG_DEBUG(cov(0, 0) << ", " << cov(0, 1) << ", " << cov(1, 0) << ", " << cov(1, 1)); + Acts::ActsSymMatrix<2> myCov = Acts::ActsSymMatrix<2>::Zero(); + myCov(0, 0) = m_covMeas00; + myCov(1, 1) = m_covMeas11; + myCov(0, 1) = m_covMeas01; + myCov(1, 0) = m_covMeas10; + + IndexSourceLink sourceLink(geoId, measurements.size()); + ThisMeasurement meas(sourceLink, myIndices, par, myCov); + sourcelinks.push_back(sourceLink); + measurements.emplace_back(std::move(meas)); + + Amg::Vector3D globalPosition = spacePoint->globalPosition(); + int station = m_idHelper->station(id); + int layer = m_idHelper->layer(id); + // TODO check if map already contains a space point for this layer + spacePoints[3*(station-1) + layer] = Acts::Vector3(globalPosition.x(), globalPosition.y(), globalPosition.z()); + + if (station == 1 && layer == 0) { + const TrackerDD::SiDetectorElement *element = m_detManager->getDetectorElement(id); + // Construct a plane surface as the target surface + const TrackerDD::SiDetectorDesign &design = element->design(); + double hlX = design.width()/2. * 1_mm; + double hlY = design.length()/2. * 1_mm; + auto rectangleBounds = std::make_shared<const Acts::RectangleBounds>(hlX, hlY); + Amg::Transform3D g2l = element->getMaterialGeom()->getDefAbsoluteTransform() + * Amg::CLHEPTransformToEigen(element->recoToHitTransform()); + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(g2l, rectangleBounds); + } + } + + // check if there is atleast one space point in each station + + if (map2vector(spacePoints, 1).empty() || map2vector(spacePoints, 2).empty() || map2vector(spacePoints, 0).empty()) { + return StatusCode::RECOVERABLE; + } + + Acts::Vector4 smearedPosition4; + Acts::Vector3 smearedDirection; + double smearedAbsoluteMomentum; + double charge; + if (m_useTrueInitialParameters) { + // get initial parameters from generated particle + SG::ReadHandle<McEventCollection> mcEventCollection {m_mcEventCollectionKey}; + ATH_CHECK(mcEventCollection.isValid()); + for (const HepMC::GenEvent* event : *mcEventCollection) { + for (const HepMC::GenParticle* particle : event->particle_range()) { + const HepMC::FourVector& momentum = particle->momentum(); + double abs_momentum = momentum.rho() * Acts::UnitConstants::MeV; + Acts::Vector3 direction = Acts::Vector3(momentum.x(), momentum.y(), momentum.z()); + const HepMC::FourVector vertex = particle->production_vertex()->position(); + charge = particle->pdg_id() > 0 ? -1 : 1; + + std::random_device rd; + std::default_random_engine rng {rd()}; + std::normal_distribution<> norm; + + auto theta = Acts::VectorHelpers::theta(direction); + auto phi = Acts::VectorHelpers::phi(direction); + auto angles = Acts::detail::normalizePhiTheta( + phi + m_sigmaPhi * norm(rng), + theta + m_sigmaTheta * norm(rng)); + smearedDirection = Acts::Vector3( + std::sin(angles.second) * std::cos(angles.first), + std::sin(angles.second) * std::sin(angles.first), + std::cos(angles.second)); + smearedAbsoluteMomentum = abs_momentum * (1 + m_sigmaP * norm(rng)); + + smearedPosition4 = Acts::Vector4(vertex.x() + m_sigmaLoc0 * norm(rng), vertex.y() + m_sigmaLoc1 * norm(rng), vertex.z(), 0); + } + } + } else { + // get initial parameters from track seed + auto [p, q] = momentum2(spacePoints); + double abs_momentum = p; + charge = q; + Acts::Vector3 initPos {0, 0, 0}; + if (spacePoints.count(0)) { + initPos = spacePoints.at(0); + } else { + ATH_MSG_ERROR("Could not find space point on first layer"); + } + smearedPosition4 = Acts::Vector4(initPos.x(), initPos.y(), initPos.z(), 0); + + auto [pos1, dir1] = linear_fit(map2vector(spacePoints, 1)); + auto [pos2, dir2] = linear_fit(map2vector(spacePoints, 2)); + smearedDirection = pos2 - pos1; +// smearedDirection = dir; + smearedAbsoluteMomentum = p; + } + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + // auto initialParameters = Acts::BoundTrackParameters(surface->getSharedPtr(), params, charge, cov); + auto initialParameters = Acts::CurvilinearTrackParameters( + smearedPosition4, smearedDirection, smearedAbsoluteMomentum, charge, cov); + + // write out + double initialCharge = initialParameters.charge(); + double initialAbsoluteMomentum = initialParameters.absoluteMomentum(); + Acts::Vector3 initialPosition = initialParameters.position(geoctx); + Acts::Vector3 initialMomentum = initialParameters.momentum(); + ATH_MSG_DEBUG("initial charge: " << initialCharge); + ATH_MSG_DEBUG("initial absolute momentum: " << initialAbsoluteMomentum); + ATH_MSG_DEBUG("initial position: x=" << initialPosition.x() << ", y=" << initialPosition.y() << ", z=" << initialPosition.z()); + ATH_MSG_DEBUG("initial momentum: x=" << initialMomentum.x() << ", y=" << initialMomentum.y() << ", z=" << initialMomentum.z()); + m_initialTrackParameters = std::make_shared<const Acts::CurvilinearTrackParameters>(initialParameters); + + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourcelinks); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + + return StatusCode::SUCCESS; +} + +StatusCode TruthSeededTrackFinderTool::finalize() { + return StatusCode::SUCCESS; +} + +Acts::Vector3 TruthSeededTrackFinderTool::average(const std::vector<Acts::Vector3>& spacePoints) { + Acts::Vector3 ret {0, 0, 0}; + if (!spacePoints.empty()) { + for (const Acts::Vector3& spacePoint : spacePoints) { + ret += spacePoint; + } + ret /= spacePoints.size(); + } + return ret; +} + +std::pair<Acts::Vector3, Acts::Vector3> +TruthSeededTrackFinderTool::linear_fit(const std::vector<Acts::Vector3>& hits) { + size_t n_hits = hits.size(); + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> centers(n_hits, 3); + for (size_t i = 0; i < n_hits; ++i) centers.row(i) = hits[i]; + + Acts::Vector3 origin = centers.colwise().mean(); + Eigen::MatrixXd centered = centers.rowwise() - origin.transpose(); + Eigen::MatrixXd cov = centered.adjoint() * centered; + Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov); + Acts::Vector3 axis = eig.eigenvectors().col(2).normalized(); + + return std::make_pair(origin, axis); +} + + +std::vector<Acts::Vector3> +TruthSeededTrackFinderTool::map2vector(const std::map<int, Acts::Vector3>& map, int station) { + std::vector<Acts::Vector3> vec; + for (int layer = station * 3; layer < station * 3 + 3; ++layer) { + if (map.count(layer)) { + vec.push_back(map.at(layer)); + } + } + return vec; +} + + +std::pair<double, double> TruthSeededTrackFinderTool::momentum2(const std::map<int, Acts::Vector3>& hits, double B) { + Acts::Vector3 pos1 = average(map2vector(hits, 0)); + Acts::Vector3 pos2 = average(map2vector(hits, 1)); + Acts::Vector3 pos3 = average(map2vector(hits, 2)); + + Acts::Vector3 vec_l = pos3 - pos1; + double abs_l = std::sqrt(vec_l.y() * vec_l.y() + vec_l.z() * vec_l.z()); + double t = (pos2.z() - pos1.z()) / (pos3.z() - pos1.z()); + Acts::Vector3 vec_m = pos1 + t * vec_l; + Acts::Vector3 vec_s = pos2 - vec_m; + double abs_s = std::sqrt(vec_s.y() * vec_s.y() + vec_s.z() * vec_s.z()); + double p_yz = 0.3 * abs_l * abs_l * B / (8 * abs_s * 1000); // in GeV + // double charge = vec_s.y() < 0 ? 1 : -1; + double charge = 1; + + return std::make_pair(p_yz, charge); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..16882021e4babed59f3a52030a565411290eb9ac --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx @@ -0,0 +1,191 @@ +#include "FaserActsKalmanFilter/TruthTrackFinderTool.h" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "Identifier/Identifier.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include <array> +#include <random> + + +TruthTrackFinderTool::TruthTrackFinderTool(const std::string& type, const std::string& name, const IInterface* parent) + : base_class(type, name, parent) {} + + +StatusCode TruthTrackFinderTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_detManager, "SCT")); + ATH_CHECK(m_siHitCollectionKey.initialize()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + return StatusCode::SUCCESS; +} + + +StatusCode TruthTrackFinderTool::run() { + SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_siHitCollectionKey}; + ATH_CHECK(siHitCollection.isValid()); + ATH_MSG_DEBUG("Read FaserSiHitCollection with " << siHitCollection->size() << " hits"); + + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry + = m_trackingGeometryTool->trackingGeometry(); + + using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>; + std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap(); + Acts::GeometryContext gctx = m_trackingGeometryTool->getNominalGeometryContext().context(); + const int kSize = 2; + using ParametersVector = Acts::ActsVector<kSize>; + using CovarianceMatrix = Acts::ActsSymMatrix<kSize>; + using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>; + std::array<Acts::BoundIndices, kSize> myIndices = {Acts::eBoundLoc0, Acts::eBoundLoc1}; + + std::vector<IndexSourceLink> sourcelinks; + std::vector<Measurement> measurements; + + std::vector<Acts::GeometryIdentifier> geoIds = {}; + int station, layer, phi, eta, side; + for (const FaserSiHit &hit: *siHitCollection) { + if (!hit.particleLink() or std::abs(hit.particleLink()->pdg_id()) != 13) { + continue; + } + + station = hit.getStation(); + layer = hit.getPlane(); + phi = hit.getRow(); + eta = hit.getModule(); + side = hit.getSensor(); + + if (side == 0) { + continue; + } + + ATH_MSG_DEBUG(station << "/" << layer << "/" << phi << "/" << eta << "/" << side); + + Identifier id = m_idHelper->wafer_id(station, layer, phi, eta, side); + // TODO check if there can be multiple simulated muon hits in the same wafer + // currently I take the first hit in each wafer + Acts::GeometryIdentifier geoId = identifierMap->at(id); + if (std::find(geoIds.begin(), geoIds.end(), geoId) != geoIds.end()) { + continue; + } + geoIds.push_back(geoId); + ATH_MSG_DEBUG(geoIds); + + auto momentum = hit.particleLink()->momentum(); + double abs_momentum = momentum.rho() * Acts::UnitConstants::MeV; + double QOverP = 1 / abs_momentum; + auto direction = Acts::Vector3(momentum.x(), momentum.y(), momentum.z()).normalized(); + + const TrackerDD::SiDetectorElement *element = m_detManager->getDetectorElement(id); + + // create source links and measurements + const Acts::Surface *surface = m_trackingGeometryTool->trackingGeometry()->findSurface(geoId); + if (surface == nullptr) { + ATH_MSG_FATAL("Could not find surface"); + continue; + } + + const HepGeom::Point3D<double> localStartPos = hit.localStartPosition(); + if (element) { + const HepGeom::Point3D<double> globalStartPos = + Amg::EigenTransformToCLHEP(element->transformHit()) * HepGeom::Point3D<double>(localStartPos); + auto center = surface->center(gctx); + Acts::Vector3 position = {globalStartPos.x(), globalStartPos.y(), center.z()}; + Acts::Result<Acts::BoundVector> boundParamsRes + = Acts::detail::transformFreeToBoundParameters(position, hit.meanTime(), direction, QOverP, *surface, gctx); + if (!boundParamsRes.ok()) { + ATH_MSG_FATAL("Could not construct bound parameters"); + return StatusCode::FAILURE; + } + const auto &boundParams = boundParamsRes.value(); + ATH_MSG_DEBUG(boundParams[0] << ", " << boundParams[1]); + + std::random_device rd; + std::default_random_engine rng {rd()}; + std::normal_distribution<> norm; + + ParametersVector smearedBoundParams = { + boundParams[0] + norm(rng) * m_sigma0, boundParams[1] + norm(rng) * m_sigma1}; + + ParametersVector par = ParametersVector::Zero(); + par[0] = smearedBoundParams[0]; + par[1] = smearedBoundParams[1]; + + ATH_MSG_DEBUG("bound parameters: par0=" << boundParams[0] << ", par1=" << boundParams[1]); + ATH_MSG_DEBUG("smeared parameters: par0=" << smearedBoundParams[0] << ", par1=" << smearedBoundParams[1]); + + CovarianceMatrix cov = CovarianceMatrix::Zero(); + cov(0, 0) = std::max(m_covMeasLoc0.value(), m_sigma0 * m_sigma0); + cov(1, 1) = std::max(m_covMeasLoc1.value(), m_sigma1 * m_sigma1); + + IndexSourceLink sourceLink(geoId, measurements.size()); + sourcelinks.emplace_back(sourceLink); + ThisMeasurement meas(sourceLink, myIndices, par, cov); + measurements.emplace_back(std::move(meas)); + + // create initial parameters from hit in first layer + if ((station == m_first_station) && (layer == m_first_layer) && (side == m_first_side)) { + + // smear initial direction + auto theta = Acts::VectorHelpers::theta(direction); + auto phi = Acts::VectorHelpers::phi(direction); + auto angles = Acts::detail::normalizePhiTheta( + phi + m_sigmaPhi * M_PI/180. * norm(rng), + theta + m_sigmaTheta * M_PI/180. * norm(rng)); + Acts::Vector3 smearedDirection( + std::sin(angles.second) * std::cos(angles.first), + std::sin(angles.second) * std::sin(angles.first), + std::cos(angles.second)); + double smearedAbsoluteMomentum = abs_momentum * (1 + m_sigmaP * norm(rng)); + + double z_init = 0; + m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3 {0, 0, z_init}, Acts::Vector3{0, 0, 1}); + + // extrapolate position on first layer to initial position + // TODO use first layer as initial layer instead? + Acts::Vector3 initPosition = position + (z_init - position.z()) / direction.z() * direction; + Acts::Vector3 smearedPosition {initPosition.x() + m_sigmaLoc0 * norm(rng), initPosition.y() + m_sigmaLoc1 * norm(rng), initPosition.z()}; + Acts::Vector4 smearedPosition4 {smearedPosition.x(), smearedPosition.y(), smearedPosition.z(), 0}; + double charge = hit.particleLink()->pdg_id() > 0 ? -1 : 1; + + Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero(); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1; + cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi; + cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta; + cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP; + cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime; + + // auto initialParameters = Acts::BoundTrackParameters(surface->getSharedPtr(), params, charge, cov); + auto initialParameters = Acts::CurvilinearTrackParameters(smearedPosition4, smearedDirection, smearedAbsoluteMomentum, charge, cov); + + // write out + double initialCharge = initialParameters.charge(); + double initialAbsoluteMomentum = initialParameters.absoluteMomentum(); + Acts::Vector3 initialPosition = initialParameters.position(gctx); + Acts::Vector3 initialMomentum = initialParameters.momentum(); + ATH_MSG_DEBUG("initial charge: " << initialCharge); + ATH_MSG_DEBUG("initial absolute momentum: " << initialAbsoluteMomentum); + ATH_MSG_DEBUG("initial position: x=" << initialPosition.x() << ", y=" << initialPosition.y() << ", z=" << initialPosition.z()); + ATH_MSG_DEBUG("initial momentum: x=" << initialMomentum.x() << ", y=" << initialMomentum.y() << ", z=" << initialMomentum.z()); + m_initialTrackParameters = std::make_shared<const Acts::CurvilinearTrackParameters>(initialParameters); + } + } + } + + m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourcelinks); + m_measurements = std::make_shared<std::vector<Measurement>>(measurements); + + return StatusCode::SUCCESS; +} + +StatusCode TruthTrackFinderTool::finalize() { + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx index 0b86d895fdd266b4df4bb9ba6ecb3b928581c9db..4c23cb7febdd977df01a7a4a4de997267dbfd4c6 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx @@ -2,19 +2,56 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -//#include "FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h" +#include "FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h" #include "FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h" -#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.h" -#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h" -#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h" -#include "FaserActsKalmanFilter/TrajectoryWriterTool.h" -#include "FaserActsKalmanFilter/SimWriterTool.h" +//#include "FaserActsKalmanFilter/MultiTrackFinderTool.h" +//#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.h" +//#include "FaserActsKalmanFilter/TruthTrackFinderTool.h" +//#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h" +//#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h" +//#include "FaserActsKalmanFilter/TrajectoryWriterTool.h" +//#include "FaserActsKalmanFilter/SimWriterTool.h" +//#include "FaserActsKalmanFilter/TruthSeededTrackFinderTool.h" +//#include "FaserActsKalmanFilter/ProtoTrackWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h" +//#include "FaserActsKalmanFilter/SegmentFitClusterTrackFinderTool.h" +//#include "FaserActsKalmanFilter/SegmentFitTrackFinderTool.h" +//#include "FaserActsKalmanFilter/ClusterTrackSeedTool.h" +#include "FaserActsKalmanFilter/ThreeStationTrackSeedTool.h" +#include "FaserActsKalmanFilter/PerformanceWriterTool.h" +#include "FaserActsKalmanFilter/TrackSeedWriterTool.h" +#include "FaserActsKalmanFilter/ActsTrackSeedTool.h" +#include "FaserActsKalmanFilter/CKF2.h" +#include "FaserActsKalmanFilter/KalmanFitterTool.h" +#include "FaserActsKalmanFilter/MyTrackSeedTool.h" +#include "FaserActsKalmanFilter/SeedingAlg.h" +#include "FaserActsKalmanFilter/CircleFitTrackSeedTool.h" +#include "FaserActsKalmanFilter/GhostBusters.h" - -//DECLARE_COMPONENT(FaserActsKalmanFilterAlg) +DECLARE_COMPONENT(FaserActsKalmanFilterAlg) DECLARE_COMPONENT(CombinatorialKalmanFilterAlg) -DECLARE_COMPONENT(TruthBasedInitialParameterTool) -DECLARE_COMPONENT(SPSeedBasedInitialParameterTool) -DECLARE_COMPONENT(SPSimpleInitialParameterTool) -DECLARE_COMPONENT(TrajectoryWriterTool) -DECLARE_COMPONENT(SimWriterTool) +//DECLARE_COMPONENT(TruthBasedInitialParameterTool) +//DECLARE_COMPONENT(SPSeedBasedInitialParameterTool) +//DECLARE_COMPONENT(SPSimpleInitialParameterTool) +//DECLARE_COMPONENT(TrajectoryWriterTool) +//DECLARE_COMPONENT(TruthTrackFinderTool) +//DECLARE_COMPONENT(SimWriterTool) +//DECLARE_COMPONENT(TruthSeededTrackFinderTool) +//DECLARE_COMPONENT(ProtoTrackWriterTool) +//DECLARE_COMPONENT(SegmentFitClusterTrackFinderTool) +//DECLARE_COMPONENT(SegmentFitTrackFinderTool) +DECLARE_COMPONENT(RootTrajectoryStatesWriterTool) +DECLARE_COMPONENT(RootTrajectorySummaryWriterTool) +//DECLARE_COMPONENT(MultiTrackFinderTool) +//DECLARE_COMPONENT(ClusterTrackSeedTool) +DECLARE_COMPONENT(ThreeStationTrackSeedTool) +DECLARE_COMPONENT(PerformanceWriterTool) +DECLARE_COMPONENT(TrackSeedWriterTool) +DECLARE_COMPONENT(ActsTrackSeedTool) +DECLARE_COMPONENT(CKF2) +DECLARE_COMPONENT(KalmanFitterTool) +DECLARE_COMPONENT(MyTrackSeedTool) +DECLARE_COMPONENT(SeedingAlg) +DECLARE_COMPONENT(CircleFitTrackSeedTool) +DECLARE_COMPONENT(GhostBusters) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py new file mode 100644 index 0000000000000000000000000000000000000000..98059c9e65857ac9f702615daa263b9c307f7877 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg +from FaserActsKalmanFilter.CKF2Config import CKF2Cfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.addFlag("Output.xAODFileName", f"CKF.xAOD.root") +ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.TrackingGeometry.MaterialSource = "Input" +ConfigFlags.Input.isMC = True +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) + +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.61, MinClustersPerFit=5, TanThetaXZCut=0.083)) +acc.merge(GhostBustersCfg(ConfigFlags)) +acc.merge(CKF2Cfg(ConfigFlags, noDiagnostics=True)) +# acc.getEventAlgo("CKF2").OutputLevel = DEBUG + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = VERBOSE +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +itemList = [ + "xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "xAOD::FaserTriggerData#*", + "xAOD::FaserTriggerDataAux#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*", +] +acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py index eef29095e39bc064e2dde11149be503b0d0d79ea..308d6f1c55e0eacfa96c59cd4e82d59fd5cb0211 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py +++ b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py @@ -10,19 +10,19 @@ from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg # from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg -from TrackerSeedFinder.TrackerSeedFinderConfig import TrackerSeedFinderCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg from FaserActsKalmanFilter.CombinatorialKalmanFilterConfig import CombinatorialKalmanFilterCfg log.setLevel(DEBUG) Configurable.configurableRun3Behavior = True ConfigFlags.Input.Files = ['my.RDO.pool.root'] -ConfigFlags.Output.ESDFileName = "myCKF.ESD.pool.root" -ConfigFlags.Output.AODFileName = "myCKF.AOD.pool.root" +ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root" ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" -# ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.GeoModel.FaserVersion = "FASER-01" ConfigFlags.GeoModel.Align.Dynamic = False ConfigFlags.Beam.NumberOfCollisions = 0. +# ConfigFlags.TrackingGeometry.MaterialSource = "Input" ConfigFlags.lock() acc = MainServicesCfg(ConfigFlags) @@ -31,8 +31,9 @@ acc.merge(PoolReadCfg(ConfigFlags)) acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) -acc.merge(TrackerSeedFinderCfg(ConfigFlags)) -acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.51, MinClustersPerFit=5, TanThetaCut=0.25)) +acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags, noDiagnostics=True)) +acc.getEventAlgo("CombinatorialKalmanFilterAlg").OutputLevel = VERBOSE # logging.getLogger('forcomps').setLevel(INFO) # acc.foreach_component("*").OutputLevel = INFO @@ -42,6 +43,5 @@ acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags)) # acc.printConfig(withDetails=True) # ConfigFlags.dump() -sc = acc.run(maxEvents=1000) - +sc = acc.run(maxEvents=-1) sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py index 5cf53fa5fb7cb4262c4c276374d54a8ea51402ef..3ea0fccd734ab65888d3b3a9c7505d2d2dc63738 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py +++ b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py @@ -6,25 +6,23 @@ from AthenaCommon.Constants import DEBUG, VERBOSE, INFO from AthenaCommon.Configurable import Configurable from CalypsoConfiguration.AllConfigFlags import ConfigFlags from CalypsoConfiguration.MainServicesConfig import MainServicesCfg -from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg -from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg +from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg -from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg -from TrackerSeedFinder.TrackerSeedFinderConfig import TrackerSeedFinderCfg from FaserActsKalmanFilter.CombinatorialKalmanFilterConfig import CombinatorialKalmanFilterCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg log.setLevel(DEBUG) Configurable.configurableRun3Behavior = True -ConfigFlags.Input.Files = ['/eos/project-f/faser-commissioning/TI12Data/Run-004411/Faser-Physics-004411-00000.raw'] -ConfigFlags.Output.ESDFileName = "myCKF.ESD.pool.root" -ConfigFlags.Output.AODFileName = "myCKF.AOD.pool.root" +ConfigFlags.Input.Files = ['/home/tboeckh/Documents/data/raw/TI12/MiddleStationTrack.raw'] +ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root" +ConfigFlags.addFlag("Output.xAODFileName", f"CKF.xAOD.root") ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" -ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now -ConfigFlags.Input.ProjectName = "data21" # Needed to bypass autoconfig -ConfigFlags.Input.isMC = False # Needed to bypass autoconfig -ConfigFlags.GeoModel.FaserVersion = "FASER-01" # FASER geometry +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASER-01" ConfigFlags.Common.isOnline = False ConfigFlags.GeoModel.Align.Dynamic = False ConfigFlags.Beam.NumberOfCollisions = 0. @@ -32,24 +30,38 @@ ConfigFlags.Detector.GeometryFaserSCT = True ConfigFlags.lock() acc = MainServicesCfg(ConfigFlags) -#acc.merge(PoolReadCfg(ConfigFlags)) acc.merge(PoolWriteCfg(ConfigFlags)) -from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) -acc.merge(WaveformReconstructionCfg(ConfigFlags)) -acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_EDGEMODE_RDOs")) -acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) -acc.merge(TrackerSeedFinderCfg(ConfigFlags)) -acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags)) - -logging.getLogger('forcomps').setLevel(VERBOSE) -acc.foreach_component("*").OutputLevel = VERBOSE -acc.foreach_component("*ClassID*").OutputLevel = INFO -acc.getService("StoreGateSvc").Dump = True -acc.getService("ConditionStore").Dump = True -acc.printConfig(withDetails=True) -ConfigFlags.dump() - -sc = acc.run(maxEvents=-1) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X")) +acc.merge(SegmentFitAlgCfg(ConfigFlags)) +acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags, SummaryWriter=False, StatesWriter=False, PerformanceWriter=False)) +acc.getEventAlgo("CombinatorialKalmanFilterAlg").OutputLevel = VERBOSE +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +itemList = ["xAOD::EventInfo#*", + "xAOD::EventAuxInfo#*", + "FaserSCT_RDO_Container#*", + "Tracker::FaserSCT_ClusterContainer#*", + "TrackCollection#*"] +acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) + +print( "Writing out xAOD objects:" ) +print( acc.getEventAlgo("OutputStreamxAOD").ItemList ) + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = INFO +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +# Hack to avoid problem with our use of MC databases when isMC = False +replicaSvc = acc.getService("DBReplicaSvc") +replicaSvc.COOLSQLiteVetoPattern = "" +replicaSvc.UseCOOLSQLite = True +replicaSvc.UseCOOLFrontier = False +replicaSvc.UseGeomSQLite = True + +sc = acc.run(maxEvents=20) sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py b/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py index 06975170f670f0fe8dec65b9a2d608aea6fc4c36..b2efe5323cf53e0220925994ab7b2d544462f81e 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py +++ b/Tracking/Acts/FaserActsKalmanFilter/test/FaserActsKalmanFilterAlg.py @@ -11,6 +11,7 @@ from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg from TruthSeededTrackFinder.TruthSeededTrackFinderConfig import TruthSeededTrackFinderCfg from FaserActsKalmanFilter.FaserActsKalmanFilterConfig import FaserActsKalmanFilterCfg @@ -20,9 +21,10 @@ log.setLevel(DEBUG) Configurable.configurableRun3Behavior = True # Configure -ConfigFlags.Input.Files = ['my.RDO.pool.root'] -ConfigFlags.Output.ESDFileName = "tmp.root" -ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion +ConfigFlags.Input.Files = ['../my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "FaserActsKalmanFilter.ESD.root" +ConfigFlags.Output.AODFileName = "FaserActsKalmanFilter.AOD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" ConfigFlags.GeoModel.Align.Dynamic = False ConfigFlags.Beam.NumberOfCollisions = 0. #ConfigFlags.Concurrency.NumThreads = 1 @@ -34,20 +36,20 @@ acc.merge(PoolReadCfg(ConfigFlags)) # Inner Detector acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) -acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) -acc.merge(TruthSeededTrackFinderCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags)) +# acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +# acc.merge(TruthSeededTrackFinderCfg(ConfigFlags)) acc.merge(FaserActsKalmanFilterCfg(ConfigFlags)) +acc.getEventAlgo("FaserActsKalmanFilterAlg").OutputLevel = DEBUG -logging.getLogger('forcomps').setLevel(VERBOSE) -acc.foreach_component("*").OutputLevel = VERBOSE -acc.foreach_component("*ClassID*").OutputLevel = INFO -acc.getService("StoreGateSvc").Dump = True -acc.getService("ConditionStore").Dump = True -acc.printConfig(withDetails=True) -ConfigFlags.dump() +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = INFO +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() # Execute and finish -sc = acc.run(maxEvents=-1) - -# Success should be 0 +sc = acc.run(maxEvents=1000) sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/GhostBusters.py b/Tracking/Acts/FaserActsKalmanFilter/test/GhostBusters.py new file mode 100644 index 0000000000000000000000000000000000000000..297f76e61fd138c325b67e98d0ea195e062eb5f3 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/GhostBusters.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from FaserActsKalmanFilter.SeedingConfig import SeedingCfg +from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "ghosts.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +# ConfigFlags.TrackingGeometry.MaterialSource = "Input" +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.61, MinClustersPerFit=5, TanThetaXZCut=0.083)) +# acc.getEventAlgo("Tracker::SegmentFitAlg").OutputLevel = VERBOSE +acc.merge(GhostBustersCfg(ConfigFlags, xTolerance=0.5, yTolerance=0.5)) +acc.getEventAlgo("GhostBusters").OutputLevel = DEBUG + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = VERBOSE +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/SeedingDbg.py b/Tracking/Acts/FaserActsKalmanFilter/test/SeedingDbg.py new file mode 100644 index 0000000000000000000000000000000000000000..01e04b803a6f1ed60ddd54db02fcea952ad8849c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/SeedingDbg.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from FaserActsKalmanFilter.SeedingConfig import SeedingCfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['my.RDO.pool.root'] +ConfigFlags.Output.ESDFileName = "circleFitSeeding.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" +ConfigFlags.GeoModel.FaserVersion = "FASER-01" +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +# ConfigFlags.TrackingGeometry.MaterialSource = "Input" +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolReadCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.51, MinClustersPerFit=5, TanThetaCut=0.25)) +acc.merge(SeedingCfg(ConfigFlags)) +acc.getEventAlgo("SeedingAlg").OutputLevel = VERBOSE + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = VERBOSE +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +sc = acc.run(maxEvents=10) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/TI12CKF2.py b/Tracking/Acts/FaserActsKalmanFilter/test/TI12CKF2.py new file mode 100644 index 0000000000000000000000000000000000000000..f6c5a5af53581d986d57ee32ad2e4d5706c6f6e1 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/TI12CKF2.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +# from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg +from FaserActsKalmanFilter.TI12CKF2Config import TI12CKF2Cfg + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = ['threeStationRun6833.raw'] +ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root" +ConfigFlags.addFlag("Output.xAODFileName", f"CKF.xAOD.root") +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data22" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASER-02" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.TrackingGeometry.MaterialSource = "Input" +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X")) +acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.61, MinClustersPerFit=5, TanThetaXZCut=0.083)) +acc.merge(GhostBustersCfg(ConfigFlags)) +acc.merge(TI12CKF2Cfg(ConfigFlags, noDiagnostics=False)) +acc.getEventAlgo("CKF2").OutputLevel = DEBUG + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = VERBOSE +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +# Hack to avoid problem with our use of MC databases when isMC = False +replicaSvc = acc.getService("DBReplicaSvc") +replicaSvc.COOLSQLiteVetoPattern = "" +replicaSvc.UseCOOLSQLite = True +replicaSvc.UseCOOLFrontier = False +replicaSvc.UseGeomSQLite = True + +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/TI12KalmanFilter.py b/Tracking/Acts/FaserActsKalmanFilter/test/TI12KalmanFilter.py new file mode 100644 index 0000000000000000000000000000000000000000..11b7e4217bed8400426f4257ef5cf43f5b7adbfd --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/TI12KalmanFilter.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +import sys +from AthenaCommon.Logging import log, logging +from AthenaCommon.Constants import DEBUG, VERBOSE, INFO +from AthenaCommon.Configurable import Configurable +from CalypsoConfiguration.AllConfigFlags import ConfigFlags +from AthenaConfiguration.TestDefaults import defaultTestFiles +from CalypsoConfiguration.MainServicesConfig import MainServicesCfg +from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg +from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg +from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg +from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg +from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg +from FaserActsKalmanFilter.FaserActsKalmanFilterConfig import FaserActsKalmanFilterCfg + + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +# Configure +ConfigFlags.Input.Files = ['/home/tboeckh/tmp/Faser-Physics-006470-00093.raw_middleStation.SPs'] +ConfigFlags.Output.ESDFileName = "MiddleStation-KalmanFilter.ESD.pool.root" +ConfigFlags.Output.AODFileName = "MiddleStation-KalmanFilter.AOD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASER-02" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.lock() + +# Core components +acc = MainServicesCfg(ConfigFlags) +acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, name="LevelClustering", DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X")) +acc.merge(SegmentFitAlgCfg(ConfigFlags, name=f"LevelFit", MaxClusters=44)) +# acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) +# acc.merge(SegmentFitAlgCfg(ConfigFlags)) +# acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) +acc.merge(FaserActsKalmanFilterCfg(ConfigFlags)) +acc.getEventAlgo("FaserActsKalmanFilterAlg").OutputLevel = DEBUG + +replicaSvc = acc.getService("DBReplicaSvc") +replicaSvc.COOLSQLiteVetoPattern = "" +replicaSvc.UseCOOLSQLite = True +replicaSvc.UseCOOLFrontier = False +replicaSvc.UseGeomSQLite = True + + +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = INFO +# acc.getService("StoreGateSvc").Dump = True +# acc.getService("ConditionStore").Dump = True +# acc.printConfig(withDetails=True) +# ConfigFlags.dump() + +# Execute and finish +sc = acc.run(maxEvents=-1) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/README.md b/Tracking/Acts/README.md index 2a0874fce87ed08d42fa4ac7c77d0226d430e318..5b4c24356a742621045dc568190bcb9c2315acca 100644 --- a/Tracking/Acts/README.md +++ b/Tracking/Acts/README.md @@ -6,3 +6,13 @@ 3) To write the tracking geometry, type the command: FaserActsWriteTrackingGeometry.py 4) To run the extrapolator, type the command: FaserActsExtrapolationAlg.py + +5) The track finding requires a json file with the correct material in the directory in which you run it. A copy can be found on lxplus: /afs/cern.ch/user/t/tboeckh/public/material/material-maps.json + If you do not want to use the material you have to comment out this line: ConfigFlags.TrackingGeometry.MaterialSource = "Input" + +6) To enable additional output set the noDiagnostics flag to False + +7) To do the track finding, type the command: CombinatorialKalmanFilterAlg.py + +8) To do the track finding and re-fit the best tracks, type the command: CKF2.py + (this is the recommended approach) diff --git a/Waveform/WaveDigiTools/CMakeLists.txt b/Waveform/WaveDigiTools/CMakeLists.txt index 692fdb69bc14451ba5a6a660d011bad5b14b66e5..d7e9fd857b273c764dad780aceebd0d3f58acc3a 100644 --- a/Waveform/WaveDigiTools/CMakeLists.txt +++ b/Waveform/WaveDigiTools/CMakeLists.txt @@ -13,13 +13,12 @@ atlas_add_library( WaveDigiToolsLib WaveDigiTools/*.h src/*.cxx src/*.h PUBLIC_HEADERS WaveDigiTools PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives WaveRawEvent + LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives WaveRawEvent Identifier PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ) atlas_add_component( WaveDigiTools src/components/*.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel WaveDigiToolsLib ) - + LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel WaveDigiToolsLib) diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h index 7241e8167d36facc42748141b58f5b640b4d33ee..c30351902a1b79e9a58ad33d5f58a5d04ed13faa 100644 --- a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h +++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h @@ -23,10 +23,15 @@ #include "WaveRawEvent/RawWaveformContainer.h" #include "WaveRawEvent/RawWaveform.h" +#include "Identifier/Identifier.h" + #include "TF1.h" #include "TRandom3.h" #include <utility> +#include <map> +#include <vector> + ///Interface for waveform digitisation tools class IWaveformDigitisationTool : virtual public IAlgTool @@ -42,19 +47,25 @@ public: virtual ~IWaveformDigitisationTool() = default; - // Digitise HITS to Raw waveform - template<class CONT> - StatusCode digitise(const CONT* hitCollection, - RawWaveformContainer* waveContainer, - TF1* kernel, std::pair<float, float> base - ) const; + /// Evaluate time kernel over time samples + virtual std::vector<float> evaluate_timekernel(TF1* kernel) const = 0; + + /// Generate random baseline + virtual unsigned int generate_baseline(int mean, int rms) const = 0; + + /// Create structure to store pulse for each channel + template <class T> + std::map<Identifier, std::vector<uint16_t>> create_waveform_map(const T* idHelper) const; + + /// Number of time samples + unsigned int nsamples() const { return m_nsamples; } private: ServiceHandle<IMessageSvc> m_msgSvc; protected: TRandom3* m_random; - + unsigned int m_nsamples; }; #include "WaveDigiTools/IWaveformDigitisationTool.icc" diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc index b07e1836ac5cedfefa87a8fcbe8c910de886693c..41b8c2650319a448df63d11e098fc8d0784dc056 100644 --- a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc +++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc @@ -1,62 +1,17 @@ -#include <vector> -#include <map> +#include "Identifier/Identifier.h" +#include "Identifier/ExpandedIdentifier.h" -template<class CONT> -StatusCode IWaveformDigitisationTool::digitise(const CONT* hitCollection, - RawWaveformContainer* container, TF1* kernel, - std::pair<float, float> base) const { +template <class ID> +std::map<Identifier, std::vector<uint16_t>> IWaveformDigitisationTool::create_waveform_map(const ID* idHelper) const { + std::map<Identifier, std::vector<uint16_t>> waveforms; - // Check the container - if (!container) { - MsgStream log(&(*m_msgSvc), name()); - log << MSG::ERROR << "HitCollection passed to digitise() is null!" << endmsg; - return StatusCode::FAILURE; + for (auto itr = idHelper->pmt_begin(); itr != idHelper->pmt_end(); ++itr) { + const ExpandedIdentifier& extId = *itr; + Identifier id = idHelper->pmt_id(extId); + waveforms[id] = std::vector<uint16_t>(); + waveforms[id].reserve(m_nsamples); } - unsigned int size = 600; // TODO: how know the correct number of time samples? - std::vector<float> time(size); - for (unsigned int i=0; i<size; i++) time[i] = 2.*i; - - std::map<unsigned int, std::vector<uint16_t>> waveforms; - //unsigned int baseline = 800; - - // TODO: varying time to centre of edge of bin (odd = centre, even = edge) - - // Loop over time samples - for (const auto& t : time) { - std::map<unsigned int, float> counts; - - unsigned int baseline = m_random->Gaus(base.first, base.second); - - // Convolve hit energy with kernel and sum for each ID (i.e. channel) - for (const auto& hit : *hitCollection) { - counts[hit.identify()] += kernel->Eval(t) * hit.energyLoss(); - //std::cout << "HIT " << hit.identify() << " @ " << t << ": " << kernel->Eval(t) << " " << hit.energyLoss() << " -> " << counts[hit.identify()] << std::endl; - } - - // Add count to correct waveform vec - for (const auto& c : counts) { - int value = baseline - c.second; - if (value < 0) { - MsgStream log(&(*m_msgSvc), name()); - log << MSG::WARNING << "Found pulse " << c.second << " larger than baseline " << c.first << endmsg; - value = 0; // Protect against scaling signal above baseline - } - waveforms[c.first].push_back(value); - //std::cout << "ADC " << c.first << " @ " << t << ": " << baseline - c.second << std::endl; - } - } - - // Loop over wavefrom vecs to make and store waveform - for (const auto& w : waveforms) { - RawWaveform* wfm = new RawWaveform(); - wfm->setWaveform(0, w.second); - wfm->setIdentifier(Identifier(w.first)); - wfm->setSamples(size); - container->push_back(wfm); - } - - - return StatusCode::SUCCESS; + return waveforms; } diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx index 1c71fe193105f089bec81a5821d4a5558cdb39ca..c62d7f8a753490907bd1e8a513cad5341a2a46be 100644 --- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx +++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx @@ -20,8 +20,28 @@ WaveformDigitisationTool::WaveformDigitisationTool(const std::string& type, cons StatusCode WaveformDigitisationTool::initialize() { ATH_MSG_INFO( name() << "::initalize()" ); + + m_nsamples = 600; m_random = new TRandom3(); + return StatusCode::SUCCESS; } +std::vector<float> +WaveformDigitisationTool::evaluate_timekernel(TF1* kernel) const { + + std::vector<float> timekernel; + timekernel.reserve(m_nsamples); + + for (unsigned int i=0; i<m_nsamples; i++) { + timekernel.push_back(kernel->Eval(2.*i)); + } + + return timekernel; +} + +unsigned int +WaveformDigitisationTool::generate_baseline(int mean, int rms) const { + return m_random->Gaus(mean, rms); +} diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h index 8a5ba71f3dd124fcdd2c6b4b8124ee96591512da..e2dd5169152845824927baeeae7ce8fc36ab46f8 100644 --- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h +++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h @@ -28,6 +28,13 @@ class WaveformDigitisationTool: public extends<AthAlgTool, IWaveformDigitisation /// Retrieve the necessary services in initialize StatusCode initialize(); + /// Evaluate time kernel over samples + std::vector<float> evaluate_timekernel(TF1* kernel) const; + + /// Generate random baseline + unsigned int generate_baseline(int mean, int rms) const; + + private: // None diff --git a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py index b3e1e73042c8d608c68865d1328572b1e5b98955..ad6bfcd1519674674ff7d101e320bc47176198ed 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py +++ b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py @@ -2,8 +2,11 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from WaveformConditionsTools.WaveformCableMappingConfig import WaveformCableMappingCfg +from WaveformConditionsTools.WaveformRangeConfig import WaveformRangeCfg def WaveByteStreamCfg(configFlags, **kwargs): - acc = WaveformCableMappingCfg(configFlags, **kwargs) + acc = ComponentAccumulator() + acc.merge(WaveformCableMappingCfg(configFlags, **kwargs)) + acc.merge(WaveformRangeCfg(configFlags, **kwargs)) return acc diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx index f3a9f9991fd0d926584727bc7546fb00ea52732d..852ae084edac08380e302ec3026548d667da70c2 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx +++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx @@ -43,7 +43,8 @@ StatusCode RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, RawWaveformContainer* container, const std::string key, - WaveformCableMap cable_map + WaveformCableMap cable_map, + WaveformRangeMap range_map ) { ATH_MSG_DEBUG("RawWaveformDecoderTool::convert("+key+")"); @@ -90,6 +91,8 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, det_type = std::string("calo"); } else if (key == std::string("VetoWaveforms")) { det_type = std::string("veto"); + } else if (key == std::string("VetoNuWaveforms")) { + det_type = std::string("vetonu"); } else if (key == std::string("TriggerWaveforms")) { det_type = std::string("trigger"); } else if (key == std::string("PreshowerWaveforms")) { @@ -141,10 +144,13 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, } // Set ID if one exists (clock, for instance, doesn't have an identifier) - if (cable_map[channel].second != -1) { // Identifier doesn't have operator>= + if (cable_map.at(channel).second != -1) { // Identifier doesn't have operator>= wfm->setIdentifier(cable_map[channel].second); } + // Set ADC range + wfm->setRange(range_map.at(channel)); + container->push_back(wfm); // Sanity check diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h index 1609d3ebacd3940bdfcd89f3c1af39b2a0a9c648..5d3ff24600e76a6d37c7e5bb60e0729e36bb71ac 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h +++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h @@ -14,6 +14,7 @@ #include "WaveRawEvent/RawWaveformContainer.h" #include "WaveformConditionsTools/IWaveformCableMappingTool.h" +#include "WaveformConditionsTools/IWaveformRangeTool.h" // This class provides conversion between bytestream and Waveform objects @@ -30,7 +31,7 @@ class RawWaveformDecoderTool : public AthAlgTool { virtual StatusCode initialize(); virtual StatusCode finalize(); - StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key, WaveformCableMap cable_map); + StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key, WaveformCableMap cable_map, WaveformRangeMap range_map); private: }; diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx index b40fc3bd8dda5469e52be5d297ad29cf4dc2e98b..38d1cc20c5240277d6a985c2ba8e57d064baa49f 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx +++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx @@ -27,6 +27,7 @@ WaveByteStreamCnv::WaveByteStreamCnv(ISvcLocator* svcloc) , m_name("WaveByteStreamCnv") , m_tool("RawWaveformDecoderTool") , m_mappingTool("WaveformCableMappingTool") + , m_rangeTool("WaveformRangeTool") , m_rdpSvc("FaserROBDataProviderSvc", m_name) { ATH_MSG_DEBUG(m_name+"::initialize() called"); @@ -49,7 +50,7 @@ StatusCode WaveByteStreamCnv::initialize() CHECK(m_rdpSvc.retrieve()); CHECK(m_tool.retrieve()); CHECK(m_mappingTool.retrieve()); - + CHECK(m_rangeTool.retrieve()); return StatusCode::SUCCESS; } @@ -96,8 +97,11 @@ StatusCode WaveByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj auto mapping = m_mappingTool->getCableMapping(); ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries"); + auto range = m_rangeTool->getRangeMapping(); + ATH_MSG_DEBUG("Range contains " << range.size() << " entries"); + // Convert selected channels - CHECK( m_tool->convert(re, wfmCont, key, mapping) ); + CHECK( m_tool->convert(re, wfmCont, key, mapping, range) ); pObj = SG::asStorable(wfmCont); diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h index ce373326fd61a3ab9f8552b5a6f561b449cc6850..960b8759e2f72633eae58efb882d67848cdfee07 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h +++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h @@ -15,6 +15,7 @@ #include "AthenaBaseComps/AthMessaging.h" #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h" #include "WaveformConditionsTools/IWaveformCableMappingTool.h" +#include "WaveformConditionsTools/IWaveformRangeTool.h" class RawWaveformDecoderTool; class IFaserROBDataProviderSvc; @@ -41,6 +42,7 @@ private: std::string m_name; ToolHandle<RawWaveformDecoderTool> m_tool; ToolHandle<IWaveformCableMappingTool> m_mappingTool; + ToolHandle<IWaveformRangeTool> m_rangeTool; ServiceHandle<IFaserROBDataProviderSvc> m_rdpSvc; }; diff --git a/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h b/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h index 3770e05513a4d6f81ca16aa08785ea0c36a459cb..a1f42f6e86db846ea544daedb482ba8aba8fbdf5 100644 --- a/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h +++ b/Waveform/WaveRawEvent/WaveRawEvent/RawWaveform.h @@ -62,11 +62,17 @@ public: // Waveform data unsigned int channel() const; const std::vector<unsigned int>& adc_counts() const; + size_t size() const {return m_adc_counts.size();} // Return channel identifier Identifier identify() const; Identifier32 identify32() const; + // Full-scale range (in V) of 14-bit ADC reading + // mV per bit is given by range() / 16.384 + float range() const; + float mv_per_bit() const {return m_range / 16.384;} + // some print-out: void print() const; @@ -89,6 +95,8 @@ public: void setSamples(unsigned int samp) {m_samples = samp;} void setCounts(const std::vector<unsigned int>& counts) {m_adc_counts = counts;} + void setRange(float range) {m_range = range;} + /////////////////////////////////////////////////////////////////// // Private data: /////////////////////////////////////////////////////////////////// @@ -105,6 +113,8 @@ private: std::vector<unsigned int> m_adc_counts; Identifier32 m_ID; + + float m_range; }; @@ -145,6 +155,9 @@ RawWaveform::identify() const { return Identifier(m_ID); } inline Identifier32 RawWaveform::identify32() const { return m_ID; } +inline float +RawWaveform::range() const { return m_range; } + std::ostream &operator<<(std::ostream &out, const RawWaveform &wfm); diff --git a/Waveform/WaveRawEvent/src/RawWaveform.cxx b/Waveform/WaveRawEvent/src/RawWaveform.cxx index d6ef63493018955a79d42eb2c4f7fe2eebc40de2..64c401dfad6a9fe9794737a953eca31eff110bc1 100644 --- a/Waveform/WaveRawEvent/src/RawWaveform.cxx +++ b/Waveform/WaveRawEvent/src/RawWaveform.cxx @@ -17,7 +17,8 @@ RawWaveform::RawWaveform( ) : m_samples(0), m_channel(0), m_adc_counts(), - m_ID(0xffff) + m_ID(0xffff), + m_range(2.) { } diff --git a/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py b/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py index d38eb4fd0a7ce0c26ffa1a78fd52a91f0261ac94..414773bf9dc2e9b8140b33d81a80220c4288e4bf 100644 --- a/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py +++ b/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py @@ -6,30 +6,26 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg +from WaveformConditionsTools.WaveformTimingConfig import WaveformTimingCfg WaveformReconstructionTool = CompFactory.WaveformReconstructionTool ClockReconstructionTool = CompFactory.ClockReconstructionTool # One stop shopping for normal FASER data -def WaveformReconstructionCfg(flags, naive = False): +def WaveformReconstructionCfg(flags): """ Return all algorithms and tools for Waveform reconstruction """ acc = ComponentAccumulator() if not flags.Input.isMC: acc.merge(WaveformClockRecCfg(flags, "ClockRecAlg")) - if flags.Input.isMC and naive: - if "TB" not in flags.GeoModel.FaserVersion: - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoTriggerHitWaveformRecAlg", "Trigger")) - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoVetoHitToWaveformRecAlg", "Veto")) - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoPresehowerHitWaveformRecAlg", "Preshower")) - acc.merge(PseudoCaloHitToWaveformRecCfg(flags, "PseudoCaloHitWaveformRecAlg")) - return acc - acc.merge(WaveformHitRecCfg(flags, "TriggerWaveformRecAlg", "Trigger")) acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto")) acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower")) acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo")) + acc.merge(WaveformHitRecCfg(flags, "VetoNuWaveformRecAlg", "VetoNu")) + + acc.merge(WaveformTimingCfg(flags)) return acc @@ -49,13 +45,13 @@ def WaveformClockRecCfg(flags, name="ClockRecAlg", **kwargs): return acc # Return configured WaveformHit reconstruction algorithm -# Specify data source (Veto, Trigger, Preshower, Calo, Test) +# Specify data source (Veto, VetoNu, Trigger, Preshower, Calo, Test) def WaveformHitRecCfg(flags, name="WaveformRecAlg", source="", **kwargs): acc = ComponentAccumulator() - if flags.Input.isMC: - kwargs.setdefault("PeakThreshold", 5) + #if flags.Input.isMC: + # kwargs.setdefault("PeakThreshold", 5) tool = WaveformReconstructionTool(name=source+"WaveformRecTool", **kwargs) diff --git a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx index 97f122e50f51c17f2ac3f0e0ff3174cf2f337347..8f8ac480969aea1f424021e3985e695d21318783 100644 --- a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx +++ b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx @@ -31,9 +31,10 @@ RawWaveformRecAlg::finalize() { ATH_MSG_INFO( m_numberOfEvents << " events processed" ); if ( m_numberOfEvents > 0) { - ATH_MSG_INFO( m_numberOfWaveforms << " waveforms found" ); - ATH_MSG_INFO( m_numberOfOverflows << " overflows" ); - ATH_MSG_INFO( m_numberOfFitErrors << " fit errors" ); + ATH_MSG_INFO( m_numberOfWaveforms << " waveforms found over threshold" ); + ATH_MSG_INFO( m_numberOfSecondaries << " secondary waveforms found" ); + ATH_MSG_INFO( m_numberOfOverflows << " overflows" ); + ATH_MSG_INFO( m_numberOfFitErrors << " fit errors" ); } return StatusCode::SUCCESS; @@ -43,6 +44,9 @@ StatusCode RawWaveformRecAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("Executing"); + // Keep track of some statistics + m_numberOfEvents++; + ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() << " Event: " << ctx.eventID().event_number()); @@ -52,41 +56,56 @@ RawWaveformRecAlg::execute(const EventContext& ctx) const { ATH_CHECK( waveformHandle.isValid() ); ATH_MSG_DEBUG("Found ReadHandle for RawWaveformContainer " << m_waveformContainerKey); + // Find the output waveform container + SG::WriteHandle<xAOD::WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx); + ATH_CHECK( hitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(), + std::make_unique<xAOD::WaveformHitAuxContainer>() ) ); + + ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' initialized"); + if (waveformHandle->size() == 0) { ATH_MSG_DEBUG("Waveform container found with zero length!"); return StatusCode::SUCCESS; } + // First reconstruct the primary hit (based on trigger time) + for( const auto& wave : *waveformHandle) { + ATH_MSG_DEBUG("Reconstruct primary waveform for channel " << wave->channel()); + CHECK( m_recoTool->reconstructPrimary(*wave, hitContainerHandle.ptr()) ); + } + + // Second, reconstruct any additional out of time hits + if (m_findMultipleHits) { + for( const auto& wave : *waveformHandle) { + ATH_MSG_DEBUG("Reconstruct secondary waveform for channel " << wave->channel()); + CHECK( m_recoTool->reconstructSecondary(*wave, hitContainerHandle.ptr()) ); + } + } + // Also find the clock information SG::ReadHandle<xAOD::WaveformClock> clockHandle(m_clockKey, ctx); const xAOD::WaveformClock* clockptr = NULL; + // Fix timing for all hits // Can survive without this, but make a note if ( clockHandle.isValid() ) { ATH_MSG_DEBUG("Found ReadHandle for WaveformClock"); clockptr = clockHandle.ptr(); + CHECK( m_recoTool->setLocalTime(clockptr, hitContainerHandle.ptr()) ); } else { ATH_MSG_WARNING("Didn't find ReadHandle for WaveformClock!"); } - // Find the output waveform container - SG::WriteHandle<xAOD::WaveformHitContainer> hitContainerHandle(m_waveformHitContainerKey, ctx); - ATH_CHECK( hitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(), - std::make_unique<xAOD::WaveformHitAuxContainer>() ) ); - - ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' initialized"); - - // Reconstruct all waveforms - CHECK( m_recoTool->reconstructAll(*waveformHandle, clockptr, hitContainerHandle.ptr()) ); - ATH_MSG_DEBUG("WaveformsHitContainer '" << hitContainerHandle.name() << "' filled with "<< hitContainerHandle->size() <<" items"); // Keep track of some statistics - m_numberOfEvents++; for (const auto& hit : *(hitContainerHandle.ptr())) { if (hit->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED)) continue; + m_numberOfWaveforms++; if (hit->status_bit(xAOD::WaveformStatus::WAVE_OVERFLOW)) m_numberOfOverflows++; + if (hit->status_bit(xAOD::WaveformStatus::SECONDARY)) m_numberOfSecondaries++; + if (hit->status_bit(xAOD::WaveformStatus::GFIT_FAILED)) { m_numberOfFitErrors++; } else if (hit->status_bit(xAOD::WaveformStatus::CBFIT_FAILED)) { diff --git a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h index e57501a730dd5f67c38435cb9594b0a7def2ec75..4de415d21d162a3aa2b64fe7f1ef1bb14e0237d9 100644 --- a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h +++ b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h @@ -42,6 +42,10 @@ class RawWaveformRecAlg : public AthReentrantAlgorithm { virtual StatusCode finalize() override; //@} + // + // Look for more than one hit in each channel + BooleanProperty m_findMultipleHits{this, "FindMultipleHits", true}; + private: /** @name Disallow default instantiation, copy, assignment */ @@ -90,6 +94,7 @@ class RawWaveformRecAlg : public AthReentrantAlgorithm { //@{ mutable std::atomic<int> m_numberOfEvents{0}; mutable std::atomic<int> m_numberOfWaveforms{0}; + mutable std::atomic<int> m_numberOfSecondaries{0}; mutable std::atomic<int> m_numberOfOverflows{0}; mutable std::atomic<int> m_numberOfFitErrors{0}; //@} diff --git a/Waveform/WaveRecTools/CMakeLists.txt b/Waveform/WaveRecTools/CMakeLists.txt index d8f3e6f053232477a1b1501a26e3a88efe9272c1..7c42c848a64280325967fc058b7d9e8ac31170e3 100644 --- a/Waveform/WaveRecTools/CMakeLists.txt +++ b/Waveform/WaveRecTools/CMakeLists.txt @@ -13,13 +13,16 @@ atlas_add_library( WaveRecToolsLib WaveRecTools/*.h src/*.cxx src/*.h PUBLIC_HEADERS WaveRecTools PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives WaveRawEvent xAODFaserWaveform + LINK_LIBRARIES AthenaBaseComps AthenaKernel GeoPrimitives + WaveformConditionsToolsLib WaveRawEvent xAODFaserWaveform Identifier PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ) atlas_add_component( WaveRecTools src/components/*.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel WaveRecToolsLib ) + LINK_LIBRARIES ${ROOT_LIBRARIES} + WaveformConditionsToolsLib AthenaBaseComps GaudiKernel + WaveRecToolsLib) diff --git a/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.h b/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.h index 6ba6e4eacdb8288a5f3667b02c3823aeaeb54d7e..fda076b2ae7a2a22bc5743b32eded9b92a006da3 100644 --- a/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.h +++ b/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.h @@ -23,6 +23,8 @@ #include "xAODFaserWaveform/WaveformHitContainer.h" #include "xAODFaserWaveform/WaveformHit.h" +class Identifier; + ///Interface for Pseudo waveform rec tools class IPseudoSimToWaveformRecTool : virtual public IAlgTool { @@ -31,9 +33,11 @@ public: // InterfaceID DeclareInterfaceID(IPseudoSimToWaveformRecTool, 1, 0); + /* IPseudoSimToWaveformRecTool(): m_msgSvc ( "MessageSvc", "ITrkEventCnvTool" ) {} + */ virtual ~IPseudoSimToWaveformRecTool() = default; @@ -42,8 +46,9 @@ public: StatusCode reconstruct(const CONT* hitCollection, xAOD::WaveformHitContainer* waveContainer) const; -private: - ServiceHandle<IMessageSvc> m_msgSvc; + // Make the actual hits (separate this so it doesn't need to be in templated function + virtual StatusCode make_hits(const std::map<Identifier, float>& sums, + xAOD::WaveformHitContainer* waveContainer) const = 0; }; diff --git a/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.icc b/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.icc index 9f85c6b020b3efc9d81949cbf914b2a424bda19b..29a689bdc2e3c7c665f08df1462ba6afb237fd84 100644 --- a/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.icc +++ b/Waveform/WaveRecTools/WaveRecTools/IPseudoSimToWaveformRecTool.icc @@ -2,35 +2,12 @@ template<class CONT> StatusCode IPseudoSimToWaveformRecTool::reconstruct(const CONT* hitCollection, xAOD::WaveformHitContainer* container) const { - - // Check the container - if (!container) { - MsgStream log(&(*m_msgSvc), name()); - log << MSG::ERROR << "HitCollection passed to reconstruct() is null!" << endmsg; - return StatusCode::FAILURE; - } - - std::map<int, float> idSums; + std::map<Identifier, float> idSums; // Sum hits in each "channel" for (const auto& hit : *hitCollection) { - idSums[hit.identify()] += hit.energyLoss(); - } - - for (const auto& id : idSums) { - xAOD::WaveformHit* hit = new xAOD::WaveformHit(); - container->push_back(hit); - - hit->set_id(id.first); - hit->set_channel(0); - hit->set_peak(0); - hit->set_mean(0); - hit->set_width(0); - hit->set_integral(id.second); - hit->set_localtime(0); - hit->set_raw_peak(0); - hit->set_raw_integral(0); + idSums[hit.getIdentifier()] += hit.energyLoss(); } - return StatusCode::SUCCESS; + return make_hits(idSums, container); } diff --git a/Waveform/WaveRecTools/WaveRecTools/IWaveformReconstructionTool.h b/Waveform/WaveRecTools/WaveRecTools/IWaveformReconstructionTool.h index cc10197b262f0695327f7304a84998d198300678..c72c2502c9391861a3aec0696f47d568a7d7aa2b 100644 --- a/Waveform/WaveRecTools/WaveRecTools/IWaveformReconstructionTool.h +++ b/Waveform/WaveRecTools/WaveRecTools/IWaveformReconstructionTool.h @@ -32,15 +32,17 @@ class IWaveformReconstructionTool : virtual public IAlgTool virtual ~IWaveformReconstructionTool() = default; - // Reconstruct all waveforms - virtual StatusCode reconstructAll(const RawWaveformContainer& waveContainer, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* container) const = 0; - - // Reconstruct all peaks in a raw waveform - virtual StatusCode reconstruct(const RawWaveform& wave, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* container) const = 0; + // Reconstruct hits in trigger window + virtual StatusCode reconstructPrimary(const RawWaveform& wave, + xAOD::WaveformHitContainer* container) const = 0; + + // Reconstruct secondary hits anywhere in the waveform + virtual StatusCode reconstructSecondary(const RawWaveform& wave, + xAOD::WaveformHitContainer* container) const = 0; + + // Set local hit times from LHC clock + virtual StatusCode setLocalTime(const xAOD::WaveformClock* clock, + xAOD::WaveformHitContainer* container) const = 0; }; diff --git a/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx b/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx index c45ea51007362eecd0ab7827f50123c05ddebab7..825cc755862200c0dd008eaf3c273cb23b37f83a 100644 --- a/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx +++ b/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx @@ -102,10 +102,10 @@ ClockReconstructionTool::reconstruct(const RawWaveform& raw_wave, ATH_MSG_DEBUG("Index: " << i << " Freq: " << i*freqmult << " Mag: " << magnitude[i]); } - // Store results - clockdata->set_dc_offset(magnitude[0]); + // Store results (amplitides in mV) + clockdata->set_dc_offset(raw_wave.mv_per_bit()*magnitude[0]); + clockdata->set_amplitude(raw_wave.mv_per_bit()*magnitude[imax]); clockdata->set_frequency(imax * freqmult); - clockdata->set_amplitude(magnitude[imax]); clockdata->set_phase(atan2(im_full[imax], re_full[imax])); // Not a bug, atan2(y,x)! ATH_MSG_DEBUG("Before correcting for finite resolution:"); @@ -133,7 +133,7 @@ ClockReconstructionTool::reconstruct(const RawWaveform& raw_wave, clockdata->set_frequency( (imax+dm) * freqmult ); clockdata->set_phase (phase); - clockdata->set_amplitude( 2*M_PI*dm*magnitude[imax] / sin(M_PI * dm) ); + clockdata->set_amplitude( raw_wave.mv_per_bit() * 2*M_PI*dm*magnitude[imax] / sin(M_PI * dm) ); ATH_MSG_DEBUG("After correcting for finite resolution:"); ATH_MSG_DEBUG(*clockdata); diff --git a/Waveform/WaveRecTools/src/ClockReconstructionTool.h b/Waveform/WaveRecTools/src/ClockReconstructionTool.h index ea7ec2ec7e2a28e49d587f9a7f072678ee4bdbc5..78e6ea1770c069314ee15a068458f88623b63bda 100644 --- a/Waveform/WaveRecTools/src/ClockReconstructionTool.h +++ b/Waveform/WaveRecTools/src/ClockReconstructionTool.h @@ -51,8 +51,8 @@ class ClockReconstructionTool: public extends<AthAlgTool, IClockReconstructionTo void checkResult(const RawWaveform& raw_wave, xAOD::WaveformClock* clockdata) const; - // Limits to print warnings - FloatProperty m_amplitude_min{this, "AmplitudeMin", 1000.}; + // Limits to print warnings (amplitude in mV) + FloatProperty m_amplitude_min{this, "AmplitudeMin", 500.}; FloatProperty m_frequency_min{this, "FrequencyMin", 40.0}; FloatProperty m_frequency_max{this, "FrequencyMax", 40.1}; diff --git a/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.cxx b/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.cxx index 6d894aeb64125274507105bd71ce37c7ad2bed31..93ae1397e3c591b2f54b3765f0138042878e25bc 100644 --- a/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.cxx +++ b/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.cxx @@ -10,18 +10,9 @@ #include "PseudoSimToWaveformRecTool.h" +#include "Identifier/Identifier.h" #include "xAODFaserWaveform/WaveformHit.h" -#include "TH1F.h" -#include "TF1.h" -#include "TFitResult.h" -#include "TFitResultPtr.h" -#include "TGraph.h" - -#include <vector> -#include <tuple> -#include <math.h> - // Constructor PseudoSimToWaveformRecTool::PseudoSimToWaveformRecTool(const std::string& type, const std::string& name, const IInterface* parent) : base_class(type, name, parent) @@ -32,7 +23,43 @@ PseudoSimToWaveformRecTool::PseudoSimToWaveformRecTool(const std::string& type, StatusCode PseudoSimToWaveformRecTool::initialize() { ATH_MSG_INFO( name() << "::initalize()" ); + + ATH_CHECK( m_mappingTool.retrieve() ); + return StatusCode::SUCCESS; } +StatusCode +PseudoSimToWaveformRecTool::make_hits(const std::map<Identifier, float>& sums, + xAOD::WaveformHitContainer* container) const { + +// Check the container + if (!container) { + ATH_MSG_ERROR("HitCollection passed to reconstruct() is null!"); + return StatusCode::FAILURE; + } + + // Get the nominal trigger time (in ns) from config + // For now, hack up the timing to match the configuration + //float trigger_time = m_timingTool->nominalTriggerTime(); + //float offset; + + for (const auto& id : sums) { + xAOD::WaveformHit* hit = new xAOD::WaveformHit(); + container->push_back(hit); + + hit->set_identifier(id.first); + hit->set_channel(m_mappingTool->getChannelMapping(id.first)); + hit->set_peak(0); + hit->set_mean(0); + hit->set_width(0); + hit->set_integral(id.second); + hit->set_localtime(0); + hit->set_trigger_time(0); + hit->set_raw_peak(0); + hit->set_raw_integral(0); + } + + return StatusCode::SUCCESS; +} diff --git a/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.h b/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.h index f3376f6ec4aa93becef3da8fc52c19d003d6dced..e117479737d3dad28c1a8dfb7065ab1742d13884 100644 --- a/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.h +++ b/Waveform/WaveRecTools/src/PseudoSimToWaveformRecTool.h @@ -13,10 +13,13 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "WaveRecTools/IPseudoSimToWaveformRecTool.h" +// Tool classes +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" + //Gaudi #include "GaudiKernel/ToolHandle.h" -//STL +class Identifier; class PseudoSimToWaveformRecTool: public extends<AthAlgTool, IPseudoSimToWaveformRecTool> { public: @@ -28,8 +31,12 @@ class PseudoSimToWaveformRecTool: public extends<AthAlgTool, IPseudoSimToWavefor /// Retrieve the necessary services in initialize StatusCode initialize(); + virtual StatusCode make_hits(const std::map<Identifier, float>& sums, + xAOD::WaveformHitContainer* waveContainer) const; + private: - // None + ToolHandle<IWaveformCableMappingTool> m_mappingTool + {this, "WaveformCableMappingTool", "WaveformCableMappingTool"}; }; diff --git a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx index ce9504ee183b2a8c25694b62041f6929db6e8290..8882027bfc13a7b28a7043f2b9feb70ed8e25877 100644 --- a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx +++ b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx @@ -39,187 +39,290 @@ WaveformReconstructionTool::initialize() { } else { ATH_MSG_INFO("Will use fit to determine baseline"); } + + ATH_CHECK( m_timingTool.retrieve() ); + return StatusCode::SUCCESS; } -// Reconstruction step +// +// Form primary hits using trigger time +// StatusCode -WaveformReconstructionTool::reconstructAll( - const RawWaveformContainer& waveContainer, - const xAOD::WaveformClock* clock, +WaveformReconstructionTool::reconstructPrimary( + const RawWaveform& wave, xAOD::WaveformHitContainer* hitContainer) const { - ATH_MSG_DEBUG(" reconstructAll called "); + ATH_MSG_DEBUG(" reconstructPrimary called"); - // Reconstruct each waveform - for( const auto& wave : waveContainer) { + xAOD::WaveformHit* newhit = new xAOD::WaveformHit(); + hitContainer->push_back(newhit); - ATH_MSG_DEBUG("Reconstruct waveform for channel " << wave->channel()); + // Set digitizer channel and identifier + newhit->set_channel(wave.channel()); + newhit->set_identifier(wave.identify()); + + // Make sure we have ADC counts + if (wave.adc_counts().size() == 0) { + ATH_MSG_WARNING( "Found waveform for channel " << wave.channel() + << " with size " << wave.adc_counts().size() << "!"); + + newhit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_MISSING); + return StatusCode::SUCCESS; + } - // Reconstruct the hits, may be more than one, so pass container - CHECK( this->reconstruct(*wave, clock, hitContainer) ); + if (wave.adc_counts().size() != wave.n_samples()) { + ATH_MSG_WARNING( "Found waveform for channel " << wave.channel() + << " with size " << wave.adc_counts().size() + << " not equal to number of samples " << wave.n_samples()); + + newhit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID); + return StatusCode::SUCCESS; } - if (m_ensureChannelHits) { - ATH_MSG_DEBUG("Ensure all channels have hits at peak time"); - ensureHits(waveContainer, clock, hitContainer); + // Find the baseline for this waveform + findBaseline(wave, newhit); + + // Check for problems + if (newhit->status_bit(xAOD::WaveformStatus::BASELINE_FAILED)) + return StatusCode::SUCCESS; + + // Get the nominal trigger time (in ns) from config + float trigger_time = m_timingTool->nominalTriggerTime(); + + // Set range for windowed data in digitizer samples + float offset = m_timingTool->triggerTimeOffset(wave.channel()); + + int lo_edge = int((trigger_time+offset)/2.) + m_windowStart; + int hi_edge = int((trigger_time+offset)/2.) + m_windowStart + m_windowWidth; + + // Fill raw hit values + fillRawHitValues(wave, lo_edge, hi_edge, newhit); + + // Check if this is over threshold + if (newhit->peak() < newhit->baseline_rms() * m_primaryPeakThreshold) { + ATH_MSG_DEBUG("Primary hit failed threshold"); + newhit->set_status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED); + } else { + // Reconstruct hit in this range + reconstructHit(newhit); } return StatusCode::SUCCESS; } // -// Make sure we have a hit for each channel at the time when -// there is a significant pulse found in the detector +// Form primary hits using trigger time // -void -WaveformReconstructionTool::ensureHits( - const RawWaveformContainer& waveContainer, - const xAOD::WaveformClock* clock, +StatusCode +WaveformReconstructionTool::reconstructSecondary( + const RawWaveform& wave, xAOD::WaveformHitContainer* hitContainer) const { - ATH_MSG_DEBUG(" ensureHits called "); + ATH_MSG_DEBUG(" reconstructSecondary called"); - // Find peak time (most significant hit) - xAOD::WaveformHit* peakHit = NULL; + // Find existing hit for this channel to get baseline + xAOD::WaveformHit* primaryHit = NULL; for( const auto& hit : *hitContainer) { - if (peakHit == NULL) { - peakHit = hit; - } else { - if ( hit->peak() > peakHit->peak() ) peakHit = hit; + // Use id rather than channel to make sure this works on MC + if (hit->identify() == wave.identify()) { + ATH_MSG_DEBUG("Found primary hit in channel "<< hit->channel() + << " with id 0x" << std::hex << hit->identify() << std::dec ); + primaryHit = hit; + break; } + } + // Did we find the primary hit for this channel? + if (!primaryHit) { + ATH_MSG_ERROR("found no primary hit for channel " << wave.channel() << "!"); + return StatusCode::FAILURE; } - // Didn't find anything? - if (peakHit == NULL) return; - if (peakHit->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED)) return; + if (primaryHit->status_bit(xAOD::WaveformStatus::WAVEFORM_MISSING)) { + ATH_MSG_DEBUG("Found primary hit with waveform missing"); + return StatusCode::SUCCESS; + } - ATH_MSG_DEBUG("Found peak hit in channel " << peakHit->channel() << " at time " << peakHit->localtime()); + if (primaryHit->status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID)) { + ATH_MSG_DEBUG("Found primary hit with waveform invalid"); + return StatusCode::SUCCESS; + } - // Now go through all of the channels and check if there is a hit - // close in time to the peakHit - for( const auto& wave : waveContainer) { + WaveformBaselineData baseline; - // Don't worry about the peak channel, we know this has a hit... - if (wave->channel() == peakHit->channel()) continue; + baseline.mean = primaryHit->baseline_mean(); + baseline.rms = primaryHit->baseline_rms(); + + // Find the secondary peak position + int ipeak; - ATH_MSG_DEBUG("Checking for hit in channel " << wave->channel()); + // Is there already a peak in the primary? + if (primaryHit->threshold()) { - bool found = false; - // Look for a baseline-only hit that we can update - xAOD::WaveformHit* baselineHit = NULL; + ATH_MSG_DEBUG("Looking for secondary hit with primary hit above threshold"); - // There aren't so many hits, just loop over container - for( const auto& hit : *hitContainer) { - if (hit->channel() != wave->channel()) continue; + // Look before and after window + int lo_edge = int(primaryHit->time_vector().front()/2.); + int hi_edge = int(primaryHit->time_vector().back()/2.); - // Is this above threshold? - if (hit->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED)) { - baselineHit = hit; - continue; - } + std::vector<float> wwave_lo(lo_edge); + std::vector<float> wwave_hi(wave.adc_counts().size() - hi_edge - 1); - // OK, this is the right channel, check the time - float dtime = abs(hit->localtime() - peakHit->localtime()); - if (dtime > m_hitTimeDifference) continue; + int ipeak_lo = -1.; + int ipeak_hi = -1.; - // We have found a hit in the right channel at the right time - found = true; - ATH_MSG_DEBUG("Found hit in channel " << hit->channel() - << " at time " << hit->localtime()); - break; - } + // Look before + if (m_findSecondaryBefore) { + for (int i=0; i<lo_edge; i++) { + wwave_lo[i] = baseline.mean - wave.mv_per_bit() * wave.adc_counts()[i]; + } - // Is there a hit? If so, go to next waveform/channel - if (found) continue; + ipeak_lo = findPeak(baseline, m_secondaryPeakThreshold, wwave_lo); - ATH_MSG_DEBUG("No hit found for channel " << wave->channel() - << " at time " << peakHit->localtime()); + if (ipeak_lo < 0) { + ATH_MSG_DEBUG("No hit found before " << lo_edge); + } else { + ATH_MSG_DEBUG("Hit found at " << ipeak_lo << " before " << lo_edge); + } + } - // Do we have a baseline-only hit we can use? - xAOD::WaveformHit* newhit = NULL; - if (baselineHit == NULL) { - // No, make a new hit here - newhit = new xAOD::WaveformHit(); - hitContainer->push_back(newhit); + // Look after + if (m_findSecondaryAfter) { + for (unsigned int i=(hi_edge+1); i<wave.adc_counts().size(); i++) { + wwave_hi[(i-(hi_edge+1))] = baseline.mean - wave.mv_per_bit() * wave.adc_counts()[i]; + } - // Mark this as a secondary hit - newhit->set_status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED); - newhit->set_status_bit(xAOD::WaveformStatus::SECONDARY); + ipeak_hi = findPeak(baseline, m_secondaryPeakThreshold, wwave_hi); - // Set digitizer channel and identifier - newhit->set_channel(wave->channel()); - newhit->set_id(wave->identify32().get_compact()); + // Is this too close to the primary hit? + if (ipeak_hi < 5) { + ATH_MSG_DEBUG("Found hit after at " << (ipeak_hi + hi_edge + 1)<< " but too close to edge"); + ipeak_hi = -1; + } - // Make sure we have ADC counts - if (wave->adc_counts().size() == 0) { - ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() - << " with size " << wave->adc_counts().size() << "!"); - - newhit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_MISSING); - continue; - } - - if (wave->adc_counts().size() != wave->n_samples()) { - ATH_MSG_WARNING( "Found waveform for channel " << wave->channel() - << " with size " << wave->adc_counts().size() - << " not equal to number of samples " << wave->n_samples()); - - newhit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID); - continue; + if (ipeak_hi < 0) { + ATH_MSG_DEBUG("No hit found after " << hi_edge); + } else { + ATH_MSG_DEBUG("Hit found at " << ipeak_hi << " after " << hi_edge); } + } - findBaseline(*wave, newhit); + // Nothing found + if (ipeak_lo < 0 && ipeak_hi < 0) + return StatusCode::SUCCESS; + + // Both? + if (ipeak_lo >= 0 && ipeak_hi >= 0) { + + // Pick the largest signal + if (wwave_lo[ipeak_lo] >= wwave_hi[ipeak_hi]) { + ipeak = ipeak_lo; + ATH_MSG_DEBUG("Picked before as " << wwave_lo[ipeak_lo] + << " > " << wwave_hi[ipeak_hi]); + } else { + ipeak = ipeak_hi + hi_edge + 1; + ATH_MSG_DEBUG("Picked after as " << wwave_lo[ipeak_lo] + << " < " << wwave_hi[ipeak_hi]); + } + + } else if (ipeak_lo > 0) { + ipeak = ipeak_lo; + ATH_MSG_DEBUG("Peak before with " << wwave_lo[ipeak_lo]); } else { - // Use the existing baseline hit - newhit = baselineHit; + ATH_MSG_DEBUG("Peak after with " << wwave_hi[ipeak_hi]); + ipeak = ipeak_hi+hi_edge+1; } - // Check for problems - if (newhit->status_bit(xAOD::WaveformStatus::BASELINE_FAILED)) continue; - - // Set range for windowed data - unsigned int lo_edge = peakHit->time_vector().front()/2.; - unsigned int hi_edge = peakHit->time_vector().back()/2.; - - ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge); - std::vector<float> wtime(hi_edge-lo_edge+1); - std::vector<float> wwave(hi_edge-lo_edge+1); - for (unsigned int i=lo_edge; i<=hi_edge; i++) { - unsigned int j = i-lo_edge; - wtime[j] = 2.*i; - wwave[j] = newhit->baseline_mean() - wave->adc_counts()[i]; - //ATH_MSG_DEBUG(" Time: " << wtime[j] << " Wave: " << wwave[j]); + } else { + + ATH_MSG_DEBUG("Looking for secondary hit without primary hit above threshold"); + std::vector<float> wwave(wave.adc_counts().size()); + for (unsigned int i=0; i<wave.adc_counts().size(); i++) { + wwave[i] = baseline.mean - wave.mv_per_bit() * wave.adc_counts()[i]; } - newhit->set_time_vector(wtime); - newhit->set_wave_vector(wwave); + ipeak = findPeak(baseline, m_secondaryPeakThreshold, wwave); - // - // Find some raw values - WaveformFitResult raw = findRawHitValues(wtime, wwave); - newhit->set_peak(raw.peak); - newhit->set_mean(raw.mean); - newhit->set_width(raw.sigma); - newhit->set_integral(raw.integral); - newhit->set_localtime(raw.mean); - newhit->set_raw_peak(raw.peak); - newhit->set_raw_integral(raw.integral); + // Nothing found + if (ipeak < 0) + return StatusCode::SUCCESS; + + ATH_MSG_DEBUG("Found secondary peak with no primary " << wwave[ipeak]); + } + + // We seem to have a secondary hit + xAOD::WaveformHit* newhit = new xAOD::WaveformHit(); + hitContainer->push_back(newhit); + + // Fill values + newhit->set_channel(wave.channel()); + newhit->set_identifier(wave.identify()); + newhit->set_status_bit(xAOD::WaveformStatus::SECONDARY); + newhit->set_baseline_mean(baseline.mean); + newhit->set_baseline_rms(baseline.rms); + + // Set range for windowed data in digitizer samples + int lo_edge = ipeak + m_windowStart; + int hi_edge = ipeak + m_windowStart + m_windowWidth; + + // Fill raw hit values + fillRawHitValues(wave, lo_edge, hi_edge, newhit); + + // Must be over threshold, so reconstruct here + reconstructHit(newhit); + + return StatusCode::SUCCESS; +} + +StatusCode +WaveformReconstructionTool::setLocalTime(const xAOD::WaveformClock* clock, + xAOD::WaveformHitContainer* container) const { + + ATH_MSG_DEBUG(" setLocalTime called "); + + // Check the container + if (!container) { + ATH_MSG_ERROR("WaveformHitCollection passed to setLocalTime() is null!"); + return StatusCode::FAILURE; + } + + bool clock_valid; + + // + // Find time from clock + if (!clock || (clock->frequency() <= 0.)) { + clock_valid = false; + } else { + clock_valid = true; + } + + float trigger_time = m_timingTool->nominalTriggerTime(); + float offset; + + // Should actually find the time of the trigger here + // and set bcid time offset from that + // Loop through hits and set local time + for( const auto& hit : *container) { // // Find time from clock - if (!clock || (clock->frequency() <= 0.)) { - newhit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID); - newhit->set_bcid_time(-1.); + if (clock_valid) { + hit->set_bcid_time(clock->time_from_clock(hit->localtime())); } else { - newhit->set_bcid_time(clock->time_from_clock(newhit->localtime())); + hit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID); + hit->set_bcid_time(-1.); } - } // End of loop over waveContainer + // Also set time with respect to nominal trigger + offset = m_timingTool->triggerTimeOffset(hit->channel()); + hit->set_trigger_time(hit->localtime() - (trigger_time + offset)); + } + + return StatusCode::SUCCESS; } // Find the baseline @@ -245,187 +348,131 @@ WaveformReconstructionTool::findBaseline(const RawWaveform& raw_wave, } else { // Save baseline to hit collection object - hit->set_baseline_mean(baseline.mean); - hit->set_baseline_rms(baseline.rms); + hit->set_baseline_mean(raw_wave.mv_per_bit()*baseline.mean); + hit->set_baseline_rms(raw_wave.mv_per_bit()*baseline.rms); + ATH_MSG_DEBUG("Baseline found with mean = " << hit->baseline_mean() + << " mV and rms = " << hit->baseline_rms() + << " mV"); } return baseline; } -StatusCode -WaveformReconstructionTool::reconstruct(const RawWaveform& raw_wave, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* container) const { - - ATH_MSG_DEBUG(" reconstruct called "); - - // Check the container - if (!container) { - ATH_MSG_ERROR("WaveformHitCollection passed to reconstruct() is null!"); - return StatusCode::FAILURE; - } - - // - // We always want to create at least one hit, so create it here - xAOD::WaveformHit* hit = new xAOD::WaveformHit(); - container->push_back(hit); - - // Set digitizer channel and identifier - hit->set_channel(raw_wave.channel()); - hit->set_id(raw_wave.identify32().get_compact()); +// Fill the raw hit parameters +void +WaveformReconstructionTool::fillRawHitValues(const RawWaveform& wave, + int lo_edge, int hi_edge, + xAOD::WaveformHit* hit) const { - // Make sure we have ADC counts - if (raw_wave.adc_counts().size() == 0) { - ATH_MSG_WARNING( "Found waveform for channel " << raw_wave.channel() - << " with size " << raw_wave.adc_counts().size() << "!"); + // First, make sure we don't overflow the waveform range + if (lo_edge < 0) lo_edge = 0; + if (hi_edge >= int(wave.size())) hi_edge = wave.size() - 1; - hit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_MISSING); - return StatusCode::SUCCESS; - } + ATH_MSG_DEBUG("Fill channel " << wave.channel() + << " waveform from sample " << lo_edge << " to " << hi_edge); - if (raw_wave.adc_counts().size() != raw_wave.n_samples()) { - ATH_MSG_WARNING( "Found waveform for channel " << raw_wave.channel() - << " with size " << raw_wave.adc_counts().size() - << " not equal to number of samples " << raw_wave.n_samples()); + // Fill hit window with data from wave + std::vector<float> wtime(hi_edge-lo_edge+1); + std::vector<float> wwave(hi_edge-lo_edge+1); - hit->set_status_bit(xAOD::WaveformStatus::WAVEFORM_INVALID); - return StatusCode::SUCCESS; + for (int i=lo_edge; i<=hi_edge; i++) { + unsigned int j = i-lo_edge; + wtime[j] = 2.*i; // 2ns per sample at 500 MHz + wwave[j] = hit->baseline_mean() - wave.mv_per_bit() * wave.adc_counts()[i]; } - // Find the baseline - WaveformBaselineData baseline = findBaseline(raw_wave, hit); - - // Check that we have data to work with - // If any status bits are set, this is bad - if (hit->status()) return StatusCode::SUCCESS; - - // - // Create baseline-subtracted data array for both time and signal - // Time in ns from start of readout - unsigned int size = raw_wave.adc_counts().size(); - std::vector<float> time(size); - for (unsigned int i=0; i<size; i++) - time[i] = 2.*i; - - // Baseline subtracted (and inverted) ADC waveform values - std::vector<float> wave(raw_wave.adc_counts().begin(), raw_wave.adc_counts().end()); - for (auto& element : wave) - element = baseline.mean - element; - - bool first = true; - - // Now we iteratively find peaks and fit - while(true) { - - // - // Find peak in array and return time and value arrays - // This range of data is also *removed* from original arrays - std::vector<float> wtime; - std::vector<float> wwave; - - // All done if we don't have any peaks above threshold - // If we do find a significant peak, fill the window - if (! findPeak(baseline, time, wave, wtime, wwave) ) { - if (first) hit->set_status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED); - break; - } - - // - // Create new hit to fill - if (!first) { - hit = new xAOD::WaveformHit(); - container->push_back(hit); - hit->set_status_bit(xAOD::WaveformStatus::SECONDARY); - } - first = false; + hit->set_time_vector(wtime); + hit->set_wave_vector(wwave); - // - // Save windowed waveform to Hit object - hit->set_channel(raw_wave.channel()); - hit->set_baseline_mean(baseline.mean); - hit->set_baseline_rms(baseline.rms); - hit->set_time_vector(wtime); - hit->set_wave_vector(wwave); + // Set raw values + WaveformFitResult raw = findRawHitValues(wtime, wwave); + hit->set_peak(raw.peak); + hit->set_mean(raw.mean); + hit->set_width(raw.sigma); + hit->set_integral(raw.integral); + hit->set_localtime(raw.mean); + hit->set_raw_peak(raw.peak); + hit->set_raw_integral(raw.integral); - // - // Find some raw values - WaveformFitResult raw = findRawHitValues(wtime, wwave); - hit->set_peak(raw.peak); - hit->set_mean(raw.mean); - hit->set_width(raw.sigma); - hit->set_integral(raw.integral); - hit->set_localtime(raw.mean); - hit->set_raw_peak(raw.peak); - hit->set_raw_integral(raw.integral); +} - // - // Perform Gaussian fit to waveform - WaveformFitResult gfit = fitGaussian(raw, wtime, wwave); - if (! gfit.valid) { - // Lets try again with a more restricted width - ATH_MSG_WARNING( " Gaussian waveform fit failed with width " << raw.sigma << " try reducing width to 1 " ); - raw.sigma = 1.; - gfit = fitGaussian(raw, wtime, wwave); - if (!gfit.valid) { - hit->set_status_bit(xAOD::WaveformStatus::GFIT_FAILED); - } - } +// Reconstruct a hit from the RawWaveform in the range specified +// Range is in units digitizer samples (not ns) +void +WaveformReconstructionTool::reconstructHit(xAOD::WaveformHit* hit) const { - // Fit results (or raw if it failed) - hit->set_peak(gfit.peak); - hit->set_mean(gfit.mean); - hit->set_width(gfit.sigma); - hit->set_integral(gfit.integral); - hit->set_localtime(gfit.time); + // Time and waveform vectors + // Don't use reference as we may modify this below + std::vector<float> wtime = hit->time_vector(); + std::vector<float> wwave = hit->wave_vector(); - // - // Check for overflow - if (m_removeOverflow && findOverflow(baseline, wtime, wwave)) { - ATH_MSG_INFO("Found waveform overflow"); - hit->set_status_bit(xAOD::WaveformStatus::WAVE_OVERFLOW); - } + ATH_MSG_DEBUG("Reconstruct channel " << hit->channel() + << " waveform from " << wtime.front() + << " to " << wtime.back()); - // - // Perform CB fit - WaveformFitResult cbfit = fitCBall(gfit, wtime, wwave); - if (! cbfit.valid) { - ATH_MSG_WARNING("CrystalBall fit failed!"); - // Still have gaussian parameters as an estimate - hit->set_status_bit(xAOD::WaveformStatus::CBFIT_FAILED); - } else { - hit->set_peak(cbfit.peak); - hit->set_mean(cbfit.mean); - hit->set_width(cbfit.sigma); - hit->set_integral(cbfit.integral); - hit->set_localtime(cbfit.time); - - hit->set_alpha(cbfit.alpha); - hit->set_nval(cbfit.nval); - } + // Fill values needed for fit (peak, mean, and sigma) + WaveformFitResult raw; + raw.peak = hit->peak(); + raw.mean = hit->mean(); + raw.sigma = hit->width(); - // - // Find time from clock - if (!clock || (clock->frequency() <= 0.)) { - hit->set_status_bit(xAOD::WaveformStatus::CLOCK_INVALID); - hit->set_bcid_time(-1.); - } else { - hit->set_bcid_time(clock->time_from_clock(hit->localtime())); + // + // Perform Gaussian fit to waveform + WaveformFitResult gfit = fitGaussian(raw, wtime, wwave); + if (! gfit.valid) { + // Lets try again with a more restricted width + ATH_MSG_WARNING( " Gaussian waveform fit failed with width " << raw.sigma << " try reducing width to 1 " ); + raw.sigma = 1.; + gfit = fitGaussian(raw, wtime, wwave); + if (!gfit.valid) { + hit->set_status_bit(xAOD::WaveformStatus::GFIT_FAILED); } + } - if (! m_findMultipleHits) break; - - } // End of loop over waveform data + // Fit results (or raw if it failed) + hit->set_peak(gfit.peak); + hit->set_mean(gfit.mean); + hit->set_width(gfit.sigma); + hit->set_integral(gfit.integral); + hit->set_localtime(gfit.time); + + // + // Check for overflow + if (m_removeOverflow && findOverflow(hit->baseline_mean(), wtime, wwave)) { + ATH_MSG_INFO("Found waveform overflow"); + hit->set_status_bit(xAOD::WaveformStatus::WAVE_OVERFLOW); + } + + // + // Perform CB fit + WaveformFitResult cbfit = fitCBall(gfit, wtime, wwave); + if (! cbfit.valid) { + ATH_MSG_WARNING("CrystalBall fit failed for channel " << hit->channel() << "!"); + // Still have gaussian parameters as an estimate + hit->set_status_bit(xAOD::WaveformStatus::CBFIT_FAILED); + } else { + hit->set_peak(cbfit.peak); + hit->set_mean(cbfit.mean); + hit->set_width(cbfit.sigma); + hit->set_integral(cbfit.integral); + hit->set_localtime(cbfit.time); + + hit->set_alpha(cbfit.alpha); + hit->set_nval(cbfit.nval); + } - ATH_MSG_DEBUG( "WaveformReconstructionTool finished for channel " - << raw_wave.channel() << " container size= " << container->size()); + ATH_MSG_DEBUG("Done reconstructing channel " << hit->channel() + << " waveform from " << wtime.front() << " to " << wtime.back()); - return StatusCode::SUCCESS; } -bool +// Returns location of peak in array wave +// Return value is -1 if peak is below threshold +int WaveformReconstructionTool::findPeak(WaveformBaselineData& baseline, - std::vector<float>& time, std::vector<float>& wave, - std::vector<float>& windowed_time, std::vector<float>& windowed_wave) const { + float threshold, + std::vector<float>& wave) const +{ ATH_MSG_DEBUG("findPeak called"); @@ -435,44 +482,31 @@ WaveformReconstructionTool::findPeak(WaveformBaselineData& baseline, ATH_MSG_DEBUG( "Found peak value " << maxval << " at position " << imax ); // Check if this is over threshold (in sigma) - if (maxval < m_peakThreshold*baseline.rms) { + if (maxval < threshold*baseline.rms) { ATH_MSG_DEBUG("Failed threshold"); - return false; + return -1; } - // Make a window around this peak, values are in bins, so units of 2ns - // Ensure our window is within the vector range - int lo_edge = ((int(imax) + m_windowStart) >= 0 ? (imax + m_windowStart) : 0); - int hi_edge = ((imax + m_windowStart + m_windowWidth) < wave.size() ? (imax + m_windowStart + m_windowWidth) : wave.size()); - - ATH_MSG_DEBUG("Windowing waveform from " << lo_edge << " to " << hi_edge); - windowed_time = std::vector<float> (time.begin()+lo_edge, time.begin()+hi_edge); - windowed_wave = std::vector<float> (wave.begin()+lo_edge, wave.begin()+hi_edge); - - // Remove these values from the original arrays so we can iterate - time.erase(time.begin()+lo_edge, time.begin()+hi_edge); - wave.erase(wave.begin()+lo_edge, wave.begin()+hi_edge); - - return true; + return imax; } bool -WaveformReconstructionTool::findOverflow(const WaveformBaselineData& base, +WaveformReconstructionTool::findOverflow(float baseline, std::vector<float>& time, std::vector<float>& wave) const { auto peakloc = std::max_element(wave.begin(), wave.end()); // If peak value is less than baseline, we have no overflow - if (*peakloc < int(base.mean)) return false; + if (*peakloc < baseline) return false; ATH_MSG_DEBUG("Removing overflows from waveform with length " << wave.size()); // We have an overflow, remove all elements that are overflowing unsigned int i = peakloc - wave.begin(); for (; i<wave.size(); i++) { - if (wave[i] < int(base.mean)) continue; + if (wave[i] < baseline) continue; - ATH_MSG_DEBUG("Removing position "<< i<< " with value " << wave[i] << " > " << int(base.mean)); + ATH_MSG_DEBUG("Removing position "<< i<< " with value " << wave[i] << " > " << baseline); // This is an overflow, remove elements time.erase(time.begin() + i); wave.erase(wave.begin() + i); @@ -703,7 +737,7 @@ WaveformReconstructionTool::fitGaussian(const WaveformFitResult& raw, const std: // Define fit function and preset range TF1 gfunc("gfunc", "gaus"); gfunc.SetParameters(raw.peak, raw.mean, raw.sigma); - gfunc.SetParError(0, std::sqrt(raw.peak)); + gfunc.SetParError(0, raw.peak/10.); gfunc.SetParError(1, raw.sigma); gfunc.SetParError(2, raw.sigma / 5.); gfunc.SetParLimits(2, 0., 20.); // Constrain width @@ -756,7 +790,7 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit, // Define fit function and preset values TF1 cbfunc("cbfunc", "crystalball"); cbfunc.SetParameter(0, cbfit.peak); // Peak height - cbfunc.SetParError(0, std::sqrt(cbfit.peak)); + cbfunc.SetParError(0, cbfit.peak/10.); cbfunc.SetParameter(1, cbfit.mean); // Mean cbfunc.SetParError(1, cbfit.sigma); cbfunc.SetParameter(2, cbfit.sigma); // Width @@ -771,7 +805,7 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit, TFitResultPtr cbfitptr = tg.Fit(&cbfunc, "QNS", ""); if (!cbfitptr->IsValid()) { - ATH_MSG_WARNING( " First Crystal Ball waveform fit failed! "); + ATH_MSG_DEBUG( " First Crystal Ball waveform fit failed! "); } // Now try releasing the tail parameter @@ -786,7 +820,7 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit, cbfit.valid = (cbfit.fit_status == 0); if (!cbfitptr->IsValid()) { - ATH_MSG_WARNING( " Crystal Ball waveform fit failed! "); + ATH_MSG_DEBUG( " Full Crystal Ball waveform fit failed! "); } else { // Improve estimation with fit results cbfit.peak = cbfitptr->Parameter(0); diff --git a/Waveform/WaveRecTools/src/WaveformReconstructionTool.h b/Waveform/WaveRecTools/src/WaveformReconstructionTool.h index 7a39f883434051173099d3702e9643fb64cc9f51..45402ff505f5fd89420299f69cbc5a1ae9ab593b 100644 --- a/Waveform/WaveRecTools/src/WaveformReconstructionTool.h +++ b/Waveform/WaveRecTools/src/WaveformReconstructionTool.h @@ -20,6 +20,9 @@ #include "WaveformBaselineData.h" #include "WaveformFitResult.h" +// Tool classes +#include "WaveformConditionsTools/IWaveformTimingTool.h" + //Gaudi #include "GaudiKernel/ToolHandle.h" @@ -37,16 +40,18 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc /// Retrieve the necessary services in initialize StatusCode initialize(); - /// Reconstruct all hits from waveform container - virtual StatusCode reconstructAll(const RawWaveformContainer& waveContainer, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* hitContainer) const; + /// Reconstruct primary hits from waveform (in trigger window) + virtual StatusCode reconstructPrimary(const RawWaveform& wave, + xAOD::WaveformHitContainer* hitContainer) const; + + /// Reconstruct primary hits from waveform (in trigger window) + virtual StatusCode reconstructSecondary(const RawWaveform& wave, + xAOD::WaveformHitContainer* hitContainer) const; + + /// Set local hit times from LHC clock + virtual StatusCode setLocalTime(const xAOD::WaveformClock* clock, + xAOD::WaveformHitContainer* container) const; - /// Reconstruct hits from waveform - - virtual StatusCode reconstruct(const RawWaveform& wave, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* hitContainer) const; private: @@ -54,6 +59,9 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc // Baseline Estimation Parameters BooleanProperty m_useSimpleBaseline{this, "UseSimpleBaseline", false}; + ToolHandle<IWaveformTimingTool> m_timingTool + {this, "WaveformTimingTool", "WaveformTimingTool"}; + // Minimum number of samples needed to calculate simple baseline // Just average these first n values IntegerProperty m_samplesForBaselineAverage{this, "SamplesForBaselineAverage", 40}; @@ -79,32 +87,40 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc FloatProperty m_baselineFitWindow{this, "BaselineFitWindow", 2.}; // - // Peak threshold (in sigma of baseline RMS) to find a hit - FloatProperty m_peakThreshold{this, "PeakThreshold", 10.}; + // Peak threshold (in sigma of baseline RMS) + // Primary threshold is requirement to try a fit for the in-time window + // Secondary threshold is requirement to produce a secondary hit + // from a local maximum + FloatProperty m_primaryPeakThreshold{this, "PrimaryPeakThreshold", 5.}; + FloatProperty m_secondaryPeakThreshold{this, "SecondaryPeakThreshold", 10.}; // // Window to define fitting range, in samples (2ns/sample) - IntegerProperty m_windowStart{this, "FitWindowStart", -15}; + IntegerProperty m_windowStart{this, "FitWindowStart", -20}; IntegerProperty m_windowWidth{this, "FitWindowWidth", 60}; // // Remove overflow values from CB fit BooleanProperty m_removeOverflow{this, "RemoveOverflow", true}; - // - // Look for more than one hit in each channel - BooleanProperty m_findMultipleHits{this, "FindMultipleHits", false}; - // // Fraction of peak to set local hit time - FloatProperty m_timingPeakFraction{this, "TimingPeakFraction", 0.45}; + FloatProperty m_timingPeakFraction{this, "TimingPeakFraction", 0.4}; // - // Ensure each channel has a waveform hit at time of most significant - // hit in the event - BooleanProperty m_ensureChannelHits{this, "EnsureChannelHits", true}; - // Max Time difference in ns to say a hit exists in a different channel - FloatProperty m_hitTimeDifference{this, "HitTimeDifference", 10.}; + // When looking for secondary hits with a primary found above threshold + // should we look before or after the primary hit? + BooleanProperty m_findSecondaryBefore{this, "FindSecondaryBefore", true}; + BooleanProperty m_findSecondaryAfter{this, "FindSecondaryAfter", false}; + + // Reco algorithms + // Fill hit with raw data from waveform + void fillRawHitValues(const RawWaveform& wave, + int lo_edge, int hi_edge, + xAOD::WaveformHit* hit) const; + + // Perform fits to WaveformHit data + void reconstructHit(xAOD::WaveformHit* hit) const; // Baseline algorithms WaveformBaselineData& findSimpleBaseline(const RawWaveform& wave) const; @@ -113,12 +129,10 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc xAOD::WaveformHit* hit) const; - // Find peak in wave, return windowed region in windowed_time and windowed_wave - // Windowed region is removed from original vectors - // Returns true if peak found, false if not - bool findPeak(WaveformBaselineData& baseline, - std::vector<float>& time, std::vector<float>& wave, - std::vector<float>& windowed_time, std::vector<float>& windowed_wave) const; + // Find peak in wave, return index to peak position, or -1 if + // peak isn't greater than threshold + int findPeak(WaveformBaselineData& baseline, float threshold, + std::vector<float>& wave) const; // Get estimate from waveform data itself WaveformFitResult& findRawHitValues(const std::vector<float> time, @@ -130,7 +144,7 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc const std::vector<float> wave) const; // Find overflows and remove points from arrays - bool findOverflow(const WaveformBaselineData& baseline, + bool findOverflow(float baseline, std::vector<float>& time, std::vector<float>& wave) const; // Fit windowed data to CrystalBall function @@ -138,12 +152,6 @@ class WaveformReconstructionTool: public extends<AthAlgTool, IWaveformReconstruc const std::vector<float> time, const std::vector<float> wave) const; - - /// Create hit in all channels at time of peak signal - void ensureHits(const RawWaveformContainer& waveContainer, - const xAOD::WaveformClock* clock, - xAOD::WaveformHitContainer* hitContainer) const; - }; #endif // WAVERECTOOLS_WAVEFORMRECONSTRUCTIONTOOL_H diff --git a/Waveform/WaveformConditions/WaveCondUtils/CMakeLists.txt b/Waveform/WaveformConditions/WaveCondUtils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c295bd9cab84b213f7ec0227a3cb4f95486edc8 --- /dev/null +++ b/Waveform/WaveformConditions/WaveCondUtils/CMakeLists.txt @@ -0,0 +1,9 @@ +################################################################################ +# Package: WaveCondUtils +################################################################################ + +# Declare the package name: +atlas_subdir( WaveCondUtils ) + +atlas_install_scripts( scripts/*.sh scripts/*.py ) + diff --git a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py new file mode 100755 index 0000000000000000000000000000000000000000..b3a1c64a23ad23ae70eaa000e3cbd76064bebfcd --- /dev/null +++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py @@ -0,0 +1,221 @@ +#!/bin/env python + +# Requires python 3.8 or higher +# +# Can test results with +# AtlCoolConsole.py "sqlite://;schema=waveform_reco.db;dbname=OFLP200" + +filename = 'waveform_reco.db' + +# Nominal trigger time in ns +nominal_data = { + 0: 820., + 4272: 830., + 6525: 820. +} + +offset_channels = 16 + +# Run +# 0 - initial data +# 3395 - Testbeam +# + +ehn1_offsets = [ -20., -20., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ] +ti12_offsets = [ -20., -20., -20., -20., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ] + +offset_data = { + 0: [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ], +# Initial TI12 + 1324: [ -10., -10., -10., -10., 0., 0., 0., 0., 0., 0., 0., 0., 18., 18., 0., 0. ], +# Testbeam geometry + 3247: [ -10., -10., -10., -10., -10., -10., 15., 15., -20., -20., 0., 0., 0., 0., 0., 0. ], +# TI12 + 4272: ti12_offsets, +# EHN1 (interleaved with TI12 running) + 4360: ehn1_offsets, + 4399: ti12_offsets, + 4409: ehn1_offsets, + 4411: ti12_offsets, + 4429: ehn1_offsets, + 4439: ti12_offsets, + 4876: ehn1_offsets, + 4892: ti12_offsets, + 4904: ehn1_offsets, + 4912: ti12_offsets, + 4954: ehn1_offsets, + 4989: ti12_offsets, + 4991: ehn1_offsets, + 4993: ti12_offsets, + 4996: ehn1_offsets, + 4997: ti12_offsets, + 5042: ehn1_offsets, + 5050: ti12_offsets, +# IFT and VetoNu installed + 6525: [ -10., -10., -10., -10., -25., -25., 0., 0., 0., 0., 0., 0., 18., 18., 0., 0. ] +} + +attr_list_desc = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header service_type="71" clid="40774348" /></addrHeader><typeName>AthenaAttributeList</typeName>' + +cond_attr_list_desc = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>' + +maxInt32 = 0xFFFFFFFF + + +# Look for data entry errors + +print('Validating nominal data') + +lastRun = -1 +for run, data in nominal_data.items(): + assert isinstance(run, int), 'Run number is not integer' + assert isinstance(data, float), 'Time is not float' + assert run > lastRun, 'Run numbers out of order' + assert run <= maxInt32, 'Run number out of range' + lastRun = run + +print('Validating offset data') +lastRun = -1 +for run, data in offset_data.items(): + assert isinstance(run, int), 'Run number is not integer' + assert run > lastRun, 'Run numbers out of order' + assert run <= maxInt32, 'Run number out of range' + lastRun = run + assert len(data) == offset_channels, 'Offset data does not have '+str(offset_channels)+' entries' + for i in range(offset_channels): + assert isinstance(data[i], float), 'Offset time is not float' + +# Data looks OK + + +from PyCool import cool + +dbSvc = cool.DatabaseSvcFactory.databaseService() +connectString = f'sqlite://;schema={filename};dbname=CONDBR3' + +print('Creating database') + +dbSvc.dropDatabase( connectString ) +db = dbSvc.createDatabase( connectString ) + +# Nominal trigger times +nominalSpec = cool.RecordSpecification() +nominalSpec.extend( 'NominalTriggerTime', cool.StorageType.Float ) + +nominalFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, nominalSpec) +nominalFolder = db.createFolder('/WAVE/DAQ/Timing', nominalFolderSpec, attr_list_desc, True) + +# There should be one record entered per IOV +lastValid = cool.ValidityKeyMax +for firstValidRun, time in reversed(nominal_data.items()): + firstValid = (firstValidRun << 32) + nominalRecord = cool.Record(nominalSpec) + nominalRecord[ 'NominalTriggerTime' ] = float(time) + nominalFolder.storeObject( firstValid, lastValid, nominalRecord, cool.ChannelId(0)) + lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF) + + +# Trigger offset times + +offsetSpec = cool.RecordSpecification() +offsetSpec.extend( 'TriggerOffset', cool.StorageType.Float ) + +offsetFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, offsetSpec) +offsetFolder = db.createFolder('/WAVE/DAQ/TimingOffset', offsetFolderSpec, cond_attr_list_desc, True) + +# There should be one record entered per IOV +lastValid = cool.ValidityKeyMax +for firstValidRun, offset_list in reversed(offset_data.items()): + firstValid = (firstValidRun << 32) + for channel in range(offset_channels): + offsetRecord = cool.Record(offsetSpec) + offsetRecord[ 'TriggerOffset' ] = float(offset_list[channel]) + offsetFolder.storeObject( firstValid, lastValid, offsetRecord, cool.ChannelId(channel) ) + + lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF) + + +db.closeDatabase() + +print('Database completed') + +print('Working on MC database') + +# Nominal data +nominal_data = { + 0: 820. +} +# No offsets by default +offset_data = { + 0: [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.] +} + +# Validate again just in case +print('Validating nominal data') + +lastRun = -1 +for run, data in nominal_data.items(): + assert isinstance(run, int), 'Run number is not integer' + assert isinstance(data, float), 'Time is not float' + assert run > lastRun, 'Run numbers out of order' + assert run <= maxInt32, 'Run number out of range' + lastRun = run + +print('Validating offset data') +lastRun = -1 +for run, data in offset_data.items(): + assert isinstance(run, int), 'Run number is not integer' + assert run > lastRun, 'Run numbers out of order' + assert run <= maxInt32, 'Run number out of range' + lastRun = run + assert len(data) == offset_channels, 'Offset data does not have '+str(offset_channels)+' entries' + for i in range(offset_channels): + assert isinstance(data[i], float), 'Offset time is not float' + +# Data looks OK + +connectString = f'sqlite://;schema={filename};dbname=OFLP200' + +dbSvc.dropDatabase( connectString ) +db = dbSvc.createDatabase( connectString ) + +# Nominal trigger times +nominalSpec = cool.RecordSpecification() +nominalSpec.extend( 'NominalTriggerTime', cool.StorageType.Float ) + +nominalFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, nominalSpec) +nominalFolder = db.createFolder('/WAVE/DAQ/Timing', nominalFolderSpec, attr_list_desc, True) + +# There should be one record entered per IOV +lastValid = cool.ValidityKeyMax +for firstValidRun, time in reversed(nominal_data.items()): + firstValid = (firstValidRun << 32) + nominalRecord = cool.Record(nominalSpec) + nominalRecord[ 'NominalTriggerTime' ] = float(time) + nominalFolder.storeObject( firstValid, lastValid, nominalRecord, cool.ChannelId(0)) + lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF) + + +# Trigger offset times + +offsetSpec = cool.RecordSpecification() +offsetSpec.extend( 'TriggerOffset', cool.StorageType.Float ) + +offsetFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, offsetSpec) +offsetFolder = db.createFolder('/WAVE/DAQ/TimingOffset', offsetFolderSpec, cond_attr_list_desc, True) + +# There should be one record entered per IOV +lastValid = cool.ValidityKeyMax +for firstValidRun, offset_list in reversed(offset_data.items()): + firstValid = (firstValidRun << 32) + for channel in range(offset_channels): + offsetRecord = cool.Record(offsetSpec) + offsetRecord[ 'TriggerOffset' ] = float(offset_list[channel]) + offsetFolder.storeObject( firstValid, lastValid, offsetRecord, cool.ChannelId(channel) ) + + lastValid = ((firstValidRun - 1) << 32) | (cool.ValidityKeyMax & 0x00000000FFFFFFFF) + + +db.closeDatabase() + +print('Database completed') diff --git a/Waveform/WaveformConditions/WaveCondUtils/scripts/wave_timing_check.py b/Waveform/WaveformConditions/WaveCondUtils/scripts/wave_timing_check.py new file mode 100755 index 0000000000000000000000000000000000000000..6c8f6332ff42e1ffc06fb168d290539c1db89208 --- /dev/null +++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/wave_timing_check.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python3 +# +import os +import sys +import math +import array +import itertools + +# Triggers: 0x01 - calo, 0x02 - veto, 0x03 - timing, 0x10 - random + +def usage(): + print("Usage: timing_check.py <filename>|<dirname> [triggermask]") + +if len(sys.argv) == 1: + usage() + sys.exit(-1) + +# Extract tracker station requirements +if len(sys.argv) == 3: + trigmask = int(sys.argv[2]) + extra = f"_{triggermask}" +else: + trigmask = 0xFF + extra = '' + +from pathlib import Path + +import ROOT +ROOT.xAOD.Init().ignore() +ROOT.xAOD.AuxContainerBase() +os.environ["XAOD_ACCESSTRACER_FRACTION"] = "0.0" + +# +# Open file or files +pathname = Path(sys.argv[1]) + +# Is this a directory? +if pathname.is_dir(): + print(f"Opening files in directory {pathname.name}") + + t2 = ROOT.TChain("CollectionTree") + nfiles = t2.Add(str(pathname)+'/Faser-Physics*.root') + + if (nfiles == 0): + print(f"TChain found no files!") + usage() + sys.exit(0) + + # Make transient tree + t1 = ROOT.xAOD.MakeTransientTree(t2) + + # Make output file name + outfile = pathname.name + "_timing"+extra+".pdf" + + print(f"TChain found {nfiles} files with {t2.GetEntries()} events") + + avperfile = t2.GetEntries() / nfiles + +# Is this a file? +elif pathname.is_file(): + print(f"Opening file {pathname.name}") + + t2 = ROOT.TChain("CollectionTree") + nfiles = t2.Add(str(pathname)) + + if (nfiles != 1): + print(f"TChain error opening file!") + usage() + sys.exit(0) + + print(f"Opened file with {t2.GetEntries()} events") + + avperfile = t2.GetEntries() + + # Make transient tree + t1 = ROOT.xAOD.MakeTransientTree(t2) + + # Make outfile name from input + outfile = pathname.stem + "_timing"+extra+".pdf" + +# Neither? +else: + print(f"Can't understand {pathname.name}") + usage() + sys.exit(-1) + +class ClockPlots: + + def __init__(self): + + # Ranges for plots + self.freq_bins = 80 + self.freq_lo = 40.0 + self.freq_hi = 40.2 + + self.th_bins = 100 + + def init(self, tree): + + self.h_freq = ROOT.TH1I("", "Clock Frequency", self.freq_bins, self.freq_lo, self.freq_hi) + self.h_freq.GetXaxis().SetTitle("Clock Frequency (MHz)") + self.h_freq.GetYaxis().SetTitle("Events") + #self.h_freq.Sumw2() + + self.h_phase = ROOT.TH1I("", "Clock Phase", 60, 2*(-3.1416), 2*3.1416) + self.h_phase.GetXaxis().SetTitle("Clock Phase") + self.h_phase.GetYaxis().SetTitle("Events") + + self.h_amp = ROOT.TH1I("", "Amplitude", 50, 0, 2000.) + self.h_amp.GetXaxis().SetTitle("Clock Amplitude (mV)") + self.h_amp.GetYaxis().SetTitle("Events") + + self.h_off = ROOT.TH1I("", "Offset", 50, 0, 2000.) + self.h_off.GetXaxis().SetTitle("Clock Offset (mV)") + self.h_off.GetYaxis().SetTitle("Events") + + def fill(self, tree): + + # First, create the histograms + self.init(tree) + + # Iterate over all entries + nev = tree.GetEntries() + iev = 0 + for ev in tree: + self.h_freq.Fill(ev.WaveformClock.frequency()) + self.h_phase.Fill(ev.WaveformClock.phase()) + self.h_amp.Fill(ev.WaveformClock.amplitude()) + self.h_off.Fill(ev.WaveformClock.dc_offset()) + + # Protect against reading off the end + iev += 1 + if iev == nev: break + + def draw(self, canvas, outfile): + + # Under/overflows, mean, rms, and entries + ROOT.gStyle.SetOptStat(111110) + + canvas.Clear() + canvas.Divide(2,2) + canvas.cd(1) + self.h_freq.Draw() + canvas.cd(2) + self.h_phase.Draw() + canvas.cd(3) + self.h_amp.Draw() + canvas.cd(4) + self.h_off.Draw() + canvas.Update() + canvas.Print(outfile) + + def print_stats(self): + + freq_mean = self.h_freq.GetMean() + freq_rms = self.h_freq.GetStdDev() + freq_n = self.h_freq.GetEntries() + print(f"LHC Clock: {freq_mean:.6} +/- {freq_rms/math.sqrt(freq_n):.6}") + +class WavePlots: + + def __init__(self, triggerMask=0xFF): + + # Number of waveforms channels + self.nchan = 15 + + # Trigger mask + self.mask = triggerMask + + self.chan_hist_list = [] + self.log_list = [] + + # Maaximum peak value + self.peak_max = 16000. + + def init(self, tree): + + # Keyed by channel + self.createChannelHist('h_localtime', 40, 750, 950, "Local Time") + self.createChannelHist('h_triggertime', 40, -80, 80, "Trigger Time") + self.createChannelHist('h_bcidtime', 50, -10, 40, "BCID Time") + + def createChannelHist(self, name, nbins, xlo, xhi, xtitle='', ytitle='Waveforms', stats=True, log=False): + + setattr(self, name, dict()) + x = getattr(self, name) + for chan in range(self.nchan): + x[chan] = ROOT.TH1I("", "", nbins, xlo, xhi) + if len(xtitle) > 0: + x[chan].GetXaxis().SetTitle(f"Ch {chan} {xtitle}") + if len(ytitle) > 0: + x[chan].GetYaxis().SetTitle(ytitle) + x[chan].SetStats(stats) + + self.chan_hist_list.append(name) + if log: + self.log_list.append(name) + + def fill(self, tree): + + # First, create the histograms + self.init(tree) + + # Iterate over all entries + nev = tree.GetEntries() + iev = 0 + for ev in tree: + + time = ev.EventInfo.timeStamp() + trig = ev.FaserTriggerData.tap() + + if not (trig & self.mask): + iev += 1 + if iev == nev: + break + else: + continue + + # Process waveforms + try: + wave_list = itertools.chain(ev.CaloWaveformHits, ev.PreshowerWaveformHits, ev.TriggerWaveformHits, ev.VetoWaveformHits, ev.VetoNuWaveformHits) + except: + wave_list = itertools.chain(ev.CaloWaveformHits, ev.PreshowerWaveformHits) + + for wave in wave_list: + + channel = wave.channel() + + # Check if failed threshold + if wave.status_bit(0): continue + + # Fill fit parameters + self.h_localtime[channel].Fill(wave.localtime()) + self.h_triggertime[channel].Fill(wave.trigger_time()) + self.h_bcidtime[channel].Fill(wave.bcid_time()) + + # End of loop over waveforms + + # Protect against reading off the end + iev+=1 + if iev == nev: break + + # End of loop over events + + # Put overflows in last bin of plots + self.fixOverflow(self.h_localtime) + self.fixOverflow(self.h_triggertime) + + def fixOverflow(self, hdict): + + for h in hdict.values(): + + if h.GetNbinsY() == 1: + self.fixOverflow1D(h) + else: + self.fixOverflow2D(h) + + def fixOverflow1D(self, hist): + nbins = hist.GetNbinsX() + nlast = hist.GetBinContent(nbins) + nover = hist.GetBinContent(nbins+1) + hist.SetBinContent(nbins, nlast+nover) + + def fixOverflow2D(self, hist): + nbx = hist.GetNbinsX() + nby = hist.GetNbinsY() + + for ibinx in range(nbx+1): + nlast = hist.GetBinContent(ibinx, nby) + nover = hist.GetBinContent(ibinx, nby+1) + hist.SetBinContent(ibinx, nby, nlast+nover) + + for ibiny in range(nby+1): + nlast = hist.GetBinContent(nbx, ibiny) + nover = hist.GetBinContent(nbx+1, ibiny) + hist.SetBinContent(nbx, ibiny, nlast+nover) + + # Also the double overflow + nlast = hist.GetBinContent(nbx, nby) + nover = hist.GetBinContent(nbx+1, nby+1) + hist.SetBinContent(nbx, nby, nlast+nover) + + + def draw(self, canvas, outfile): + + # + # Plot channel plots + for name in self.chan_hist_list: + canvas.Clear() + canvas.Divide(4,4) + + if name in self.log_list: + setlog = True + else: + setlog = False + + for chan in range(self.nchan): + canvas.cd(chan+1) + x = getattr(self, name) + x[chan].Draw() + if setlog: + ROOT.gPad.SetLogy(True) + else: + ROOT.gPad.SetLogy(False) + + canvas.Print(outfile) + + def print_stats(self): + + for chan in range(self.nchan): + local_mean = self.h_localtime[chan].GetMean() + trig_mean = self.h_triggertime[chan].GetMean() + bcid_mean = self.h_bcidtime[chan].GetMean() + print(f"Chan {chan:2}: Entries {int(self.h_localtime[chan].GetEntries()):8} Local {local_mean:6.1f} Trigger {trig_mean:6.2f} BCID {bcid_mean:6.2f}") + +#print("xAOD tree") +#t1.Print() +#print("non xAOD tree") +#t2.Print() + +cp = ClockPlots() +cp.fill(t1) + +# Triggers: 0x01 - calo, 0x02 - veto, 0x03 - timing, 0x10 - random +wp = WavePlots(triggerMask=trigmask) +wp.fill(t1) + +c = ROOT.TCanvas() +c.Print(outfile+"[") + +cp.draw(c, outfile) +wp.draw(c, outfile) + +c.Print(outfile+"]") + +cp.print_stats() +wp.print_stats() diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h index 8886506e5a04efe269bb75ca91fc36c8fe283d85..461c087e0fb3957e90c1a1e50723e87a2baff996 100644 --- a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h +++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h @@ -2,7 +2,7 @@ Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations */ -/** @file ISCT_CableMappingTool.h Interface file for SCT_CableMappingTool. +/** @file IWaveformCableMappingTool.h Interface file for WaveformCableMappingTool. */ // Multiple inclusion protection @@ -38,6 +38,10 @@ class IWaveformCableMappingTool: virtual public IAlgTool { virtual WaveformCableMap getCableMapping(const EventContext& ctx) const = 0; virtual WaveformCableMap getCableMapping(void) const = 0; + virtual int getChannelMapping(const EventContext& ctx, const Identifier id) const = 0; + virtual int getChannelMapping(const Identifier id) const = 0; + + }; //---------------------------------------------------------------------- diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformRangeTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformRangeTool.h new file mode 100644 index 0000000000000000000000000000000000000000..316d9c4953a100e83c4ec1a0a052714372e1fdaf --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformRangeTool.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations +*/ + +/** @file IWaveformRangeTool.h Interface file for WaveformRangeTool. + */ + +// Multiple inclusion protection +#ifndef IWAVEFORMRANGETOOL +#define IWAVEFORMRANGETOOL + +//STL includes +#include <map> + +//Gaudi Includes +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" + +// ADC range in volts indexed by digitizer channel number +typedef std::map<int, float> WaveformRangeMap; + +class IWaveformRangeTool: virtual public IAlgTool { + + public: + + //----------Public Member Functions----------// + // Structors + virtual ~IWaveformRangeTool() = default; //!< Destructor + + /// Creates the InterfaceID and interfaceID() method + DeclareInterfaceID(IWaveformRangeTool, 1, 0); + + // Methods to return cable-mapping data + // Key is digitizer channel, pair is <type, identifier> + virtual WaveformRangeMap getRangeMapping(const EventContext& ctx) const = 0; + virtual WaveformRangeMap getRangeMapping(void) const = 0; + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORMRANGETOOL diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformTimingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformTimingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..de2a2dcbd1dde01c8a48e2a6a67822efc13e7519 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformTimingTool.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations +*/ + +/** @file IWaveformTimingTool.h Interface file for WaveformTimingTool. + * + * Provides times and offsets (in ns) for different channels in the + * waveform digitizer. This aligns the input signals for different + * path lengths and cable delays. + * + */ + +// Multiple inclusion protection +#ifndef IWAVEFORMTIMINGTOOL +#define IWAVEFORMTIMINGTOOL + +//STL includes +#include <map> + +//Gaudi Includes +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" + + +class IWaveformTimingTool: virtual public IAlgTool { + + public: + + //----------Public Member Functions----------// + // Structors + virtual ~IWaveformTimingTool() = default; //!< Destructor + + /// Creates the InterfaceID and interfaceID() method + DeclareInterfaceID(IWaveformTimingTool, 1, 0); + + // Methods to return timing data + + // Nominal trigger time (in ns) in the digitizer readout + virtual float nominalTriggerTime(void) const = 0; + virtual float nominalTriggerTime(const EventContext& ctx) const = 0; + + // Channel-by-channel corrections to the nominal trigger time (in ns) + // A given channel should be centered at nominal + offset + virtual float triggerTimeOffset(int channel) const = 0; + virtual float triggerTimeOffset(const EventContext& ctx, int channel) const = 0; + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORMTIMINGTOOL diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..6450bcec88b3cb8c7194b01edeb59aa6b97e242f --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformRangeConfig.py @@ -0,0 +1,27 @@ +""" Define methods to configure WaveformRangeTool + +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +""" +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from IOVDbSvc.IOVDbSvcConfig import addFolders +WaveformRangeTool=CompFactory.WaveformRangeTool + +def WaveformRangeToolCfg(flags, name="WaveformRangeTool", **kwargs): + """ Return a configured WaveformRangeTool""" + return WaveformRangeTool(name, **kwargs) + +def WaveformRangeCfg(flags, **kwargs): + """ Return configured ComponentAccumulator and tool for Waveform Range + + WaveformRangeTool may be provided in kwargs + """ + + acc = ComponentAccumulator() + # tool = kwargs.get("WaveformRangeTool", WaveformRangeTool(flags)) + # Probably need to figure this out! + dbInstance = kwargs.get("dbInstance", "TDAQ_OFL") + dbFolder = kwargs.get("dbFolder", "/WAVE/DAQ/Range") + acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection")) + return acc + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformTimingConfig.py b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformTimingConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..3b95ed388208d7d4ab51a3d5621ab868d438c433 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformTimingConfig.py @@ -0,0 +1,32 @@ +""" Define methods to configure WaveformTimingTool + +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +""" +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from IOVDbSvc.IOVDbSvcConfig import addFolders +WaveformTimingTool=CompFactory.WaveformTimingTool + +def WaveformTimingToolCfg(flags, name="WaveformTimingTool", **kwargs): + """ Return a configured WaveformTimingTool""" + return WaveformTimingTool(name, **kwargs) + +def WaveformTimingCfg(flags, **kwargs): + """ Return configured ComponentAccumulator and tool for Waveform Timing + + WaveformTimingTool may be provided in kwargs + """ + + acc = ComponentAccumulator() + # tool = kwargs.get("WaveformTimingTool", WaveformTimingTool(flags)) + # Probably need to figure this out! + dbInstance = kwargs.get("dbInstance", "TRIGGER_OFL") + if flags.Input.isMC: + dbname = "OFLP200" + else: + dbname = "CONDBR3" + + acc.merge(addFolders(flags, "/WAVE/DAQ/Timing", dbInstance, className="AthenaAttributeList", db=dbname)) + acc.merge(addFolders(flags, "/WAVE/DAQ/TimingOffset", dbInstance, className="CondAttrListCollection", db=dbname)) + return acc + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx index a846fe8da6a51bd3293f02b73cd960439d8d77b5..3922d0605339fce204cff01c9dbd69d3c6f21a97 100644 --- a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx @@ -27,6 +27,7 @@ WaveformCableMappingTool::initialize() { // Set up helpers ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID")); ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID")); + ATH_CHECK(detStore()->retrieve(m_vetoNuID, "VetoNuID")); ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID")); ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID")); @@ -98,6 +99,9 @@ WaveformCableMappingTool::getCableMapping(const EventContext& ctx) const { else if (det_type == "veto") { identifier = m_vetoID->pmt_id(stationVal, plateVal, pmtVal); } + else if (det_type == "vetonu") { + identifier = m_vetoNuID->pmt_id(stationVal, plateVal, pmtVal); + } else if (det_type == "trigger") { identifier = m_triggerID->pmt_id(stationVal, plateVal, pmtVal); } @@ -135,5 +139,104 @@ WaveformCableMappingTool::getCableMapping(void) const { return getCableMapping(ctx); } +//---------------------------------------------------------------------- +int +WaveformCableMappingTool::getChannelMapping(const EventContext& ctx, const Identifier id) const { + // Print where you are + ATH_MSG_DEBUG("in getChannelMapping("<< id <<")"); + int channel = -1; + + // Read Cond Handle + SG::ReadCondHandle<CondAttrListCollection> readHandle{m_readKey, ctx}; + const CondAttrListCollection* readCdo{*readHandle}; + if (readCdo==nullptr) { + ATH_MSG_FATAL("Null pointer to the read conditions object"); + return channel; + } + // Get the validitiy range + EventIDRange rangeW; + if (not readHandle.range(rangeW)) { + ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key()); + return channel; + } + ATH_MSG_DEBUG("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdo->size()= " << readCdo->size()); + ATH_MSG_DEBUG("Range of input is " << rangeW); + + // Read mapping info + CondAttrListCollection::const_iterator attrList{readCdo->begin()}; + CondAttrListCollection::const_iterator end{readCdo->end()}; + // CondAttrListCollection doesn't support C++11 type loops, no generic 'begin' + for (; attrList!=end; ++attrList) { + // A CondAttrListCollection is a map of ChanNum and AttributeList + CondAttrListCollection::ChanNum channelNumber{attrList->first}; + const CondAttrListCollection::AttributeList &payload{attrList->second}; + if (payload.exists("type") and not payload["type"].isNull()) { + + std::string det_type{payload["type"].data<std::string>()}; + + int stationVal{payload["station"].data<int>()}; + int plateVal {payload["plate"].data<int>()}; + int rowVal {payload["row"].data<int>()}; + int moduleVal {payload["module"].data<int>()}; + int pmtVal {payload["pmt"].data<int>()}; + Identifier identifier; + + // Ugh, cant use switch statement with strings + // Must do this using an if ladder + if (det_type == "calo") { + identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal); + } + else if (det_type == "veto") { + identifier = m_vetoID->pmt_id(stationVal, plateVal, pmtVal); + } + else if (det_type == "vetonu") { + identifier = m_vetoNuID->pmt_id(stationVal, plateVal, pmtVal); + } + else if (det_type == "trigger") { + identifier = m_triggerID->pmt_id(stationVal, plateVal, pmtVal); + } + else if (det_type == "preshower") { + identifier = m_preshowerID->pmt_id(stationVal, plateVal, pmtVal); + } + else if (det_type == "clock") { + // No valid identifiers for these + identifier = -1; + } + else if (det_type == "none") { + identifier = -1; + } + else { + ATH_MSG_WARNING("Detector type " << det_type << " not known for channel " << channelNumber << "!"); + det_type = std::string("none"); + identifier = -1; + } + + // ATH_MSG_DEBUG("Comparing " << det_type << " ID: " + // << identifier.get_identifier() + // << " to requested " << id); + + // Is this the identifier we are looking for? + if (id != identifier) continue; + + ATH_MSG_DEBUG("Mapped identifier " << det_type << " ID: " << identifier << " to digitizer channel " << channelNumber); + + channel = channelNumber; + break; + } + } // End of loop over attributes + + if (channel < 0) { + ATH_MSG_WARNING("No channel found for identifier " << id << "!"); + + } + + return channel; +} + +int +WaveformCableMappingTool::getChannelMapping(const Identifier id) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return getChannelMapping(ctx, id); +} diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h index 19e6e6d9b5f294692ba0496b1594741494ef223a..8443cb1815e4db7a9c0181515b5fd405cd27d48c 100644 --- a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h @@ -21,6 +21,7 @@ #include "Identifier/Identifier.h" #include "FaserCaloIdentifier/EcalID.h" #include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/PreshowerID.h" @@ -56,6 +57,11 @@ class WaveformCableMappingTool: public extends<AthAlgTool, IWaveformCableMapping virtual WaveformCableMap getCableMapping(const EventContext& ctx) const override; virtual WaveformCableMap getCableMapping(void) const override; + // Reverse mapping, reads idenfifier and returns digitizer channel + // Returns -1 if match not found for given identifier + virtual int getChannelMapping(const EventContext& ctx, const Identifier id) const override; + virtual int getChannelMapping(const Identifier id) const override; + private: // Read Cond Handle SG::ReadCondHandleKey<CondAttrListCollection> m_readKey{this, "ReadKey", "/WAVE/DAQ/CableMapping", "Key of input cabling folder"}; @@ -65,6 +71,7 @@ class WaveformCableMappingTool: public extends<AthAlgTool, IWaveformCableMapping // ID helpers const EcalID* m_ecalID{nullptr}; const VetoID* m_vetoID{nullptr}; + const VetoNuID* m_vetoNuID{nullptr}; const TriggerID* m_triggerID{nullptr}; const PreshowerID* m_preshowerID{nullptr}; diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5c7670e3cbc2dcc9e967107b9f304743695987fc --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.cxx @@ -0,0 +1,90 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +/** @file WaveformRangeTool.cxx Implementation file for WaveformRangeTool. + @author Eric Torrence (05/02/22) +*/ + +#include "WaveformRangeTool.h" + +//---------------------------------------------------------------------- +WaveformRangeTool::WaveformRangeTool (const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +//---------------------------------------------------------------------- +StatusCode +WaveformRangeTool::initialize() { + // Read Cond Handle Key + + ATH_MSG_DEBUG("WaveformRangeTool::initialize()"); + + ATH_CHECK(m_readKey.initialize()); + + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +StatusCode +WaveformRangeTool::finalize() { + // Print where you are + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +WaveformRangeMap +WaveformRangeTool::getRangeMapping(const EventContext& ctx) const { + // Print where you are + ATH_MSG_DEBUG("in getRangeMapping()"); + WaveformRangeMap mappingData; + + // Read Cond Handle + SG::ReadCondHandle<CondAttrListCollection> readHandle{m_readKey, ctx}; + const CondAttrListCollection* readCdo{*readHandle}; + if (readCdo==nullptr) { + ATH_MSG_FATAL("Null pointer to the read conditions object"); + return mappingData; + } + // Get the validitiy range + EventIDRange rangeW; + if (not readHandle.range(rangeW)) { + ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key()); + return mappingData; + } + ATH_MSG_DEBUG("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdo->size()= " << readCdo->size()); + ATH_MSG_DEBUG("Range of input is " << rangeW); + + // Read range info + + CondAttrListCollection::const_iterator attrList{readCdo->begin()}; + CondAttrListCollection::const_iterator end{readCdo->end()}; + // CondAttrListCollection doesn't support C++11 type loops, no generic 'begin' + for (; attrList!=end; ++attrList) { + // A CondAttrListCollection is a map of ChanNum and AttributeList + CondAttrListCollection::ChanNum channelNumber{attrList->first}; + const CondAttrListCollection::AttributeList &payload{attrList->second}; + if (payload.exists("range") and not payload["range"].isNull()) { + + float range {payload["range"].data<float>()}; + + ATH_MSG_DEBUG("Found digitizer channel " << channelNumber << " range as " << range); + + mappingData.emplace(std::make_pair(channelNumber, range)); + + } + + } // End of loop over attributes + + return mappingData; +} + +WaveformRangeMap +WaveformRangeTool::getRangeMapping(void) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return getRangeMapping(ctx); +} + + + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e33123f243a41e286f32cf09059e748306a1348c --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformRangeTool.h @@ -0,0 +1,60 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations +*/ + +/** @file WaveformRangeTool.h Header file for WaveformRangeTool. + @author Eric Torrence, 20/04/22 +*/ + +// Multiple inclusion protection +#ifndef WAVEFORM_RANGE_TOOL +#define WAVEFORM_RANGE_TOOL + +// Include interface class +#include "AthenaBaseComps/AthAlgTool.h" +#include "WaveformConditionsTools/IWaveformRangeTool.h" + +// Include Athena stuff +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "StoreGate/ReadCondHandleKey.h" + +#include "GaudiKernel/ICondSvc.h" +#include "Gaudi/Property.h" + +// Include Gaudi classes +#include "GaudiKernel/EventContext.h" + +/** This class contains a Tool that reads Waveform range data and makes it available to + other algorithms. The current implementation reads the data from a COOL database. +*/ + +class WaveformRangeTool: public extends<AthAlgTool, IWaveformRangeTool> { + + public: + //----------Public Member Functions----------// + // Structors + WaveformRangeTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor + virtual ~WaveformRangeTool() = default; //!< Destructor + + // Standard Gaudi functions + virtual StatusCode initialize() override; //!< Gaudi initialiser + virtual StatusCode finalize() override; //!< Gaudi finaliser + + // Methods to return calibration data + // Map indexed by digitizer channel number + // Returns full-scale ADC range as float + virtual WaveformRangeMap getRangeMapping(const EventContext& ctx) const override; + virtual WaveformRangeMap getRangeMapping(void) const override; + + private: + // Read Cond Handle + SG::ReadCondHandleKey<CondAttrListCollection> m_readKey{this, "ReadKey", "/WAVE/DAQ/Range", "Key of range folder"}; + + ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"}; + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORM_CABLE_MAPPING_TOOL diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f163c65620a107ea8a5812818e5f8c5ba4049bac --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.cxx @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +/** @file WaveformTimingTool.cxx Implementation file for WaveformTimingTool. + @author Eric Torrence (04/05/22) +*/ + +#include "WaveformTimingTool.h" + +//---------------------------------------------------------------------- +WaveformTimingTool::WaveformTimingTool (const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +//---------------------------------------------------------------------- +StatusCode +WaveformTimingTool::initialize() { + // Read Cond Handle Key + + ATH_MSG_DEBUG("WaveformTimingTool::initialize()"); + + ATH_CHECK(m_timingReadKey.initialize()); + ATH_CHECK(m_offsetReadKey.initialize()); + + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +StatusCode +WaveformTimingTool::finalize() { + // Print where you are + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +float +WaveformTimingTool::nominalTriggerTime(const EventContext& ctx) const { + // Print where you are + ATH_MSG_DEBUG("in nominalTriggerTime()"); + + float time=-1.; + + // Read Cond Handle + SG::ReadCondHandle<AthenaAttributeList> readHandle{m_timingReadKey, ctx}; + const AthenaAttributeList* readCdo(*readHandle); + + if (readCdo==nullptr) { + ATH_MSG_FATAL("Null pointer to the read conditions object"); + return time; + } + + // Get the validitiy range + EventIDRange rangeW; + if (not readHandle.range(rangeW)) { + ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key()); + return time; + } + ATH_MSG_DEBUG("Range of input is " << rangeW); + + // Read time info + + const CondAttrListCollection::AttributeList &payload{*readCdo}; + if (payload.exists("NominalTriggerTime") and not payload["NominalTriggerTime"].isNull()) { + time = payload["NominalTriggerTime"].data<float>(); + ATH_MSG_DEBUG("Found nominal trigger time "<<time<<" ns"); + } else { + ATH_MSG_WARNING("No valid nominal trigger time found!"); + } + + return time; +} + +//---------------------------------------------------------------------- +float +WaveformTimingTool::triggerTimeOffset(const EventContext& ctx, int channel) const { + + ATH_MSG_DEBUG("in triggerTimeOffset("<<channel<<")"); + + float time=0.; + + // Read Cond Handle + SG::ReadCondHandle<CondAttrListCollection> readHandle{m_offsetReadKey, ctx}; + const CondAttrListCollection* readCdo{*readHandle}; + if (readCdo==nullptr) { + ATH_MSG_FATAL("Null pointer to the read conditions object"); + return time; + } + // Get the validitiy range + EventIDRange rangeW; + if (not readHandle.range(rangeW)) { + ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key()); + return time; + } + ATH_MSG_DEBUG("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdo->size()= " << readCdo->size()); + ATH_MSG_DEBUG("Range of input is " << rangeW); + + // Read offset for specific channel + const CondAttrListCollection::AttributeList& payload{readCdo->attributeList(channel)}; + + if (payload.exists("TriggerOffset") and not payload["TriggerOffset"].isNull()) { + time = payload["TriggerOffset"].data<float>(); + ATH_MSG_DEBUG("Found digitizer channel " << channel << " triger offset as " << time); + } else { + ATH_MSG_WARNING("No valid trigger offset found for channel "<<channel<<"!"); + } + + return time; + +} + +//---------------------------------------------------------------------- +float +WaveformTimingTool::nominalTriggerTime(void) const { + const EventContext& ctx(Gaudi::Hive::currentContext()); + return nominalTriggerTime(ctx); +} + +float +WaveformTimingTool::triggerTimeOffset(int channel) const { + const EventContext& ctx(Gaudi::Hive::currentContext()); + return triggerTimeOffset(ctx, channel); +} + + + + + + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b69e52b200907a369865f85b5b709aec5341d0dd --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformTimingTool.h @@ -0,0 +1,69 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations +*/ + +/** @file WaveformTimingTool.h Header file for WaveformTimingTool. + @author Eric Torrence, 20/04/22 +*/ + +// Multiple inclusion protection +#ifndef WAVEFORM_TIMING_TOOL +#define WAVEFORM_TIMING_TOOL + +// Include interface class +#include "AthenaBaseComps/AthAlgTool.h" +#include "WaveformConditionsTools/IWaveformTimingTool.h" + +// Include Athena stuff +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "StoreGate/ReadCondHandleKey.h" + +#include "GaudiKernel/ICondSvc.h" +#include "Gaudi/Property.h" + +// Include Gaudi classes +#include "GaudiKernel/EventContext.h" + +/** This class contains a Tool that reads Waveform timing data and makes it available + to other algorithms. +*/ + +class WaveformTimingTool: public extends<AthAlgTool, IWaveformTimingTool> { + + public: + //----------Public Member Functions----------// + // Structors + WaveformTimingTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor + virtual ~WaveformTimingTool() = default; //!< Destructor + + // Standard Gaudi functions + virtual StatusCode initialize() override; //!< Gaudi initialiser + virtual StatusCode finalize() override; //!< Gaudi finaliser + + // Methods to return timing data + // Channels indexed by digitizer channel number + // All times are in ns + + // Nominal trigger time (in ns) in the digitizer readout + virtual float nominalTriggerTime(void) const override; + virtual float nominalTriggerTime(const EventContext& ctx) const override; + + // Channel-by-channel corrections to the nominal trigger time (in ns) + // A given channel should be centered at nominal + offset + virtual float triggerTimeOffset(int channel) const override; + virtual float triggerTimeOffset(const EventContext& ctx, int channel) const override; + + private: + + // Read Cond Handle + SG::ReadCondHandleKey<AthenaAttributeList> m_timingReadKey{this, "TimingReadKey", "/WAVE/DAQ/Timing", "Key of timing folder"}; + SG::ReadCondHandleKey<CondAttrListCollection> m_offsetReadKey{this, "OffsetReadKey", "/WAVE/DAQ/TimingOffset", "Key of timing offset folder"}; + + ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"}; + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORM_CABLE_MAPPING_TOOL diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx index 1f6a41ac923beab0533fcd60066b86143f813b90..f694fef647428802bfb98ab393e4f784180ae2b0 100644 --- a/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx @@ -1,3 +1,7 @@ +#include "../WaveformRangeTool.h" +#include "../WaveformTimingTool.h" #include "../WaveformCableMappingTool.h" +DECLARE_COMPONENT( WaveformRangeTool ) +DECLARE_COMPONENT( WaveformTimingTool ) DECLARE_COMPONENT( WaveformCableMappingTool ) diff --git a/faser-common b/faser-common index 5124b0e78dbcc4a05c22f511700d5dbcdb4808df..69a90ec95da88a00097fb809bede6c2bae8c02d6 160000 --- a/faser-common +++ b/faser-common @@ -1 +1 @@ -Subproject commit 5124b0e78dbcc4a05c22f511700d5dbcdb4808df +Subproject commit 69a90ec95da88a00097fb809bede6c2bae8c02d6 diff --git a/graphics/VTI12/README.md b/graphics/VTI12/README.md index 708260f7e77ac3591b3d629b1f6f76107b0a6eb8..bfd96be854ac9668b93117ed4ea20c04ba0fb023 100644 --- a/graphics/VTI12/README.md +++ b/graphics/VTI12/README.md @@ -8,7 +8,7 @@ To run on Calypso MC data (from an installation (run) directory): Note that VP1PLUGINPATH can be ninja-changed by asetup, and if it does not include the Calypso installation library folder, nothing will work. Also note that it must be an ABSOLUTE (not relative) path! -You can also give the -detdescr="FASER-01" (baseline detector), -detdescr="FASER-02" (baseline + IFT), -detdescr="FASERNU-02" (baseline + IFT + emulsion) or -detdescr="FASER-TB00" (2021 Test-beam) to specify the geometry. +You can also give the -detdescr="FASER-01" (baseline detector), -detdescr="FASER-02" (baseline + IFT), -detdescr="FASERNU-03" (baseline + IFT + emulsion) or -detdescr="FASER-TB00" (2021 Test-beam) to specify the geometry. You also need either -globcond="OFLCOND-FASER-01" (baseline) or -globcond="OFLCOND-FASER-02" (IFT with or without emulsion), or -globcond="OFLCOND-FASER-TB00" (test-beam) flags to specify the conditions. diff --git a/graphics/VTI12/VTI12Algs/share/vti12.py b/graphics/VTI12/VTI12Algs/share/vti12.py index 3878899db88d845cd247602b91faf6a1204cee7b..07a3a97a2ca79ae0f920f1516590a03c55a2a13b 100644 --- a/graphics/VTI12/VTI12Algs/share/vti12.py +++ b/graphics/VTI12/VTI12Algs/share/vti12.py @@ -32,7 +32,8 @@ if not 'vp1NoSortDBReplicas' in dir(): vp1NoSortDBReplicas=False if not 'vp1FilterEvents' in dir(): vp1FilterEvents="" if not 'vp1NoGui' in dir(): vp1NoGui=False if not 'vp1SpacePoints' in dir(): vp1SpacePoints=False -if not 'vp1Cavern' in dir(): vp1Cavern=False +# if not 'vp1Cavern' in dir(): vp1Cavern=False +vp1Cavern=True if not 'vp1NoAutoConf' in dir(): vp1NoAutoConf=False if not 'vp1Trig' in dir(): vp1Trig=False if not 'vp1NSW' in dir(): vp1NSW=False diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h index a50cf0d19605f3bbd922459105c416271968d1d7..8aefd8e48631325fefad9f9a25253e5c2f147a13 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/VTI12GeometrySystems/VP1GeoFlags.h @@ -27,14 +27,16 @@ public: None = 0x00000000, Emulsion = 0x00000001, - Veto = 0x00000002, - Trigger = 0x00000004, - Preshower = 0x00000008, + VetoNu = 0x00000002, + Veto = 0x00000004, + Trigger = 0x00000008, + Preshower = 0x00000010, - SCT = 0x00000010, - Dipole = 0x00000020, + SCT = 0x00000020, + Dipole = 0x00000040, - Ecal = 0x00000040, + Ecal = 0x00000080, + CavernInfra = 0x00000100, // Pixel = 0x00000001, // bit 0 // SCT = 0x00000002, // 1 // TRT = 0x00000004, // 2 diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx index e6325f8f2ff62915d13dc462bd87e626b23c9227..fbb27a254fe2aa6454d1e5b80060e083804ffc1e 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/GeoSysController.cxx @@ -150,6 +150,7 @@ GeoSysController::GeoSysController(IVP1System * sys) m_d->subSysCheckBoxMap[VP1GeoFlags::Emulsion] = m_d->ui.checkBox_Emulsion; // SCINTILLATOR + m_d->subSysCheckBoxMap[VP1GeoFlags::VetoNu] = m_d->ui.checkBox_VetoNu; m_d->subSysCheckBoxMap[VP1GeoFlags::Veto] = m_d->ui.checkBox_Veto; m_d->subSysCheckBoxMap[VP1GeoFlags::Trigger] = m_d->ui.checkBox_Trigger; m_d->subSysCheckBoxMap[VP1GeoFlags::Preshower] = m_d->ui.checkBox_Preshower; @@ -161,6 +162,9 @@ GeoSysController::GeoSysController(IVP1System * sys) // Calorimeter m_d->subSysCheckBoxMap[VP1GeoFlags::Ecal] = m_d->ui.checkBox_Ecal; + // Cavern + m_d->subSysCheckBoxMap[VP1GeoFlags::CavernInfra] = m_d->ui.checkBox_CavernInfra; + // MISCELLANEOUS // OTHER m_d->subSysCheckBoxMap[VP1GeoFlags::AllUnrecognisedVolumes] = m_d->ui.checkBox_other; diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx index 8e4b61921f3d849bdd127f00f5c0c4ca1b868aa2..e5c0eed5d6622562488cc3075dc3115659796fcc 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VP1GeometrySystem.cxx @@ -329,12 +329,14 @@ QWidget * VP1GeometrySystem::buildController() bool negategrandchildrenregexp = false // wheter we want to negate teh granchildren regex */ m_d->addSubSystem( VP1GeoFlags::Emulsion, "Emulsion"); + m_d->addSubSystem( VP1GeoFlags::VetoNu, "VetoNu"); m_d->addSubSystem( VP1GeoFlags::Veto, "Veto"); m_d->addSubSystem( VP1GeoFlags::Trigger, "Trigger"); m_d->addSubSystem( VP1GeoFlags::Preshower,"Preshower"); m_d->addSubSystem( VP1GeoFlags::SCT, "SCT"); m_d->addSubSystem( VP1GeoFlags::Dipole, "Dipole"); m_d->addSubSystem( VP1GeoFlags::Ecal, "Ecal"); + m_d->addSubSystem( VP1GeoFlags::CavernInfra, "Cavern"); @@ -1109,6 +1111,12 @@ void VP1GeometrySystem::Imp::createPathExtras(const VolumeHandle* volhandle, QSt entries.push("Veto::Veto"); return; } + case VP1GeoFlags::VetoNu:{ + prefix = QString("VetoNu::"); + entries.push("SCINT::SCINT"); + entries.push("VetoNu::VetoNu"); + return; + } case VP1GeoFlags::Trigger:{ prefix = QString("Trigger::"); entries.push("SCINT::SCINT"); @@ -1139,6 +1147,13 @@ void VP1GeometrySystem::Imp::createPathExtras(const VolumeHandle* volhandle, QSt entries.push("Ecal::Ecal"); return; } + case VP1GeoFlags::CavernInfra:{ + prefix = QString("Cavern::"); + entries.push("CAVERN::CAVERN"); + entries.push("Trench::Trench"); + return; + } + case VP1GeoFlags::None: case VP1GeoFlags::AllUnrecognisedVolumes: default:{ diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx index 82825c71806f9cddaef0e065a30086fffae4e270..27fd3362c4a18bfa999517529fc925951fbff20c 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VisAttributes.cxx @@ -160,6 +160,7 @@ DetVisAttributes::DetVisAttributes() { material->specularColor.setValue(.915152, .915152, .915152); material->shininess.setValue(0.642424); add("Veto",material); + add("VetoNu",material); add("Trigger",material); add("Preshower",material); } diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx index b1aff16c0a2c354c77428af96bf7fb8b7c1d2dc6..ea681cdd6fe6b261a90d6701c5b8fa864777b39c 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/VolumeTreeModel.cxx @@ -31,7 +31,7 @@ class VolumeTreeModel::Imp { public: //Static definitions of sections and which subsystems goes in which sections: - enum SECTION { UNKNOWN, NEUTRINO, SCINT, TRACKER, CALO, MISC }; + enum SECTION { UNKNOWN, NEUTRINO, SCINT, TRACKER, CALO, MISC, CAVERN }; static std::map<SECTION,QString> section2string; static std::map<VP1GeoFlags::SubSystemFlag,SECTION> subsysflag2section; static std::map<VP1GeoFlags::SubSystemFlag,QString> subsysflag2string; @@ -108,6 +108,7 @@ VolumeTreeModel::VolumeTreeModel( QObject * parent ) Imp::section2string[Imp::SCINT] = "Scintillators"; Imp::section2string[Imp::TRACKER] = "Tracker"; Imp::section2string[Imp::CALO] = "Calorimeter"; + Imp::section2string[Imp::CAVERN] = "Cavern"; Imp::section2string[Imp::MISC] = "Miscellaneous"; } if (Imp::subsysflag2section.empty()) { @@ -116,6 +117,7 @@ VolumeTreeModel::VolumeTreeModel( QObject * parent ) Imp::defineSubSystem(VP1GeoFlags::Emulsion, "Emulsion", Imp::NEUTRINO); // Scintillator Imp::defineSubSystem(VP1GeoFlags::Veto, "Veto", Imp::SCINT); + Imp::defineSubSystem(VP1GeoFlags::VetoNu, "VetoNu", Imp::SCINT); Imp::defineSubSystem(VP1GeoFlags::Trigger, "Trigger", Imp::SCINT); Imp::defineSubSystem(VP1GeoFlags::Preshower, "Preshower", Imp::SCINT); // Tracker @@ -123,6 +125,8 @@ VolumeTreeModel::VolumeTreeModel( QObject * parent ) Imp::defineSubSystem(VP1GeoFlags::Dipole, "Dipole", Imp::TRACKER); // Calorimeter Imp::defineSubSystem(VP1GeoFlags::Ecal, "Ecal", Imp::CALO); + // Cavern + Imp::defineSubSystem(VP1GeoFlags::CavernInfra, "Cavern", Imp::CAVERN); } } diff --git a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui index be9ac807d6b5d2511d214a4a6265064f0bd7ef26..a5ef9228de57c9a314e6348a78af6eca572d31cb 100644 --- a/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui +++ b/graphics/VTI12/VTI12Systems/VTI12GeometrySystems/src/geometrysystemcontroller.ui @@ -239,20 +239,27 @@ <number>0</number> </property> <item row="0" column="0"> + <widget class="QCheckBox" name="checkBox_VetoNu"> + <property name="text"> + <string>VetoNu</string> + </property> + </widget> + </item> + <item row="0" column="1"> <widget class="QCheckBox" name="checkBox_Veto"> <property name="text"> <string>Veto</string> </property> </widget> </item> - <item row="0" column="1"> + <item row="1" column="0"> <widget class="QCheckBox" name="checkBox_Trigger"> <property name="text"> <string>Trigger</string> </property> </widget> </item> - <item row="0" column="2"> + <item row="1" column="1"> <widget class="QCheckBox" name="checkBox_Preshower"> <property name="text"> <string>Preshower</string> @@ -333,7 +340,7 @@ <property name="title"> <string>Calorimeter</string> </property> - <layout class="QVBoxLayout" name="_12"> + <layout class="QVBoxLayout" name="_121"> <property name="spacing"> <number>0</number> </property> @@ -350,7 +357,7 @@ <number>4</number> </property> <item> - <layout class="QHBoxLayout" name="_14"> + <layout class="QHBoxLayout" name="_141"> <item> <widget class="QCheckBox" name="checkBox_Ecal"> <property name="text"> diff --git a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx index 19634a20a2b55431ade9a88704a8b9ca6cf06ba4..a9eec098eed63415284583faeaf4b0e4fe71dd0c 100755 --- a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/VP1SimHitSystem.cxx @@ -64,6 +64,7 @@ QWidget* VP1SimHitSystem::buildController() // Populate Check Box Names Map m_clockwork->checkBoxNamesMap.insert(ui.chbxEmulsionHits,"Emulsion"); + m_clockwork->checkBoxNamesMap.insert(ui.chbxVetoNuHits,"VetoNu"); m_clockwork->checkBoxNamesMap.insert(ui.chbxVetoHits,"Veto"); m_clockwork->checkBoxNamesMap.insert(ui.chbxTriggerHits,"Trigger"); m_clockwork->checkBoxNamesMap.insert(ui.chbxPreshowerHits,"Preshower"); @@ -84,6 +85,7 @@ void VP1SimHitSystem::systemcreate(StoreGateSvc* /*detstore*/) { // Populate Color Map m_clockwork->colorMap.insert("Emulsion",SbColor(1,0,1)); + m_clockwork->colorMap.insert("VetoNu",SbColor(0,1,1)); m_clockwork->colorMap.insert("Veto",SbColor(0,0,1)); m_clockwork->colorMap.insert("Trigger",SbColor(1,1,1)); m_clockwork->colorMap.insert("Preshower",SbColor(1,0,0)); @@ -227,6 +229,25 @@ void VP1SimHitSystem::buildHitTree(const QString& detector) else message("Unable to retrieve Veto Hits"); } + else if(detector=="VetoNu") + { + // + // VetoNu: + // + const ScintHitCollection* p_collection = nullptr; + if(sg->retrieve(p_collection, "VetoNuHits")==StatusCode::SUCCESS) + { + for(ScintHitConstIterator i_hit=p_collection->begin(); i_hit!=p_collection->end(); ++i_hit) + { + GeoScintHit ghit(*i_hit); + if(!ghit) continue; + HepGeom::Point3D<double> u = ghit.getGlobalPosition(); + hitVtxProperty->vertex.set1Value(hitCount++,u.x(),u.y(),u.z()); + } + } + else + message("Unable to retrieve VetoNu Hits"); + } else if(detector=="Trigger") { // diff --git a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui index 67f62d51f9450ac5416d1452f106c37633f25809..b9797015a001150b7da85edc1463ee245a168c9d 100755 --- a/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui +++ b/graphics/VTI12/VTI12Systems/VTI12SimHitSystems/src/simhitcontrollerform.ui @@ -106,6 +106,13 @@ <string>Scintillator</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="chbxVetoNuHits"> + <property name="text"> + <string>VetoNu Hits</string> + </property> + </widget> + </item> <item> <widget class="QCheckBox" name="chbxVetoHits"> <property name="text"> @@ -181,7 +188,7 @@ <property name="title"> <string>Calorimeter</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_31"> <item> <widget class="QCheckBox" name="chbxCaloHits"> <property name="text"> diff --git a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx index ef731fa9549323d72b6b4f7d516fb7989b4182b3..eedf4ed49e4a50c1c6c6534f47cb8297659593e5 100644 --- a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackCollHandle_TruthTracks.cxx @@ -127,8 +127,9 @@ QStringList TrackCollHandle_TruthTracks::availableCollections( IVP1System*sys ) if (VP1JobConfigInfo::hasVetoGeometry() || VP1JobConfigInfo::hasTriggerGeometry() || - VP1JobConfigInfo::hasPreshowerGeometry()) - keys_scintillatorhits = sgcont.getKeys<ScintHitCollection>();//"VetoHits", "TriggerHits" and "PreshowerHits" + VP1JobConfigInfo::hasPreshowerGeometry() || + VP1JobConfigInfo::hasVetoNuGeometry()) + keys_scintillatorhits = sgcont.getKeys<ScintHitCollection>();//"VetoHits", "VetoNuHits", "TriggerHits" and "PreshowerHits" if (VP1JobConfigInfo::hasSCTGeometry()) keys_siliconhits = sgcont.getKeys<FaserSiHitCollection>();//"SCT_Hits" if (VP1JobConfigInfo::hasEcalGeometry()) @@ -264,6 +265,7 @@ bool TrackCollHandle_TruthTracks::Imp::loadHitLists(std::map<SimBarCode,SimHitLi if (VP1JobConfigInfo::hasEmulsionGeometry()) addHitCollections<NeutrinoHitCollection>(hitLists); if (VP1JobConfigInfo::hasVetoGeometry() || + VP1JobConfigInfo::hasVetoNuGeometry() || VP1JobConfigInfo::hasTriggerGeometry() || VP1JobConfigInfo::hasPreshowerGeometry()) // std::cout << "Called addHitCollections" << std::endl; diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformHitSystem.h b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformHitSystem.h index fa0831b3f579c8c052fd3d38639da1a491888d7c..52312553b7c1a6aa39d64e8535faa1a463f7c946 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformHitSystem.h +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformHitSystem.h @@ -45,6 +45,7 @@ public: public slots: void updateVetoElements(bool); + void updateVetoNuElements(bool); void updateTriggerElements(bool); void updatePreshowerElements(bool); void updateCalorimeterElements(bool); diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformSystem.h b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformSystem.h index d17e3b60f5e58fc5709064be6c77215c21d7a5b4..73535d6ad2f19aac9982a89b8f559615268de775 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformSystem.h +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/VP1WaveformSystem.h @@ -45,6 +45,7 @@ public: public slots: void updateVetoElements(bool); + void updateVetoNuElements(bool); void updateTriggerElements(bool); void updatePreshowerElements(bool); void updateCalorimeterElements(bool); diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/WaveformSysController.h b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/WaveformSysController.h index ebb3c4c34ca693d245a300b2f47813ce738b4597..74a2191c7277af9cbf31374466911804ff531e1e 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/WaveformSysController.h +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/VTI12WaveformSystems/WaveformSysController.h @@ -40,6 +40,7 @@ public: /////////////////////////////////// bool vetoEnabled() const; + bool vetoNuEnabled() const; bool triggerEnabled() const; bool preshowerEnabled() const; bool calorimeterEnabled() const; @@ -52,6 +53,7 @@ public: /////////////////////////////////////// signals: void vetoEnabledChanged(bool); + void vetoNuEnabledChanged(bool); void triggerEnabledChanged(bool); void preshowerEnabledChanged(bool); void calorimeterEnabledChanged(bool); @@ -65,6 +67,7 @@ private: private slots: void possibleChange_vetoEnabled(); + void possibleChange_vetoNuEnabled(); void possibleChange_triggerEnabled(); void possibleChange_preshowerEnabled(); void possibleChange_calorimeterEnabled(); diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformHitSystem.cxx b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformHitSystem.cxx index 7d0c07c942414273964ffed851b27b745cca2756..c46089cf4a23397d324b422ea07d4dcc008e896f 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformHitSystem.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformHitSystem.cxx @@ -46,6 +46,7 @@ public: VP1WaveformHitSystem *theclass; WaveformSysController * controller; std::vector<QChart*> vetoCharts; + std::vector<QChart*> vetoNuCharts; std::vector<QChart*> triggerCharts; std::vector<QChart*> preshowerCharts; std::vector<QChart*> calorimeterCharts; @@ -82,6 +83,7 @@ QWidget * VP1WaveformHitSystem::buildController() m_d->controller = new WaveformSysController(this); connect(m_d->controller,SIGNAL(vetoEnabledChanged(bool)),this,SLOT(updateVetoElements(bool))); + connect(m_d->controller,SIGNAL(vetoNuEnabledChanged(bool)),this,SLOT(updateVetoNuElements(bool))); connect(m_d->controller,SIGNAL(triggerEnabledChanged(bool)),this,SLOT(updateTriggerElements(bool))); connect(m_d->controller,SIGNAL(preshowerEnabledChanged(bool)),this,SLOT(updatePreshowerElements(bool))); connect(m_d->controller,SIGNAL(calorimeterEnabledChanged(bool)),this,SLOT(updateCalorimeterElements(bool))); @@ -99,6 +101,7 @@ void VP1WaveformHitSystem::buildEventItemCollection(StoreGateSvc* sg, VP1Graphic } m_d->vetoCharts.clear(); + m_d->vetoNuCharts.clear(); m_d->triggerCharts.clear(); m_d->preshowerCharts.clear(); m_d->calorimeterCharts.clear(); @@ -107,6 +110,7 @@ void VP1WaveformHitSystem::buildEventItemCollection(StoreGateSvc* sg, VP1Graphic // m_d->nCharts = 0; m_d->createCharts(sg, root, m_d->controller->vetoEnabled(), m_d->vetoCharts, "VetoWaveformHits"); + m_d->createCharts(sg, root, m_d->controller->vetoNuEnabled(), m_d->vetoNuCharts, "VetoNuWaveformHits"); m_d->createCharts(sg, root, m_d->controller->triggerEnabled(), m_d->triggerCharts, "TriggerWaveformHits"); m_d->createCharts(sg, root, m_d->controller->preshowerEnabled(), m_d->preshowerCharts, "PreshowerWaveformHits"); m_d->createCharts(sg, root, m_d->controller->calorimeterEnabled(), m_d->calorimeterCharts, "CaloWaveformHits"); @@ -264,6 +268,7 @@ QChart* VP1WaveformHitSystem::Imp::createChart(const std::vector<float>& times, void VP1WaveformHitSystem::Imp::getVisible() { visibleCharts.clear(); + getVisible(vetoNuCharts); getVisible(vetoCharts); getVisible(triggerCharts); getVisible(preshowerCharts); @@ -356,6 +361,16 @@ void VP1WaveformHitSystem::updateVetoElements(bool enabled) m_d->layoutCharts(); } +void VP1WaveformHitSystem::updateVetoNuElements(bool enabled) +{ + for (QChart* c : m_d->vetoNuCharts) + { + c->setVisible(enabled); + } + m_d->layoutCharts(); +} + + void VP1WaveformHitSystem::updateTriggerElements(bool enabled) { for (QChart* c : m_d->triggerCharts) diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformSystem.cxx b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformSystem.cxx index ffe6bd00acecfd6f3fe611c01b24a1f2ea6afd1a..172bdebd9d22b183a4304bd8414b6e6f3be3985e 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformSystem.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/VP1WaveformSystem.cxx @@ -45,6 +45,7 @@ public: VP1WaveformSystem *theclass; WaveformSysController * controller; std::vector<QChart*> vetoCharts; + std::vector<QChart*> vetoNuCharts; std::vector<QChart*> triggerCharts; std::vector<QChart*> preshowerCharts; std::vector<QChart*> calorimeterCharts; @@ -80,6 +81,7 @@ QWidget * VP1WaveformSystem::buildController() m_d->controller = new WaveformSysController(this); connect(m_d->controller,SIGNAL(vetoEnabledChanged(bool)),this,SLOT(updateVetoElements(bool))); + connect(m_d->controller,SIGNAL(vetoNuEnabledChanged(bool)),this,SLOT(updateVetoNuElements(bool))); connect(m_d->controller,SIGNAL(triggerEnabledChanged(bool)),this,SLOT(updateTriggerElements(bool))); connect(m_d->controller,SIGNAL(preshowerEnabledChanged(bool)),this,SLOT(updatePreshowerElements(bool))); connect(m_d->controller,SIGNAL(calorimeterEnabledChanged(bool)),this,SLOT(updateCalorimeterElements(bool))); @@ -97,6 +99,7 @@ void VP1WaveformSystem::buildEventItemCollection(StoreGateSvc* sg, VP1GraphicsIt } m_d->vetoCharts.clear(); + m_d->vetoNuCharts.clear(); m_d->triggerCharts.clear(); m_d->preshowerCharts.clear(); m_d->calorimeterCharts.clear(); @@ -105,6 +108,7 @@ void VP1WaveformSystem::buildEventItemCollection(StoreGateSvc* sg, VP1GraphicsIt // m_d->nCharts = 0; m_d->createCharts(sg, root, m_d->controller->vetoEnabled(), m_d->vetoCharts, "VetoWaveforms"); + m_d->createCharts(sg, root, m_d->controller->vetoNuEnabled(), m_d->vetoNuCharts, "VetoNuWaveforms"); m_d->createCharts(sg, root, m_d->controller->triggerEnabled(), m_d->triggerCharts, "TriggerWaveforms"); m_d->createCharts(sg, root, m_d->controller->preshowerEnabled(), m_d->preshowerCharts, "PreshowerWaveforms"); m_d->createCharts(sg, root, m_d->controller->calorimeterEnabled(), m_d->calorimeterCharts, "CaloWaveforms"); @@ -194,6 +198,7 @@ void VP1WaveformSystem::Imp::getVisible() { visibleCharts.clear(); getVisible(vetoCharts); + getVisible(vetoNuCharts); getVisible(triggerCharts); getVisible(preshowerCharts); getVisible(calorimeterCharts); @@ -286,6 +291,15 @@ void VP1WaveformSystem::updateVetoElements(bool enabled) m_d->layoutCharts(); } +void VP1WaveformSystem::updateVetoNuElements(bool enabled) +{ + for (QChart* c : m_d->vetoNuCharts) + { + c->setVisible(enabled); + } + m_d->layoutCharts(); +} + void VP1WaveformSystem::updateTriggerElements(bool enabled) { for (QChart* c : m_d->triggerCharts) diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/WaveformSysController.cxx b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/WaveformSysController.cxx index 765ce0d4d702245b2c2733f4003824b21a150ba2..856fc0071f9679cfbf585bd0279587a521fcc220 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/WaveformSysController.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/WaveformSysController.cxx @@ -45,6 +45,7 @@ public: } bool last_vetoEnabled; + bool last_vetoNuEnabled; bool last_triggerEnabled; bool last_preshowerEnabled; bool last_calorimeterEnabled; @@ -62,6 +63,9 @@ WaveformSysController::WaveformSysController(IVP1System * sys) addUpdateSlot(SLOT(possibleChange_vetoEnabled())); connectToLastUpdateSlot(m_d->ui.checkBox_vetoEnabled); + addUpdateSlot(SLOT(possibleChange_vetoNuEnabled())); + connectToLastUpdateSlot(m_d->ui.checkBox_vetoNuEnabled); + addUpdateSlot(SLOT(possibleChange_triggerEnabled())); connectToLastUpdateSlot(m_d->ui.checkBox_triggerEnabled); @@ -91,6 +95,11 @@ bool WaveformSysController::vetoEnabled() const return m_d->ui.checkBox_vetoEnabled->isChecked(); } +bool WaveformSysController::vetoNuEnabled() const +{ + return m_d->ui.checkBox_vetoNuEnabled->isChecked(); +} + bool WaveformSysController::triggerEnabled() const { return m_d->ui.checkBox_triggerEnabled->isChecked(); @@ -126,6 +135,7 @@ void WaveformSysController::actualSaveSettings(VP1Serialise&s) const { s.save(m_d->ui.checkBox_vetoEnabled); + s.save(m_d->ui.checkBox_vetoNuEnabled); s.save(m_d->ui.checkBox_triggerEnabled); s.save(m_d->ui.checkBox_preshowerEnabled); s.save(m_d->ui.checkBox_calorimeterEnabled); @@ -143,6 +153,7 @@ void WaveformSysController::actualRestoreSettings(VP1Deserialise& s) } s.restore(m_d->ui.checkBox_vetoEnabled); + s.restore(m_d->ui.checkBox_vetoNuEnabled); s.restore(m_d->ui.checkBox_triggerEnabled); s.restore(m_d->ui.checkBox_preshowerEnabled); s.restore(m_d->ui.checkBox_calorimeterEnabled); @@ -157,6 +168,7 @@ void WaveformSysController::actualRestoreSettings(VP1Deserialise& s) #define VP1CONTROLLERCLASSNAME WaveformSysController #include "VP1Base/VP1ControllerMacros.h" POSSIBLECHANGE_IMP(vetoEnabled) +POSSIBLECHANGE_IMP(vetoNuEnabled) POSSIBLECHANGE_IMP(triggerEnabled) POSSIBLECHANGE_IMP(preshowerEnabled) POSSIBLECHANGE_IMP(calorimeterEnabled) diff --git a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/waveformcontrollerform.ui b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/waveformcontrollerform.ui index cb854170cb4351c4f61e0672cd51cf6853af6fe2..a90933874c20e67ba073ae34ccfa1053b86d2a41 100644 --- a/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/waveformcontrollerform.ui +++ b/graphics/VTI12/VTI12Systems/VTI12WaveformSystems/src/waveformcontrollerform.ui @@ -32,6 +32,16 @@ <number>0</number> </property> <item row="0" column="0"> + <widget class="QCheckBox" name="checkBox_vetoNuEnabled"> + <property name="text"> + <string>VetoNu</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> <widget class="QCheckBox" name="checkBox_vetoEnabled"> <property name="text"> <string>Veto</string> @@ -41,7 +51,7 @@ </property> </widget> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QCheckBox" name="checkBox_triggerEnabled"> <property name="text"> <string>Trigger</string> @@ -51,7 +61,7 @@ </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QCheckBox" name="checkBox_preshowerEnabled"> <property name="text"> <string>Preshower</string> @@ -61,7 +71,7 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="4" column="0"> <widget class="QCheckBox" name="checkBox_calorimeterEnabled"> <property name="text"> <string>Calorimeter</string> @@ -71,7 +81,7 @@ </property> </widget> </item> - <item row="4" column="0"> + <item row="5" column="0"> <widget class="QCheckBox" name="checkBox_clockEnabled"> <property name="text"> <string>Clock</string> @@ -81,7 +91,7 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QCheckBox" name="checkBox_testEnabled"> <property name="text"> <string>Test</string> diff --git a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h index ff521e608e83558942909b2af4eb7f5f3d227f8d..46ae0c23a4ed356d0149f79b0378dc047fdc737d 100644 --- a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h +++ b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1DetInfo.h @@ -23,6 +23,7 @@ class StoreGateSvc; namespace NeutrinoDD { class EmulsionDetectorManager; } namespace TrackerDD { class SCT_DetectorManager; } namespace ScintDD { class VetoDetectorManager; } +namespace ScintDD { class VetoNuDetectorManager; } namespace ScintDD { class TriggerDetectorManager; } namespace ScintDD { class PreshowerDetectorManager; } namespace CaloDD { class EcalDetectorManager; } @@ -31,6 +32,7 @@ class FaserDetectorID; class EmulsionDetectorID; class ScintDetectorID; class VetoID; +class VetoNuID; class TriggerID; class PreshowerID; class FaserSCT_ID; @@ -51,6 +53,7 @@ public: static const NeutrinoDD::EmulsionDetectorManager * emulsionDetMgr(); static const ScintDD::VetoDetectorManager * vetoDetMgr(); + static const ScintDD::VetoNuDetectorManager * vetoNuDetMgr(); static const ScintDD::TriggerDetectorManager * triggerDetMgr(); static const ScintDD::PreshowerDetectorManager * preshowerDetMgr(); @@ -66,6 +69,7 @@ public: static const EmulsionID * emulsionIDHelper(); static const VetoID * vetoIDHelper(); + static const VetoNuID * vetoNuIDHelper(); static const TriggerID * triggerIDHelper(); static const PreshowerID * preshowerIDHelper(); diff --git a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h index a90910903a46ee80f207ee10a8e5d2295602fe33..96c80ac470dedb37562dc2b6d7e1c38ff5bec9c3 100644 --- a/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h +++ b/graphics/VTI12/VTI12Utils/VTI12Utils/VP1JobConfigInfo.h @@ -35,6 +35,7 @@ public: static bool hasEmulsionGeometry(); static bool hasVetoGeometry(); + static bool hasVetoNuGeometry(); static bool hasTriggerGeometry(); static bool hasPreshowerGeometry(); @@ -42,6 +43,8 @@ public: static bool hasEcalGeometry(); + static bool hasCavernInfraGeometry(); + //Top geomodel volume link (not strictly "JobConfig", but here it is): static const GeoPVConstLink * geoModelWorld();//might return 0 diff --git a/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx b/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx index ba2ecb3fb349040c013933feb8d81474ddc2f5a8..b92e7cf2c2f1f066c2177de36448b49f8bf78fcb 100644 --- a/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx +++ b/graphics/VTI12/VTI12Utils/src/VP1DetInfo.cxx @@ -25,6 +25,7 @@ #include "NeutrinoReadoutGeometry/EmulsionDetectorManager.h" #include "ScintReadoutGeometry/VetoDetectorManager.h" +#include "ScintReadoutGeometry/VetoNuDetectorManager.h" #include "ScintReadoutGeometry/TriggerDetectorManager.h" #include "ScintReadoutGeometry/PreshowerDetectorManager.h" @@ -37,6 +38,7 @@ #include "NeutrinoIdentifier/EmulsionID.h" #include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" #include "ScintIdentifier/TriggerID.h" #include "ScintIdentifier/PreshowerID.h" @@ -58,6 +60,7 @@ public: static const NeutrinoDD::EmulsionDetectorManager * m_emulsionDetMgr; static const ScintDD::VetoDetectorManager * m_vetoDetMgr; + static const ScintDD::VetoNuDetectorManager * m_vetoNuDetMgr; static const ScintDD::TriggerDetectorManager * m_triggerDetMgr; static const ScintDD::PreshowerDetectorManager * m_preshowerDetMgr; @@ -70,6 +73,7 @@ public: static const EmulsionID * m_emulsionIDHelper; static const VetoID * m_vetoIDHelper; + static const VetoNuID * m_vetoNuIDHelper; static const TriggerID * m_triggerIDHelper; static const PreshowerID * m_preshowerIDHelper; @@ -84,6 +88,7 @@ const char VP1DetInfo::Imp::m_badInitFlag = ' '; const NeutrinoDD::EmulsionDetectorManager * VP1DetInfo::Imp::m_emulsionDetMgr = 0; const ScintDD::VetoDetectorManager * VP1DetInfo::Imp::m_vetoDetMgr = 0; +const ScintDD::VetoNuDetectorManager * VP1DetInfo::Imp::m_vetoNuDetMgr = 0; const ScintDD::TriggerDetectorManager * VP1DetInfo::Imp::m_triggerDetMgr = 0; const ScintDD::PreshowerDetectorManager * VP1DetInfo::Imp::m_preshowerDetMgr = 0; @@ -96,6 +101,7 @@ const FaserDetectorID * VP1DetInfo::Imp::m_faserIDHelper = 0; const EmulsionID * VP1DetInfo::Imp::m_emulsionIDHelper = 0; const VetoID * VP1DetInfo::Imp::m_vetoIDHelper = 0; +const VetoNuID * VP1DetInfo::Imp::m_vetoNuIDHelper = 0; const TriggerID * VP1DetInfo::Imp::m_triggerIDHelper = 0; const PreshowerID * VP1DetInfo::Imp::m_preshowerIDHelper = 0; @@ -144,6 +150,7 @@ const T * VP1DetInfo::Imp::cachedRetrieve(const T*& cachedPtr, const char* prefe const NeutrinoDD::EmulsionDetectorManager * VP1DetInfo::emulsionDetMgr() { return Imp::cachedRetrieve(Imp::m_emulsionDetMgr,"Emulsion",VP1JobConfigInfo::hasEmulsionGeometry()); } const ScintDD::VetoDetectorManager * VP1DetInfo::vetoDetMgr() { return Imp::cachedRetrieve(Imp::m_vetoDetMgr,"Veto",VP1JobConfigInfo::hasVetoGeometry()); } +const ScintDD::VetoNuDetectorManager * VP1DetInfo::vetoNuDetMgr() { return Imp::cachedRetrieve(Imp::m_vetoNuDetMgr,"VetoNu",VP1JobConfigInfo::hasVetoNuGeometry()); } const ScintDD::TriggerDetectorManager * VP1DetInfo::triggerDetMgr() { return Imp::cachedRetrieve(Imp::m_triggerDetMgr,"Trigger",VP1JobConfigInfo::hasTriggerGeometry()); } const ScintDD::PreshowerDetectorManager * VP1DetInfo::preshowerDetMgr() { return Imp::cachedRetrieve(Imp::m_preshowerDetMgr,"Preshower",VP1JobConfigInfo::hasPreshowerGeometry()); } @@ -156,6 +163,7 @@ const FaserDetectorID * VP1DetInfo::faserIDHelper() { return Imp::cachedRetrieve const EmulsionID * VP1DetInfo::emulsionIDHelper() { return Imp::cachedRetrieve(Imp::m_emulsionIDHelper,"EmulsionID",VP1JobConfigInfo::hasEmulsionGeometry()); } const VetoID * VP1DetInfo::vetoIDHelper() { return Imp::cachedRetrieve(Imp::m_vetoIDHelper,"VetoID",VP1JobConfigInfo::hasVetoGeometry()); } +const VetoNuID * VP1DetInfo::vetoNuIDHelper() { return Imp::cachedRetrieve(Imp::m_vetoNuIDHelper,"VetoNuID",VP1JobConfigInfo::hasVetoNuGeometry()); } const TriggerID * VP1DetInfo::triggerIDHelper() { return Imp::cachedRetrieve(Imp::m_triggerIDHelper,"TriggerID",VP1JobConfigInfo::hasTriggerGeometry()); } const PreshowerID * VP1DetInfo::preshowerIDHelper() { return Imp::cachedRetrieve(Imp::m_preshowerIDHelper,"PreshowerID",VP1JobConfigInfo::hasPreshowerGeometry()); } @@ -179,6 +187,8 @@ bool VP1DetInfo::isUnsafe( const Identifier& id ) { if (idhelper->is_scint(id)) { if (!VP1JobConfigInfo::hasVetoGeometry() && idhelper->is_veto(id)) return true; + if (!VP1JobConfigInfo::hasVetoNuGeometry() && idhelper->is_vetonu(id)) + return true; if (!VP1JobConfigInfo::hasTriggerGeometry() && idhelper->is_trigger(id)) return true; if (!VP1JobConfigInfo::hasPreshowerGeometry() && idhelper->is_preshower(id)) diff --git a/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx b/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx index 03a305c6851e984faa31a33eec57e41f11297177..bd325e0d306fb4c93cdc23b82683cf6ac5244e7a 100644 --- a/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx +++ b/graphics/VTI12/VTI12Utils/src/VP1JobConfigInfo.cxx @@ -37,6 +37,7 @@ public: static bool hasGeoModelExperiment; static bool hasEmulsionGeometry; static bool hasVetoGeometry; + static bool hasVetoNuGeometry; static bool hasTriggerGeometry; static bool hasPreshowerGeometry; static bool hasSCTGeometry; @@ -52,6 +53,7 @@ bool VP1JobConfigInfo::Imp::initialised = false; bool VP1JobConfigInfo::Imp::hasGeoModelExperiment = false; bool VP1JobConfigInfo::Imp::hasEmulsionGeometry = false; bool VP1JobConfigInfo::Imp::hasVetoGeometry = false; +bool VP1JobConfigInfo::Imp::hasVetoNuGeometry = false; bool VP1JobConfigInfo::Imp::hasTriggerGeometry = false; bool VP1JobConfigInfo::Imp::hasPreshowerGeometry = false; bool VP1JobConfigInfo::Imp::hasSCTGeometry = false; @@ -64,6 +66,7 @@ void VP1JobConfigInfo::Imp::turnOffAll() hasGeoModelExperiment = false; hasEmulsionGeometry = false; hasVetoGeometry = false; + hasVetoNuGeometry = false; hasTriggerGeometry = false; hasPreshowerGeometry = false; hasSCTGeometry = false; @@ -89,12 +92,15 @@ void VP1JobConfigInfo::Imp::ensureInit() VP1Msg::messageVerbose("VTI12JobConfigInfo => hasGeoModelExperiment = "+QString(hasGeoModelExperiment?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasEmulsionGeometry = "+QString(hasEmulsionGeometry?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasVetoGeometry = "+QString(hasVetoGeometry?"On":"Off")); + VP1Msg::messageVerbose("VTI12JobConfigInfo => hasVetoNuGeometry = "+QString(hasVetoNuGeometry?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasTriggerGeometry = "+QString(hasTriggerGeometry?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasPreshowerGeometry = "+QString(hasPreshowerGeometry?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasSCTGeometry = "+QString(hasSCTGeometry?"On":"Off")); VP1Msg::messageVerbose("VTI12JobConfigInfo => hasEcalGeometry = "+QString(hasEcalGeometry?"On":"Off")); + VP1Msg::messageVerbose("VTI12JobConfigInfo => hasCavernInfraGeometry = "+QString(hasCavernInfraGeometry?"On":"Off")); + } } @@ -103,12 +109,14 @@ void VP1JobConfigInfo::Imp::ensureInit() bool VP1JobConfigInfo::hasGeoModelExperiment() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasGeoModelExperiment; } bool VP1JobConfigInfo::hasEmulsionGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasEmulsionGeometry; } bool VP1JobConfigInfo::hasVetoGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasVetoGeometry; } +bool VP1JobConfigInfo::hasVetoNuGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasVetoNuGeometry; } bool VP1JobConfigInfo::hasTriggerGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasTriggerGeometry; } bool VP1JobConfigInfo::hasPreshowerGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasPreshowerGeometry; } bool VP1JobConfigInfo::hasSCTGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasSCTGeometry; } bool VP1JobConfigInfo::hasEcalGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasEcalGeometry; } +bool VP1JobConfigInfo::hasCavernInfraGeometry() { if (!Imp::initialised) Imp::ensureInit(); return Imp::hasCavernInfraGeometry; } //____________________________________________________________________ bool VP1JobConfigInfo::Imp::actualInit( StoreGateSvc* detStore ) @@ -159,10 +167,12 @@ bool VP1JobConfigInfo::Imp::actualInit( StoreGateSvc* detStore ) VP1Msg::message( QString { name.c_str() } ); if ( !hasEmulsionGeometry && name=="Emulsion") hasEmulsionGeometry = true; if ( !hasVetoGeometry && name=="Veto") hasVetoGeometry = true; + if ( !hasVetoNuGeometry && name=="VetoNu") hasVetoNuGeometry = true; if ( !hasTriggerGeometry && name=="Trigger") hasTriggerGeometry = true; if ( !hasPreshowerGeometry && name=="Preshower") hasPreshowerGeometry = true; if ( !hasSCTGeometry && name=="SCT") hasSCTGeometry = true; if ( !hasEcalGeometry && name=="Ecal") hasEcalGeometry = true; + if ( !hasCavernInfraGeometry && name == "Trench") hasCavernInfraGeometry = true; //FIXME: Look for CavernInfra as well!!! diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx index df91c67cf77ef79b749934687ee910146ee3e309..59562e632c5704d53ca09eec67b0d036c6ac45b0 100644 --- a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx +++ b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx @@ -27,6 +27,8 @@ namespace xAOD { AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, bcid_time, set_bcid_time ) + AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, trigger_time, set_trigger_time ) + AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, raw_peak, set_raw_peak ) AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, raw_integral, set_raw_integral ) diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h index 9ea7b6dc573d53a533df44d02ff3edbf92c8a9ce..e3615dbedd60ab1863d1d749cd7595dc961cacb2 100644 --- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h +++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h @@ -48,12 +48,19 @@ namespace xAOD { void set_channel(unsigned int value); /// 32-bit version of channel identifier + /// From Identifier::get_identifier32()::get_compact() unsigned int id() const; void set_id(unsigned int value); + /// Interface for proper identifier Identifier identify() const { return Identifier(this->id()); } + void set_identifier(const Identifier& id) { + set_id(id.get_identifier32().get_compact()); + } + + /// All values are in units of ns and mV /// Best results float localtime() const; @@ -72,6 +79,10 @@ namespace xAOD { float bcid_time() const; void set_bcid_time(float value); + /// Time with respect to nominal trigger time (including known offsets) + float trigger_time() const; + void set_trigger_time(float value); + /// Raw values from waveform float raw_peak() const; void set_raw_peak(float value); @@ -102,7 +113,7 @@ namespace xAOD { float nval() const; void set_nval(float value); - /// Raw time and waveform data + /// Raw time and waveform data (in ns and mV) std::vector<float> time_vector() const; void set_time_vector(std::vector<float> value);