diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3cba605b33ce3adcd9ad6a604170521570005156..0aef82debb458e44c3b9bfa1dceb4d2f79548bee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,7 +25,7 @@ build_image: - mkdir build - cd build - set +e && source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh; set -e - - set +e && asetup --input=../../calypso/asetup.faser Athena,22.0.40; set -e + - set +e && asetup --input=../../calypso/asetup.faser Athena,22.0.49; set -e - cmake ../../calypso - make -j 3 artifacts: @@ -41,7 +41,7 @@ test_unittest: - yum -y install man - cd build - set +e && source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh; set -e - - set +e && asetup --input=../../calypso/asetup.faser Athena,22.0.40; set -e + - set +e && asetup --input=../../calypso/asetup.faser Athena,22.0.49; set -e - set +e && source `find . -name 'setup.sh'`; set -e - ctest -j3 dependencies: diff --git a/Calorimeter/CaloDigiAlgs/CMakeLists.txt b/Calorimeter/CaloDigiAlgs/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..89d20eae8e67a52daa6a23b60825e06f43610ec3 --- /dev/null +++ b/Calorimeter/CaloDigiAlgs/CMakeLists.txt @@ -0,0 +1,17 @@ +################################################################################ +# Package: CaloDigiAlgs +################################################################################ + +# Declare the package name: +atlas_subdir( CaloDigiAlgs ) + +# Component(s) in the package: +atlas_add_component( CaloDigiAlgs + src/*.cxx src/*.h + src/components/*.cxx + 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 new file mode 100644 index 0000000000000000000000000000000000000000..c9ae148779f540c6357b67344f0c03f61ab1cbca --- /dev/null +++ b/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py @@ -0,0 +1,66 @@ +# Copyright (C) 2020-2021 CERN for the benefit of the FASER collaboration + +from re import VERBOSE +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +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, **kwargs): + """ Return all algorithms and tools for Waveform digitization """ + acc = ComponentAccumulator() + + if not flags.Input.isMC: + return acc + + acc.merge(CaloWaveformDigiCfg(flags, "CaloWaveformDigiAlg", **kwargs)) + acc.merge(CaloWaveformDigitizationOutputCfg(flags)) + acc.merge(WaveformCableMappingCfg(flags)) + + return acc + +# Return configured digitization algorithm from SIM hits +def CaloWaveformDigiCfg(flags, name="CaloWaveformDigiAlg", **kwargs): + + acc = ComponentAccumulator() + + tool = CompFactory.WaveformDigitisationTool(name="CaloWaveformDigtisationTool") + kwargs.setdefault("WaveformDigitisationTool", tool) + + kwargs.setdefault("CaloHitContainerKey", "EcalHits") + kwargs.setdefault("WaveformContainerKey", "CaloWaveforms") + + kwargs.setdefault("CB_alpha", -0.32) + kwargs.setdefault("CB_n", 1000) + kwargs.setdefault("CB_sigma", 3.67) + kwargs.setdefault("CB_mean", 820) # Time in ns + # This number is over-ridden in the digitization script, so change it there! + kwargs.setdefault("CB_norm", 5.0) # Low gain default without filters, use x5? for high gain + + kwargs.setdefault("base_mean", 15650) + kwargs.setdefault("base_rms", 3) + + digiAlg = CompFactory.CaloWaveformDigiAlg(name, **kwargs) + print(f"CaloWaveformDigiAlg normalization: {digiAlg.CB_norm}") + print(f"CaloWaveformDigiAlg mean time: {digiAlg.CB_mean}") + + acc.addEventAlgo(digiAlg) + + return acc + +def CaloWaveformDigitizationOutputCfg(flags, **kwargs): + """ Return ComponentAccumulator with output for Waveform Digi""" + acc = ComponentAccumulator() + ItemList = [ + "RawWaveformContainer#*" + ] + acc.merge(OutputStreamCfg(flags, "RDO")) + ostream = acc.getEventAlgo("OutputStreamRDO") + # 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 new file mode 100644 index 0000000000000000000000000000000000000000..3e10288eaa2e68f82f1c72be38fde04cb73c66fd --- /dev/null +++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx @@ -0,0 +1,143 @@ +#include "CaloWaveformDigiAlg.h" + +#include "Identifier/Identifier.h" + +#include "FaserCaloSimEvent/CaloHitIdHelper.h" + +#include <map> +#include <utility> + +CaloWaveformDigiAlg::CaloWaveformDigiAlg(const std::string& name, + ISvcLocator* pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator) +{ + +} + +StatusCode +CaloWaveformDigiAlg::initialize() { + ATH_MSG_INFO(name() << "::initalize()" ); + + // Initalize tools + ATH_CHECK( m_digiTool.retrieve() ); + ATH_CHECK( m_mappingTool.retrieve() ); + + // Set key to read waveform from + ATH_CHECK( m_caloHitContainerKey.initialize() ); + + // Set key to write container + ATH_CHECK( m_waveformContainerKey.initialize() ); + + // 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->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; +} + +StatusCode +CaloWaveformDigiAlg::finalize() { + ATH_MSG_INFO(name() << "::finalize()"); + + delete m_kernel; + + return StatusCode::SUCCESS; +} + +StatusCode +CaloWaveformDigiAlg::execute(const EventContext& ctx) const { + ATH_MSG_DEBUG("Executing"); + 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); + + ATH_CHECK( caloHitHandle.isValid() ); + ATH_MSG_DEBUG("Found ReadHandle for CaloHitCollection " << m_caloHitContainerKey); + + // Find the output waveform container + SG::WriteHandle<RawWaveformContainer> waveformContainerHandle(m_waveformContainerKey, ctx); + ATH_CHECK( waveformContainerHandle.record( std::make_unique<RawWaveformContainer>()) ); + + ATH_MSG_DEBUG("WaveformsContainer '" << waveformContainerHandle.name() << "' initialized"); + + if (caloHitHandle->size() == 0) { + ATH_MSG_DEBUG("CaloHitCollection found with zero length!"); + return StatusCode::SUCCESS; + } + + // 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"); + + return StatusCode::SUCCESS; +} diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..25111bc9655ae99d97e7ea56a98524102ce151f3 --- /dev/null +++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h @@ -0,0 +1,112 @@ +#ifndef CALODIGIALGS_CALOWAVEFORMDIGIALG_H +#define CALODIGIALGS_CALOWAVEFORMDIGIALG_H + +// Base class +#include "AthenaBaseComps/AthReentrantAlgorithm.h" + +// Data classes +#include "WaveRawEvent/RawWaveformContainer.h" +#include "FaserCaloSimEvent/CaloHitCollection.h" + +// Tool classes +#include "WaveDigiTools/IWaveformDigitisationTool.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" + +// Handles +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/WriteHandleKey.h" + +// Gaudi +#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 { + + public: + // Constructor + CaloWaveformDigiAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CaloWaveformDigiAlg() = default; + + /** @name Usual algorithm methods */ + //@{ + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + //@} + + private: + + /** @name Disallow default instantiation, copy, assignment */ + //@{ + CaloWaveformDigiAlg() = delete; + CaloWaveformDigiAlg(const CaloWaveformDigiAlg&) = delete; + 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"}; + Gaudi::Property<double> m_CB_sigma {this, "CB_sigma", 0, "Sigma of the crystal ball function"}; + Gaudi::Property<double> m_CB_norm {this, "CB_norm", 0, "Norm of the crystal ball function"}; + + 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 and evaluated values **/ + //@{ + TF1* m_kernel; + std::vector<float> m_timekernel; + //@} + + /// Detector ID helper + const EcalID* m_ecalID{nullptr}; + + /** + * @name Digitisation tool + */ + ToolHandle<IWaveformDigitisationTool> m_digiTool + {this, "WaveformDigitisationTool", "WaveformDigitisationTool"}; + + /** + * @name Mapping tool + */ + ToolHandle<IWaveformCableMappingTool> m_mappingTool + {this, "WaveformCableMappingTool", "WaveformCableMappingTool"}; + + /** + * @name Input HITS using SG::ReadHandleKey + */ + //@{ + + SG::ReadHandleKey<CaloHitCollection> m_caloHitContainerKey + {this, "CaloHitContainerKey", ""}; + + //@} + + + /** + * @name Output data using SG::WriteHandleKey + */ + //@{ + SG::WriteHandleKey<RawWaveformContainer> m_waveformContainerKey + {this, "WaveformContainerKey", ""}; + //@} + +}; + + + +#endif // CALODIGIALGS_CALODIGIALG_H diff --git a/Calorimeter/CaloDigiAlgs/src/components/CaloDigiAlgs_entries.cxx b/Calorimeter/CaloDigiAlgs/src/components/CaloDigiAlgs_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..832cfbb096ffdb13430ba92dc2bfc7b1125bd53c --- /dev/null +++ b/Calorimeter/CaloDigiAlgs/src/components/CaloDigiAlgs_entries.cxx @@ -0,0 +1,2 @@ +#include "../CaloWaveformDigiAlg.h" +DECLARE_COMPONENT( CaloWaveformDigiAlg ) diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx index 2ac860d86c8f3c42b3c5f1382f36e905bc17371c..6abec9240110bcc60b27a2afec12a9a7029fa242 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx @@ -18,12 +18,16 @@ CaloHitCollection_PERS* CaloHitCollectionCnv::createPersistent(CaloHitCollection CaloHitCollection* CaloHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "CaloHitCollectionConverter" ); CaloHitCollectionCnv_p1 converter_p1; + CaloHitCollectionCnv_p1a converter_p1a; static const pool::Guid p1_guid("134E8045-AB99-43EF-9AD1-324C48830B64"); - // static const pool::Guid p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779"); + static const pool::Guid p1a_guid("02C108EE-0AD9-4444-83BD-D5273FCDEF6F"); CaloHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { + if( this->compareClassGuid(p1a_guid)) { + std::unique_ptr< CaloHitCollection_p1a > col_vect( this->poolReadObject< CaloHitCollection_p1a >() ); + trans_cont = converter_p1a.createTransient( col_vect.get(), mlog ); + } else if( this->compareClassGuid(p1_guid)) { std::unique_ptr< CaloHitCollection_p1 > col_vect( this->poolReadObject< CaloHitCollection_p1 >() ); trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); } else { diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h index b46894c5ffe1f96fe91451b9206269b2f8e44b53..1de7cc3e08b9d75f340646ee1c4007e78211a6bb 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h @@ -8,12 +8,14 @@ #include "FaserCaloSimEvent/CaloHitCollection.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef CaloHitCollection_p1 CaloHitCollection_PERS; -typedef CaloHitCollectionCnv_p1 CaloHitCollectionCnv_PERS; +typedef CaloHitCollection_p1a CaloHitCollection_PERS; +typedef CaloHitCollectionCnv_p1a CaloHitCollectionCnv_PERS; class CaloHitCollectionCnv : public T_AthenaPoolCustomCnv<CaloHitCollection, CaloHitCollection_PERS > { friend class CnvFactory<CaloHitCollectionCnv>; diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/CMakeLists.txt b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/CMakeLists.txt index dbbd1a372aa26fde66a58aee80ce3bf30f758812..ef770c2b59d440fe41bc1c63893f49ecd0d49439 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/CMakeLists.txt +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/CMakeLists.txt @@ -22,5 +22,5 @@ atlas_add_dictionary( FaserCaloSimEventTPCnvDict FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h FaserCaloSimEventTPCnv/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv FaserCaloSimEvent TestTools StoreGateLib SGtests Identifier FaserCaloSimEventTPCnv ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv FaserCaloSimEvent TestTools StoreGateLib SGtests Identifier FaserCaloSimEventTPCnv AthenaKernel) diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..80534aae7aaff3b32ca4bb1aff9105296859e05a --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CALOHITCOLLECTIONCNV_P1A_H +#define CALOHITCOLLECTIONCNV_P1A_H + +// CaloHitCollectionCnv_p1, T/P separation of Calo Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "FaserCaloSimEvent/CaloHitCollection.h" +#include "CaloHitCollection_p1a.h" + + +class CaloHitCollectionCnv_p1a : public T_AthenaPoolTPCnvBase<CaloHitCollection, CaloHitCollection_p1a> +{ + public: + + CaloHitCollectionCnv_p1a() {}; + + virtual CaloHitCollection* createTransient(const CaloHitCollection_p1a* persObj, MsgStream &log); + + virtual void persToTrans(const CaloHitCollection_p1a* persCont, + CaloHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const CaloHitCollection* transCont, + CaloHitCollection_p1a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..7dc511d9d281c6223c6a6209f0b6778ddb399703 --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CALOHITCOLLECTION_P1A_H +#define CALOHITCOLLECTION_P1A_H + +/* + +Authors: Davide Costanzo Rob Duxfield +Modified for FASER by D. Casper - change internal unsigned short counters to unsigned long +p2, p3, etc reserved for possible future ATLAS changes + +*/ + +#include <vector> +#include <string> + +class CaloHitCollection_p1a +{ + public: +/// Default constructor + CaloHitCollection_p1a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned long> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +CaloHitCollection_p1a::CaloHitCollection_p1a () {} + +#endif diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h index 80937ffc825a51c8dc4611a559507fcd0e7e30b5..de24c20ac134a200e6de30114da8ea2d2ed56210 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h @@ -15,6 +15,8 @@ #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCnv_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHit_p1.h" #endif // CALOEVENTTPCNV_CALOSIMEVENTTPCNVDICT_H diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml index d73b5ce1a258bce7766b3278358530e5a99b4fbc..e90551988f46845a79383bb3ec830265715ea73e 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml @@ -4,4 +4,6 @@ <class name="CaloHit_p1" /> <class name="std::vector<CaloHit_p1>" /> <class name="CaloHitCollection_p1" id="134E8045-AB99-43EF-9AD1-324C48830B64" /> + <class name="CaloHitCollection_p1a" id="02C108EE-0AD9-4444-83BD-D5273FCDEF6F" /> + </lcgdict> diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1.cxx b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1.cxx index c54f8765abfcbeda9b8c72b67717608c9c8b21ef..0568ff080b1e634023284128efdd7909dbc85af2 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1.cxx +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1.cxx @@ -14,7 +14,10 @@ #include "CLHEP/Geometry/Point3D.h" // Gaudi #include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + // Athena +#include "AthenaKernel/ExtendedEventContext.h" #include "StoreGate/StoreGateSvc.h" // * * * stolen from eflowRec * * * // @@ -60,7 +63,7 @@ const double CaloHitCollectionCnv_p1::m_2bHalfMaximum = pow(2.0, 15.0); const int CaloHitCollectionCnv_p1::m_2bMaximum = (unsigned short)(-1); -void CaloHitCollectionCnv_p1::transToPers(const CaloHitCollection* transCont, CaloHitCollection_p1* persCont, MsgStream &/*log*/) +void CaloHitCollectionCnv_p1::transToPers(const CaloHitCollection* transCont, CaloHitCollection_p1* persCont, MsgStream &log) { // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and // persistifies the end point of each hit plus the start point of the first hit in each string. @@ -77,6 +80,8 @@ void CaloHitCollectionCnv_p1::transToPers(const CaloHitCollection* transCont, Ca static const double dRcut = 1.0e-7; static const double dTcut = 1.0; + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); const HepMcParticleLink * lastLink=nullptr; int lastId = -1; double stringFirstTheta = 0.0; @@ -98,11 +103,23 @@ void CaloHitCollectionCnv_p1::transToPers(const CaloHitCollection* transCont, Ca if ( !lastLink || (siHit->particleLink() != *lastLink) ) { - // store barcode once for set of consecutive hits with same barcode + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode lastLink = &(siHit->particleLink()); persCont->m_barcode.push_back(lastLink->barcode()); - persCont->m_mcEvtIndex.push_back(lastLink->eventIndex()); + log << MSG::ALWAYS << "TP: Event collection from link: " << lastLink->getEventCollection() << " ; char value: " << lastLink->getEventCollectionAsChar() << " barcode: " << lastLink->barcode() << endmsg; + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); if (idx > 0) { @@ -238,18 +255,29 @@ void CaloHitCollectionCnv_p1::transToPers(const CaloHitCollection* transCont, Ca persCont->m_nBC.push_back(idx - endBC); persCont->m_nId.push_back(idx - endId); persCont->m_nHits.push_back(idx - endHit); + + log << MSG::ALWAYS << "nBC: " << persCont->m_nBC << endmsg; + log << MSG::ALWAYS << "nId: " << persCont->m_nId << endmsg; + log << MSG::ALWAYS << "nHits:" << persCont->m_nHits << endmsg; } CaloHitCollection* CaloHitCollectionCnv_p1::createTransient(const CaloHitCollection_p1* persObj, MsgStream &log) { + for (size_t i = 0; i < persObj->m_evtColl.size(); i++) + { + if (persObj->m_evtColl[i] != 'a') + log << MSG::ALWAYS << "Corrupted in createTransient: " << persObj->m_evtColl[i] << endmsg; + } std::unique_ptr<CaloHitCollection> trans(std::make_unique<CaloHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); persToTrans(persObj, trans.get(), log); return(trans.release()); } -void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, CaloHitCollection* transCont, MsgStream &/*log*/) +void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, CaloHitCollection* transCont, MsgStream &log) { + const EventContext& ctx = Gaudi::Hive::currentContext(); + unsigned int hitCount = 0; unsigned int angleCount = 0; unsigned int idxBC = 0; @@ -260,12 +288,15 @@ void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, unsigned int endBC = 0; unsigned int endId = 0; + log << MSG::ALWAYS << "nHits.size(): " << persCont->m_nHits.size() << " nBC.size(): " << persCont->m_nBC.size() << endmsg; + log << MSG::ALWAYS << " nBC: " << persCont->m_nBC << endmsg; + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { if (persCont->m_nHits[i]) { - const unsigned int start = endHit; endHit += persCont->m_nHits[i]; + log << MSG::ALWAYS << "i: " << i << " persCont->m_nHits[i]: " << persCont->m_nHits[i] << " start: " << start << " endHit: " << endHit << endmsg; const double t0 = persCont->m_hit1_meanTime[i]; const double theta0 = persCont->m_hit1_theta[i]; @@ -273,7 +304,6 @@ void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); for (unsigned int j = start; j < endHit; j++) { - if (j >= endBC + persCont->m_nBC[idxBC]) endBC += persCont->m_nBC[idxBC++]; @@ -299,7 +329,13 @@ void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, HepGeom::Point3D<double> endThis( endLast + r ); - HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), HepMcParticleLink::IS_INDEX ); + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + log << MSG::ALWAYS << "PT: Event collection from persCont: " << persCont->m_evtColl[idxBC] << " ; idxBC: " << idxBC << " evtColl.size(): " << persCont->m_evtColl.size() << " evtIndex.size(): " << persCont->m_mcEvtIndex.size() << endmsg; + + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); endLast = endThis; @@ -309,4 +345,5 @@ void CaloHitCollectionCnv_p1::persToTrans(const CaloHitCollection_p1* persCont, } } } + log << MSG::ALWAYS << "hitCount: " << hitCount << endmsg; } diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d1d6ec53b9250c1b184c5b78f5af4b85711409bd --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx @@ -0,0 +1,339 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "FaserCaloSimEvent/CaloHit.h" +#include "FaserCaloSimEvent/CaloHitCollection.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "AthenaKernel/ExtendedEventContext.h" +#include "StoreGate/StoreGateSvc.h" + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double CaloHitCollectionCnv_p1a::m_persEneUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_persLenUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_persAngUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_2bHalfMaximum = pow(2.0, 15.0); +const int CaloHitCollectionCnv_p1a::m_2bMaximum = (unsigned short)(-1); + + +void CaloHitCollectionCnv_p1a::transToPers(const CaloHitCollection* transCont, CaloHitCollection_p1a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (CaloHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + CaloHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store id once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); +} + + +CaloHitCollection* CaloHitCollectionCnv_p1a::createTransient(const CaloHitCollection_p1a* persObj, MsgStream &log) { + for (size_t i = 0; i < persObj->m_evtColl.size(); i++) + { + if (persObj->m_evtColl[i] != 'a') + log << MSG::ALWAYS << "Corrupted in createTransient: " << persObj->m_evtColl[i] << endmsg; + } + std::unique_ptr<CaloHitCollection> trans(std::make_unique<CaloHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void CaloHitCollectionCnv_p1a::persToTrans(const CaloHitCollection_p1a* persCont, CaloHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + + if (persCont->m_nHits[i]) { + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } +} diff --git a/Calorimeter/CaloG4/EcalG4_SD/python/EcalG4_SDToolConfig.py b/Calorimeter/CaloG4/EcalG4_SD/python/EcalG4_SDToolConfig.py index e679d7fca9c93e9341a87c61685f6bd2d9d00b6c..293f2057dd710cc2edb3f5cd29d049f619a127df 100644 --- a/Calorimeter/CaloG4/EcalG4_SD/python/EcalG4_SDToolConfig.py +++ b/Calorimeter/CaloG4/EcalG4_SD/python/EcalG4_SDToolConfig.py @@ -17,5 +17,7 @@ def EcalSensorSDCfg(ConfigFlags, name="EcalSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["Ecal::_dd_Geometry_DownstreamRegion_Ecal_Modules_OutCell"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, EcalSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.EcalSensorSDTool(name, **kwargs)) + return result + 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/BarcodeChecker/CMakeLists.txt b/Control/CalypsoExample/BarcodeChecker/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f1e720b867398acbdbdcba483abcf61ed84fefc --- /dev/null +++ b/Control/CalypsoExample/BarcodeChecker/CMakeLists.txt @@ -0,0 +1,11 @@ +################################################################################ +# Package: BarcodeChecker +################################################################################ + +# Declare the package name: +atlas_subdir( BarcodeChecker ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +atlas_install_joboptions( share/*.py ) \ No newline at end of file diff --git a/Control/CalypsoExample/BarcodeChecker/python/BarcodeCheckerAlg.py b/Control/CalypsoExample/BarcodeChecker/python/BarcodeCheckerAlg.py new file mode 100644 index 0000000000000000000000000000000000000000..0e29c7d2e60b880f22cf383e766ee9ce338f27d3 --- /dev/null +++ b/Control/CalypsoExample/BarcodeChecker/python/BarcodeCheckerAlg.py @@ -0,0 +1,39 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +import AthenaPython.PyAthena as PyAthena +from AthenaPython.PyAthena import StatusCode, McEventCollection, HepMC, CLHEP +import McParticleEvent.Pythonizations + +__author__ = "Dave Casper <dcasper@uci.edu>" + +class BarcodeCheckerAlg(PyAthena.Alg): + def __init__(self, name="BarcodeChecker", MCEventKey="TruthEvent"): + super(BarcodeCheckerAlg,self).__init__(name=name) + self.MCEventKey = MCEventKey + return + + def initialize(self): + self.maxLow = 0 + self.maxMid = 0 + self.maxHi = 0 + return StatusCode.Success + + + def execute(self): + evtCollection = self.evtStore[self.MCEventKey] + for mcEvt in evtCollection: + for mcParticle in mcEvt.particles: + barCode = mcParticle.barcode() + if barCode%1000000 <= 200000: + self.maxLow = max(self.maxLow, barCode%1000000) + if barCode%1000000 > 200000: + self.maxMid = max(self.maxMid, barCode%1000000 - 200000) + self.maxHi = max(self.maxHi, barCode//1000000) + return StatusCode.Success + + def finalize(self): + print("Low part: ", self.maxLow, " out of 200000 (",100*self.maxLow/200000,"% of overflow )") + print("Mid part: ", self.maxMid, " out of ", 1000000 - 200000, " (",100*self.maxMid/(1000000-200000),"% of overflow )") + print("Hi part: ", self.maxHi, " out of ", (1<<31)//1000000, " (", 100*self.maxHi/((1<<31)//1000000),"% of overflow )") + + return StatusCode.Success \ No newline at end of file diff --git a/Control/CalypsoExample/BarcodeChecker/python/__init__.py b/Control/CalypsoExample/BarcodeChecker/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d13ae164caa4e93bf2899cea4e67d0ec515784a2 --- /dev/null +++ b/Control/CalypsoExample/BarcodeChecker/python/__init__.py @@ -0,0 +1 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration diff --git a/Control/CalypsoExample/BarcodeChecker/share/BarcodeChecker_jobOptions.py b/Control/CalypsoExample/BarcodeChecker/share/BarcodeChecker_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..1e739beb0c3865e924721b21fe5683b9f18fdaec --- /dev/null +++ b/Control/CalypsoExample/BarcodeChecker/share/BarcodeChecker_jobOptions.py @@ -0,0 +1,29 @@ +# +# Usage: athena.py -c'INPUT=["faser.1.gfaser.root","faser.2.gfaser.root"]' BarcodeChecker/BarcodeChecker_jobOptions.py >& BarcodeChecker.log +# +# INPUT is mandatory (INPUT can be a list, as shown above) +# + +if not 'INPUT' in dir(): + print("Missing INPUT parameter") + exit() + +if not isinstance(INPUT, (list,tuple)): + INPUT = [INPUT] + pass + +from AthenaCommon.GlobalFlags import globalflags + +globalflags.InputFormat.set_Value_and_Lock('pool') + +import AthenaPoolCnvSvc.ReadAthenaPool + +svcMgr.EventSelector.InputCollections = INPUT + +from BarcodeChecker.BarcodeCheckerAlg import BarcodeCheckerAlg + +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() +job += BarcodeCheckerAlg() + +theApp.EvtMax = -1 diff --git a/Control/CalypsoExample/Digitization/CMakeLists.txt b/Control/CalypsoExample/Digitization/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8caebb598f6cea848edafea449a0bd19e657c6d --- /dev/null +++ b/Control/CalypsoExample/Digitization/CMakeLists.txt @@ -0,0 +1,26 @@ +################################################################################ +# Package: Digitization +################################################################################ + +# Declare the package name: +atlas_subdir( Digitization ) + +# Component(s) in the package: +#atlas_add_component( GeoModelTest +# src/GeoModelTestAlg.cxx +# src/components/GeoModelTest_entries.cxx +# INCLUDE_DIRS ${GEOMODEL_INCLUDE_DIRS} +# LINK_LIBRARIES ${GEOMODEL_LIBRARIES} AthenaBaseComps GeoModelFaserUtilities ScintReadoutGeometry TrackerReadoutGeometry MagFieldInterfaces MagFieldElements MagFieldConditions ) + +# Install files from the package: +#atlas_install_joboptions( share/*.py ) +#atlas_install_python_modules( python/*.py ) +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 ) +#atlas_add_test( ProdRecoTestBeam +# SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-003613-filtered.raw TestBeamData +# PROPERTIES TIMEOUT 300 ) + diff --git a/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py new file mode 100755 index 0000000000000000000000000000000000000000..1154edd8aad0cd4ac8daadf5559e05ef1cc362b9 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi.py @@ -0,0 +1,161 @@ +#!/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("--highCaloGain", action='store_true', + help="Use high gain settings for calo PMTs") +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 +if args.highCaloGain: + calo_norm = 25. +else: + calo_norm = 5. +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, CB_norm=calo_norm)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + ConfigFlags.dump() + +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..a421cead6c379b8dd56fc2d80ea86bb9ca8ab342 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faserMDC_digi_merge.py @@ -0,0 +1,223 @@ +#!/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("--highCaloGain", action='store_true', + help="Use high gain settings for calo PMTs") +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 +if args.highCaloGain: + calo_norm = 25. +else: + calo_norm = 5. +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, CB_norm=calo_norm)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + ConfigFlags.dump() + +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 new file mode 100755 index 0000000000000000000000000000000000000000..72f890a3bd3b7f352f60c66207de15aaa2ec4961 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faser_digi.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Run with: +# ./faser_digi.py filepath +# +# 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" +# +# Options: +# --geom=runtype - flag to specify the data type (TI12OldMC or TI12MC or TestBeamMC). +# default to TI12MC +# +import sys +import time +import argparse + +a = time.time() + +parser = argparse.ArgumentParser(description="Run FASER digitization") + +parser.add_argument("file_path", + help="Fully qualified path of the raw input file") +parser.add_argument("-g", "--geom", default="TI12MC", + help="Specify geometry (default: TI12MC, alt: TestBeamMC)") +parser.add_argument("-t", "--tag", default="", + help="Specify digi tag (to append to output filename)") +parser.add_argument("--highCaloGain", action='store_true', + help="Use high gain settings for calo PMTs") +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 +runtype= args.geom + +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 geometry type found:", runtype) + print("Specify correct geometry 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 +if args.highCaloGain: + calo_norm = 25. +else: + calo_norm = 5. +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, CB_norm=calo_norm)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + ConfigFlags.dump() + +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_merge.py b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py new file mode 100755 index 0000000000000000000000000000000000000000..ea135db8346438f9a392959d7791744997353a1e --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Run with: +# ./faser_digi_merge.py dirpath +# +# filepath - fully qualified path, to the directory with input HITS file +# example: "/eos/experiment/faser/sim/tb21/particle_gun/000100/rdo/test" +# +# Options: +# --geom=runtype - flag to specify the data type (TI12OldMC or TI12MC or TestBeamMC). +# default to TI12MC +# +import sys +import time +import argparse + +a = time.time() + +parser = argparse.ArgumentParser(description="Run FASER digitization") + +parser.add_argument("dir_path", + help="Fully qualified path of the input file directory") +parser.add_argument("-p", "--partial", action="store_true", + help="Allow partial merge (default: all specified files required)") +parser.add_argument("-g", "--geom", default="TI12MC", + help="Specify geometry (default: TI12MC, alt: TestBeamMC)") +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("--highCaloGain", action='store_true', + help="Use high gain settings for calo PMTs") +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 +runtype=args.geom + +# 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) + +print("HITS files available:") +[print(file) for file in dirlist] + +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") + if args.partial: + break + else: + sys.exit(1) # Abort this job + + # Check if segment number exists in hits file (this is not perfect) + segstr = f"{seg:05d}" + if segstr not in dirlist[seg].name: + print(f"Segment {segstr} not in file {dirlist[seg].name}!") + if not args.partial: sys.exit(1) # abort + else: + print(f"Segment {segstr} found in file {dirlist[seg]}") + + 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 +if args.dir_path[:22] == '/eos/experiment/faser/': + ConfigFlags.Input.Files = [f"root://eospublic.cern.ch/{str(file)}" for file in filelist] +else: + 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 +if args.highCaloGain: + calo_norm = 25. +else: + calo_norm = 5. +acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, CB_norm=calo_norm)) + +from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg +acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + +# Configure verbosity +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + ConfigFlags.dump() + +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/submit_faserMDC_digi.sh b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh new file mode 100755 index 0000000000000000000000000000000000000000..b6b0c80c42a44e1d3731bd92e2fa800aa8036316 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi.sh @@ -0,0 +1,207 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_digi.sh [--highGain] filepath [release_directory] [working_directory] +# +# Options: +# --highGain - apply high gain settings to the Calorimeter PMTs (for muons) +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 sim/s???? or digi/d???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +while [ -n "$1" ] +do + case "$1" in + --highGain) + echo "Applying high gain settings" + highgain=1 + shift;; # This 'eats' the argument + + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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 [--highGain] 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 +logfile="${file_stem}.rdo.log" +exec >& "${output_directory}/${logfile}" +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 "$highgain" ]]; then + gainstr="" +else + gainstr="--highCaloGain" +fi +# +if [[ -z "$tag" ]]; then + faserMDC_digi.py $gainstr "$file_path" +else + faserMDC_digi.py $gainstr "--tag=$tag" "$file_path" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-RDO.root to $outdest" + mkdir -p $outdest + eos cp *-RDO.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi 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..ca2e27fcc6956e1ff180dacc41cf1f9ee2e304bf --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faserMDC_digi_merge.sh @@ -0,0 +1,230 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_digi_merge.sh [--highGain] dirpath slice nfiles [release_directory] [working_directory] +# +# Options: +# --highGain - apply high gain settings to the Calorimeter PMTs (for muons) +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 +while [ -n "$1" ] +do + case "$1" in + --highGain) + echo "Applying high gain settings" + highgain=1 + shift;; # This 'eats' the argument + + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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 +logfile="${file_stem}.rdo.log" +exec >& "$output_directory/$logfile" +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 "$highgain" ]]; then + gainstr="" +else + gainstr="--highCaloGain" +fi +# +if [[ -z "$tag" ]]; then + faserMDC_digi_merge.py $gainstr --slice $slice --files $nfiles $dir_path +else + faserMDC_digi_merge.py $gainstr --slice $slice --files $nfiles --tag $tag $dir_path +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-RDO.root to $outdest" + mkdir -p $outdest + eos cp *-RDO.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh new file mode 100644 index 0000000000000000000000000000000000000000..76abf8172614a17a1f3290f45896f1c6978b5439 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh @@ -0,0 +1,223 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faser_digi.sh [--highGain] filepath [release_directory] [working_directory] +# +# Options: +# --highGain - apply high gain settings to the Calorimeter PMTs (for muons) +# --geom - geometry setting +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 sim/s???? or digi/d???? it will be passed to the job +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +while [ -n "$1" ] +do + case "$1" in + --highGain) + echo "Applying high gain settings" + highgain=1 + shift;; # This 'eats' the argument + + -g | --geom) + geom="$2"; + shift; + shift;; + + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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_faser_digi.sh [--highGain] 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 +logfile="${file_stem}.rdo.log" +exec >& "${output_directory}/${logfile}" +echo `date` - $HOSTNAME +echo "File: $file_name" +echo "Geom: $geom" +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 run/setup.sh +#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 "$highgain" ]]; then + gainstr="" +else + gainstr="--highCaloGain" +fi +# +if [[ -z "$geom" ]]; then + geomstr="" +else + geomstr="--geom $geom" +fi +# +if [[ -z "$tag" ]]; then + tagstr="" +else + tagstr="--tag=$tag" +fi +# +faser_digi.py $geomstr $gainstr $tagstr "$file_path" +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-RDO.root to $outdest" + mkdir -p $outdest + eos cp *-RDO.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh new file mode 100755 index 0000000000000000000000000000000000000000..fd2fe20e2d5f3b5829a6f57dbb83d9a6480ab6b6 --- /dev/null +++ b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh @@ -0,0 +1,245 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faser_digi_merge.sh [--highGain] dirpath slice nfiles [release_directory] [working_directory] +# +# Options: +# --highGain - apply high gain settings to the Calorimeter PMTs (for muons) +# --geom - geometry setting +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 +# +# Job options strings +gainstr="" +partialstr="" +geomstr="" +# +# Parse command-line options +while [ -n "$1" ] +do + case "$1" in + --highGain) + echo "Applying high gain settings" + gainstr="--highCaloGain" + shift;; # This 'eats' the argument + + --partial) + echo "Allowing partial merge" + partialstr="--partial" + shift;; + + -g | --geom) + geomstr="--geom $2"; + shift; + shift;; + + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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_faser_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_faser_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_faser_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 +logfile="${file_stem}.rdo.log" +exec >& "$output_directory/$logfile" +echo `date` - $HOSTNAME +echo "Directory: $dir_path" +echo "Geom: $geom" +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 +source run/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 +# +if [[ -z "$tag" ]]; then + tagstr="" +else + tagstr="-- $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 +# +faser_digi_merge.py $partialstr $geomstr $gainstr $tagstr --slice $slice --files $nfiles $dir_path +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-RDO.root to $outdest" + mkdir -p $outdest + eos cp *-RDO.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi 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_100GeV-101104.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_100GeV-101104.json new file mode 100644 index 0000000000000000000000000000000000000000..fafd471d70b1be4b812ac23023904b353d75ca7e --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_100GeV-101104.json @@ -0,0 +1,14 @@ +{ + "file_length": 1000, + "mass": 0.511, + "maxE": 100.0, + "minE": 100.0, + "pid": [-11, 11], + "radius": -20.0, + "angle": 0.001, + "run": 101104, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_elec_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_200GeV-101106.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_200GeV-101106.json new file mode 100644 index 0000000000000000000000000000000000000000..bac122293c2a2c17ebf9c37792b7a83d820ca9d3 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_200GeV-101106.json @@ -0,0 +1,13 @@ +{ + "file_length": 1000, + "mass": 0.511, + "maxE": 200.0, + "minE": 200.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 101106, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_elec_200GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_50GeV-101105.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_50GeV-101105.json new file mode 100644 index 0000000000000000000000000000000000000000..794c51fcd643a5dfd5f6d5dddd0f444911f343e3 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_elec_50GeV-101105.json @@ -0,0 +1,13 @@ +{ + "file_length": 1000, + "mass": 0.511, + "maxE": 50.0, + "minE": 50.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 101105, + "sampler": "const", + "segment": 0, + "short": "MDC_PG_elec_50GeV", + "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_100GeV-101304.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_100GeV-101304.json new file mode 100644 index 0000000000000000000000000000000000000000..8d1a59c3bacd38ad31f967689383447a008c97c9 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_100GeV-101304.json @@ -0,0 +1,14 @@ +{ + "file_length": 2000, + "mass": 105.66, + "maxE": 100.0, + "minE": 100.0, + "pid": [-13, 13], + "radius": -20.0, + "angle": 0.001, + "run": 101304, + "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_higain_logE-101305.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_higain_logE-101305.json new file mode 100644 index 0000000000000000000000000000000000000000..6ebccb3062205aa73c48b2953d36e2decf307ef4 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_higain_logE-101305.json @@ -0,0 +1,13 @@ +{ + "file_length": 2000, + "mass": 105.66, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-13, 13], + "radius": -100.0, + "run": 101305, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_muon_fasernu_higain_logE", + "zpos": -3990.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..1c3d9b606c4ffc0d31974c7d0592cf2bf1d68801 --- /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": -3990.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101306.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101306.json new file mode 100644 index 0000000000000000000000000000000000000000..d6b9e7b58fe233b6f8099bb8ad15f979ecbcd027 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101306.json @@ -0,0 +1,14 @@ +{ + "file_length": 5000, + "mass": 105.66, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-13, 13], + "radius": -2.5, + "angle": 0.0006, + "run": 101306, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_muon_fasernu_logE", + "zpos": -3990.0 +} diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101307.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101307.json new file mode 100644 index 0000000000000000000000000000000000000000..3e57b2d300eac4ae2caa74cdccd746b2f24c997a --- /dev/null +++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_muon_fasernu_logE-101307.json @@ -0,0 +1,14 @@ +{ + "file_length": 5000, + "mass": 105.66, + "maxE": 5000.0, + "minE": 10.0, + "pid": [-13, 13], + "radius": -25.0, + "angle": 0.0006, + "run": 101307, + "sampler": "log", + "segment": 0, + "short": "MDC_PG_muon_fasernu_logE", + "zpos": -3990.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/data/tb21/FaserMC-TB_PG_elec_100GeV-000200.json b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_100GeV-000200.json new file mode 100644 index 0000000000000000000000000000000000000000..5296e25aa0b1e77b34d6a5c870aa0b342c446331 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_100GeV-000200.json @@ -0,0 +1,14 @@ +{ + "file_length": 1000, + "geom": "TestBeamMC", + "mass": 0.511, + "maxE": 100.0, + "minE": 100.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 200, + "sampler": "const", + "segment": 0, + "short": "TB_PG_elec_100GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_200GeV-000203.json b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_200GeV-000203.json new file mode 100644 index 0000000000000000000000000000000000000000..d05ca3f6bab5c29e3bee3e792b1fc8274e8749f8 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_200GeV-000203.json @@ -0,0 +1,14 @@ +{ + "file_length": 1000, + "geom": "TestBeamMC", + "mass": 0.511, + "maxE": 200.0, + "minE": 200.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 203, + "sampler": "const", + "segment": 0, + "short": "TB_PG_elec_200GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_30GeV-000202.json b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_30GeV-000202.json new file mode 100644 index 0000000000000000000000000000000000000000..332f05dbadc980e83872766ecff39e05c985f4af --- /dev/null +++ b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_30GeV-000202.json @@ -0,0 +1,14 @@ +{ + "file_length": 1000, + "geom": "TestBeamMC", + "mass": 0.511, + "maxE": 30.0, + "minE": 30.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 202, + "sampler": "const", + "segment": 0, + "short": "TB_PG_elec_30GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_50GeV-000201.json b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_50GeV-000201.json new file mode 100644 index 0000000000000000000000000000000000000000..6423bea683751eef9fad1a7e07974ba833f590b7 --- /dev/null +++ b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_elec_50GeV-000201.json @@ -0,0 +1,14 @@ +{ + "file_length": 1000, + "geom": "TestBeamMC", + "mass": 0.511, + "maxE": 50.0, + "minE": 50.0, + "pid": [-11, 11], + "radius": -100.0, + "run": 201, + "sampler": "const", + "segment": 0, + "short": "TB_PG_elec_50GeV", + "zpos": -1000.0 +} diff --git a/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_muon_100GeV-000100.json b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_muon_100GeV-000100.json new file mode 100644 index 0000000000000000000000000000000000000000..d6c6eee30676d772ab4a9fdd6cee9e46365658cd --- /dev/null +++ b/Control/CalypsoExample/Generation/data/tb21/FaserMC-TB_PG_muon_100GeV-000100.json @@ -0,0 +1,14 @@ +{ + "file_length": 2000, + "geom": "TestBeamMC", + "mass": 105.66, + "maxE": 100.0, + "minE": 100.0, + "pid": [-13, 13], + "radius": -100.0, + "run": 100, + "sampler": "const", + "segment": 0, + "short": "TB_PG_muon_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..575a2e2a4dc09078a2662b86e43086be45bb555c --- /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.005, 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/python/faser_parser.py b/Control/CalypsoExample/Generation/python/faser_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..43f98387e7089cfdf258531ec57aeea072b70f53 --- /dev/null +++ b/Control/CalypsoExample/Generation/python/faser_parser.py @@ -0,0 +1,175 @@ +# +# 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 particle gun samples +# +def faser_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("--geom", default="TI12MC", + help="Specify geomtery to simulation (default: TI12MC, alt: TestBeamMC)") + + 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="PG_logE", + help="Short description for filename") + parser.add_argument("--tag", default=None, + help="Generator tag (e.g.: 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.005, 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 Foresee samples +# +def faser_fsparser(): + + import sys + import json + import argparse + + parser = argparse.ArgumentParser(description="Run FASER Foresee 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="PG_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..f16b6a40a0413278097824bb7af63b51811eaa9c --- /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', 'Trench'] +# +# 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..98975a548601209a81b932c7cbbbe03da7184035 --- /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] + 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', 'Trench'] +# +# 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..6abdfdd4a8c8ae18547462b68532bd51cc4a9d71 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/faser_particlegun.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +""" +Produce particle gun samples +Derived from G4FaserAlgConfigNew + +Usage: +faser_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.faser_parser import faser_pgparser + args = faser_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} evnts into 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] + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [(args.segment+1)] + ConfigFlags.Input.isMC = True + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions +# +# 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) + + if args.geom == "TI12MC": + # 2022 TI12 geometry + ConfigFlags.GeoModel.FaserVersion = "FASERNU-02" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Conditions set-up + # TI12 detectors + detectors = ['Veto', 'VetoNu', 'Preshower', 'FaserSCT', 'Ecal', 'Trigger', + 'Dipole', 'Emulsion', 'Trench'] + + elif args.geom == "TestBeamMC": + # Define 2021 test beam geometry + ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" # Geometry set-up + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-TB00" # Conditions set-up + # Testbeam detectors (trigger layers are actually veto counters) + detectors = ['Veto', 'Preshower', 'FaserSCT', 'Ecal'] + + else: + print(f"Unknown geometry {args.geom}!") + sys.exit(1) + + 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 + } + + # -1000 is safely upstream of detector (to be checked) + # 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 +# +# By being a little clever, we can steer the geometry setup from the command line using GeoModel.FaserVersion +# +# 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/submit_faserMDC_foresee.sh b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh new file mode 100755 index 0000000000000000000000000000000000000000..94d9ab8b85e2dbf30498662178e599a519641951 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_foresee.sh @@ -0,0 +1,223 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_foresee.sh config_file segment [release_directory] [working_directory] +# +# Options: +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 options +while [ -n "$1" ] +do + case "$1" in + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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 +# Check if relative path (only works run interactively) +if ! [[ ${config_path::1} == "/" ]]; then + echo "config_path should be absolute!" + config_path=`pwd`/${1} + echo "Using: $config_path" +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 +logfile="${config_file_stem}-${seg_str}.gen.log" +exec >& "$output_directory/${logfile}" +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 +if [[ "$gentag" == "digi/d"???? ]]; then + tag=`echo "$gentag" | cut -c 6-11` + echo "Found digi tag: $tag" +fi +if [[ "$gentag" == "reco/r"???? ]]; then + tag=`echo "$gentag" | 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 "${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" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-HITS.root to $outdest" + mkdir -p $outdest + eos cp *-HITS.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logffile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi 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..5d704e9a51445d2ae408512c4eb0df83c71a8b39 --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/submit_faserMDC_particlegun.sh @@ -0,0 +1,221 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faserMDC_particlegun.sh config_file segment [release_directory] [working_directory] +# +# Options: +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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) +# +# Afterwards, the output file will be copied to the directory specified in working_directory +# +# 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 options +while [ -n "$1" ] +do + case "$1" in + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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 +# Check if relative path (only works run interactively) +if ! [[ ${config_path::1} == "/" ]]; then + echo "config_path should be absolute!" + config_path=`pwd`/${1} + echo "Using: $config_path" +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 +logfile="${config_file_stem}-${seg_str}.gen.log" +exec >& "$output_directory/${logfile}" +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 +if [[ "$gentag" == "digi/d"???? ]]; then + tag=`echo "$gentag" | cut -c 6-11` + echo "Found digi tag: $tag" +fi +if [[ "$gentag" == "reco/r"???? ]]; then + tag=`echo "$gentag" | 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 "${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" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-HITS.root to $outdest" + mkdir -p $outdest + eos cp *-HITS.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi diff --git a/Control/CalypsoExample/Generation/scripts/submit_faser_particlegun.sh b/Control/CalypsoExample/Generation/scripts/submit_faser_particlegun.sh new file mode 100755 index 0000000000000000000000000000000000000000..ec13600f7a94ce8f1958652f83a6e36f72b4563f --- /dev/null +++ b/Control/CalypsoExample/Generation/scripts/submit_faser_particlegun.sh @@ -0,0 +1,221 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faser_particlegun.sh config_file segment [release_directory] [working_directory] +# +# Options: +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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) +# +# Afterwards, the output file will be copied to the directory specified in working_directory +# +# 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 options +while [ -n "$1" ] +do + case "$1" in + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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_faser_particlegun.sh config_file segment [release dir] [output dir]" + exit 1 +fi +# Check if relative path (only works run interactively) +if ! [[ ${config_path::1} == "/" ]]; then + echo "config_path should be absolute!" + config_path=`pwd`/${1} + echo "Using: $config_path" +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 +logfile="${config_file_stem}-${seg_str}.gen.log" +exec >& "$output_directory/${logfile}" +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 +if [[ "$gentag" == "digi/d"???? ]]; then + tag=`echo "$gentag" | cut -c 6-11` + echo "Found digi tag: $tag" +fi +if [[ "$gentag" == "reco/r"???? ]]; then + tag=`echo "$gentag" | 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 "${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 + faser_particlegun.py "--conf=$config_path" "--segment=$seg_str" +else + faser_particlegun.py "--conf=$config_path" "--segment=$seg_str" "--tag=$tag" +fi +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-HITS.root to $outdest" + mkdir -p $outdest + eos cp *-HITS.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi 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..23af9627f673516d4e78d17a75596770ca6e3b4b 100644 --- a/Control/CalypsoExample/Reconstruction/CMakeLists.txt +++ b/Control/CalypsoExample/Reconstruction/CMakeLists.txt @@ -14,13 +14,27 @@ atlas_subdir( Reconstruction ) # Install files from the package: #atlas_install_joboptions( share/*.py ) -#atlas_install_python_modules( python/*.py ) +atlas_install_python_modules( python/*.py ) 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 + SCRIPT scripts/faser_reco.py --geom=TI12Data ${CMAKE_CURRENT_SOURCE_DIR}/../rawdata/Faser-Physics-001920-filtered.raw PROPERTIES TIMEOUT 300 ) + atlas_add_test( ProdRecoTestBeam - SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-003613-filtered.raw TestBeamData + SCRIPT scripts/faser_reco.py --geom=TestBeamData ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-003613-filtered.raw + PROPERTIES TIMEOUT 300 ) + +atlas_add_test( ProdRecoPilotTracks + SCRIPT scripts/faser_reco.py --geom=TI12Data ${CMAKE_CURRENT_SOURCE_DIR}/../RAWDATA/Faser-Physics-pilot_tracks-filtered.raw PROPERTIES TIMEOUT 300 ) +# Test of TI12Data02 geometry (should auto-select from run number) +atlas_add_test( ProdRecoTI12-02-2022 + SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../rawdata/Faser-Physics-006525-filtered.raw + PROPERTIES TIMEOUT 300 ) + +# Test of TI12Data03 geometry (should auto-select from run number) +atlas_add_test( ProdRecoTI12-03-2022 + SCRIPT scripts/faser_reco.py ${CMAKE_CURRENT_SOURCE_DIR}/../rawdata/Faser-Physics-007833-00003-TrigMask08.raw + PROPERTIES TIMEOUT 300 ) diff --git a/Control/CalypsoExample/Reconstruction/python/xAODTruthCnvAlgConfig.py b/Control/CalypsoExample/Reconstruction/python/xAODTruthCnvAlgConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..9d166c2aeeae2c4aa2fa9c9d52cc575beab5b7b8 --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/python/xAODTruthCnvAlgConfig.py @@ -0,0 +1,23 @@ +# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2022 CERN for the benefit of the FASER collaboration + +def xAODTruthCnvAlgCfg(flags, name="xAODTruthCnvAlg", **kwargs): + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + acc = ComponentAccumulator() + + kwargs.setdefault('WriteTruthMetaData', False) + kwargs.setdefault('AODContainerName', 'TruthEvent') + kwargs.setdefault('EventInfo', 'McEventInfo') + + from AthenaConfiguration.ComponentFactory import CompFactory + algo = CompFactory.xAODMaker.xAODTruthCnvAlg(name, **kwargs) + acc.addEventAlgo(algo, primary=True) + + toAOD = ["xAOD::TruthEventContainer#*", "xAOD::TruthEventAuxContainer#*", + "xAOD::TruthVertexContainer#*", "xAOD::TruthVertexAuxContainer#*", + "xAOD::TruthParticleContainer#*", "xAOD::TruthParticleAuxContainer#*"] + + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + acc.merge(OutputStreamCfg(flags, "xAOD", ItemList=toAOD)) + + return acc diff --git a/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py new file mode 100755 index 0000000000000000000000000000000000000000..6f5b224ee7b2de4bd7dfe66aa277a8b5b755157c --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/scripts/faserMDC_reco.py @@ -0,0 +1,251 @@ +#!/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 +# Remove any filetype modifier +if filestem[-4:] == "-RDO": + filestem = filestem[:-4] + +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)) + +# Add tracking collection with no IFT +acc.merge(CKF2Cfg(ConfigFlags, maskedLayers=[0, 1, 2], name="CKF_woIFT", + OutputCollection="CKFTrackCollectionWithoutIFT", 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: + # Make xAOD versions of truth + from Reconstruction.xAODTruthCnvAlgConfig import xAODTruthCnvAlgCfg + acc.merge(xAODTruthCnvAlgCfg(ConfigFlags)) + + # Add MC information 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 +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + ConfigFlags.dump() +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 7c1f662f4cfdad38026a90a7c01c82e834a0ef01..4e233bf4fcb8a014393bf8858c55ef25d7690519 100755 --- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py +++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py @@ -2,30 +2,39 @@ # # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration # Run with: -# ./faser_reco.py filepath [runtype] +# ./faser_reco.py [--geom=runtype] filepath # # 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 - optional flag to specify the data type (TI12Data or TestBeamData). -# In a normal file system location, this will be extracted from the directory name, -# but runtype will override this assignment. +# runtype - optionally specify the data type (TI12Data, TI12Data02, TI12Data03 or TestBeamData). +# +# Options: +# --isMC - needed to reconstruct MC data +# --testBeam - shortcut to specify testbeam 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("-g", "--geom", default="", + help="Specify geometry (if it can't be parsed from run number)\n Values: TI12Data03 (2022 TI12)") 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") +parser.add_argument("--isMC", action='store_true', + help="Running on digitised MC rather than data") +parser.add_argument("--testBeam", action='store_true', + help="Set geometry for 2021 test beam") args = parser.parse_args() @@ -34,18 +43,38 @@ from pathlib import Path filepath=Path(args.file_path) # runtype has been provided -if len(args.run_type) > 0: - runtype=args.run_type +if len(args.geom) > 0: + runtype=args.geom -# Extract runtype from path -# Should be directory above run -# i.e.: TestBeamData/Run-004150/Faser-Physics-004150-00000.raw" -else: - if len(filepath.parts) < 3: - print("Can't determine run type from path - specify on command line instead") - sys.exit(-1) +# Shortcut for testbeam +elif args.testBeam: + print(f"Use 2021 TestBeam configuration") + runtype = "TestBeamData" - runtype = filepath.parts[-3] +else: + print(f"Assuming TI12 geometry") + runtype = "TI12Data03" + + # Try to pick correct geometry from run number + # This won't work for testbeam data, + # so lets call this a hack for now + runname = filepath.parts[-1] + try: + runnumber = int(runname.split('-')[2]) + except Exception as e: + print(f"Failed to find run number in {filepath}") + print(f"Couldn't parse {runname}") + print(f"Leave runtype as {runtype}!") + else: + if runnumber > 6700: # Not sure if this is exact + print(f"Found run number {runnumber}, using TI12 configuration with IFT+faserNu") + runtype = "TI12Data03" + elif runnumber > 5302: # Last TI12 run on Nov. 23, 2021 without IFT + print(f"Found run number {runnumber}, using TI12 configuration with IFT") + runtype = "TI12Data02" + else: + print(f"Found run number {runnumber}, using original TI12 configuration") + runtype = "TI12Data" print(f"Starting reconstruction of {filepath.name} with type {runtype}") if args.nevents > 0: @@ -63,37 +92,60 @@ from CalypsoConfiguration.AllConfigFlags import ConfigFlags Configurable.configurableRun3Behavior = True # Flags for this job -ConfigFlags.Input.isMC = False # Needed to bypass autoconfig -ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now +ConfigFlags.Input.isMC = args.isMC # Needed to bypass autoconfig +if args.isMC: + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions +else: + ConfigFlags.IOVDb.DatabaseInstance = "CONDBR3" # Use data conditions 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" ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Testbeam setup -elif runtype == "TestBeamData": +elif runtype == "TestBeamData" or runtype == "TestBeamMC": 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") - sys.exit(-1) + 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[-4:] == "-RDO": + filestem = filestem[:-4] + 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? @@ -111,8 +163,13 @@ acc.merge(PoolWriteCfg(ConfigFlags)) # # Set up RAW data access -from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg -acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags)) + +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? @@ -129,15 +186,35 @@ 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)) -# Try Dave's fitter -from TrackerClusterFit.TrackerClusterFitConfig import ClusterFitAlgCfg -acc.merge(ClusterFitAlgCfg(ConfigFlags)) +# Try Dave's new fitter +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)) + + # Add tracking collection with no IFT + acc.merge(CKF2Cfg(ConfigFlags, maskedLayers=[0, 1, 2], name="CKF_woIFT", + OutputCollection="CKFTrackCollectionWithoutIFT", noDiagnostics=True)) # # Configure output @@ -146,13 +223,29 @@ 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#*" ] -acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList)) +# +if args.isMC: + # Make xAOD versions of truth + from Reconstruction.xAODTruthCnvAlgConfig import xAODTruthCnvAlgCfg + acc.merge(xAODTruthCnvAlgCfg(ConfigFlags)) + + # Add MC information here + itemList.extend( ["McEventCollection#*", "TrackerSimDataCollection#*"] ) + +# Output stream +acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList, disableEventTag=True)) + +# Try to turn off annoying INFO message, as we don't use this +# disableEventTag=True doesn't seem to work... +tagBuilder = CompFactory.EventInfoTagBuilder() +tagBuilder.PropagateInput=False +acc.addEventAlgo(tagBuilder) # Waveform reconstruction output from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionOutputCfg @@ -167,29 +260,35 @@ print( "Writing out xAOD objects:" ) print( acc.getEventAlgo("OutputStreamxAOD").ItemList ) # 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 +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 - - #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 - + ConfigFlags.dump() else: acc.foreach_component("*").OutputLevel = INFO + # Reduce event loop printout + eventLoop = CompFactory.AthenaEventLoopMgr() + eventLoop.EventPrintoutInterval = 100 + acc.addService(eventLoop) + 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/filterRun.sh b/Control/CalypsoExample/Reconstruction/scripts/filterRun.sh new file mode 100755 index 0000000000000000000000000000000000000000..9901f9e9fcd1e3168b9833ddefab28514e2387fa --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/scripts/filterRun.sh @@ -0,0 +1,210 @@ +#!/usr/bin/bash +# +# Script to filter events likely to have tracks and reconstruct them +# Need to build calypso AND faser-common for this to work +# Execute from the run folder in a release directory +# +# Usage: +# ./filterRun.sh [--seg] [--install] <runnumber> +# +# Options: +# --seg - filter individual segments +# by default, run is filtered into single file +# --install - copy output to EOS +# --cleanup - delete local files after EOS copy +# +# During the first 13.6 collision event, this was run with: +# watch -n 150 ./filterRun.sh --install --seg 7733 +# +# The --cleanup flag doesn't work for this, as the script checks the +# local directory (not EOS) to see if a segment has already been processed. +# +# To just make a single filtered file for a run and cleanup afterwards: +# ./filterRun.sh --install --cleanup 7733 +# +# Hacky parameters +# These are used to label the output files, correct for when this was used, +# but may not be correct in the future +rtag='r0008' +filter='TrigMask08' +# +# Usage function +print_usage () { + echo "Usage: filterRun [--seg] [--install] [--cleanup] <runnum>" +} + +# EOS copy function +copy_to_eos () { + local filtdir=/eos/experiment/faser/filter/2022/$filter + local rawdir=$filtdir/raw/$run_number + local recdir=$filtdir/$rtag/$run_number + local logdir=$filtdir/${rtag}_log/$run_number + + # Make sure directories exist + mkdir -p $rawdir + mkdir -p $recdir + mkdir -p $logdir + + # Copy files + echo "Copy $outfile to $rawdir" + xrdcp --silent --force $outfile root://eospublic.cern.ch/${rawdir} + echo "Copy $recfile to $recdir" + xrdcp --silent --force $recfile root://eospublic.cern.ch/${recdir} + echo "Copy $logfile to $logdir" + xrdcp --silent --force $logfile root://eospublic.cern.ch/${logdir} +} + +# Parse commaand-line options +while [ -n "$1" ] +do + case "$1" in + -s | --seg) + echo "Filtering individual segments" + seg=1 + shift;; # This eats the option + + -i | --install) + echo "Copying files to EOS when done" + install=1 + shift;; + + --cleanup) + cleanup=1 + shift;; + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +if [ -z $1 ] +then + echo "No run number specified!" + print_usage + exit 1 +fi +# +printf -v run "%06d" ${1} +echo Filtering run ${1} +# +eosdir=/eos/experiment/faser/raw/2022/$run +appstr='' +for file in $eosdir/* +do + if ! [ -f $file ]; then + continue + fi + + if ! [[ $file == $eosdir/Faser-Physics-* ]]; then + continue + fi + + filename=`basename $file` + + # Split filename + OIFS=$IFS + IFS='.' + read file_stem ext <<< "$filename" + + IFS='-' + read faser type run_number segment <<< "$file_stem" + + # Put the delimieter baack + IFS=$OIFS + + # Do this one file at a time? + if [ -z $seg ] + then + # Append filtered output to one file + outfile=Faser-$type-$run_number-$filter.$ext + logfile=Faser-$type-$run_number-$filter.log + + # Make sure logfile exists for first iteration + touch $logfile + echo Filtering $filename to $outfile + echo Filtering $filename to $outfile >> $logfile + + # Split file to get file name + ../calypso/faser-common/build/EventFormats/eventFilter $appstr -t 0x08 $file $outfile >> $logfile 2>&1 + + # Append from here on out + appstr='-a' + + else + # Separate files for each segment + outfile=Faser-$type-$run_number-$segment-$filter.$ext + logfile=Faser-$type-$run_number-$segment-$filter.log + + # Don't overwrite + if [ -f "$outfile" ]; then + echo $outfile already done - skipping + continue + fi + + echo Filtering $filename to $outfile + echo Filtering $filename to $outfile > $logfile + + # Filter + ../calypso/faser-common/build/EventFormats/eventFilter -t 0x08 $file $outfile >> $logfile 2>&1 + + echo Filtered `grep "#fragments=" $logfile | wc -l` events + echo Filtered `grep "#fragments=" $logfile | wc -l` events >> $logfile + + # And reconstruct it if not empty + if ! [ -s $outfile ]; then + echo "No events filtered" >> $logfile + continue + fi + + # Recontruct + echo "Reco $outfile" + faser_reco.py -r $rtag $outfile TI12Data03 >> $logfile 2>&1 + + # Do we want to save this to EOS? + if [ -z $install ]; then + continue + fi + + # Copy files + recfile=Faser-Physics-$run_number-$segment-$filter-$rtag-xAOD.root + copy_to_eos + + fi + +done + +# Did we write one big file? +if [ -z $seg ] +then + + echo Filtered `grep "#fragments=" $logfile | wc -l` events + echo Filtered `grep "#fragments=" $logfile | wc -l` events >> $logfile + + # Run reco if file isn't empty + if [ -s $outfile ]; then + echo "Reco $outfile" + faser_reco.py -r $rtag $outfile TI12Data03 >> $logfile 2>&1 + + # Do we want to save this to EOS? + if [ -z $install ]; then + exit 0 + fi + + recfile=Faser-Physics-$run_number-$filter-$rtag-xAOD.root + copy_to_eos + + else + echo "No events filtered" >> $logfile + fi +fi + +if ! [ -z $cleanup ]; then + echo "Removing files" + rm Faser-Physics-$run_number-* + rm PoolFileCatalog.xml + rm SegmentFitHistograms.root + rm eventLoopHeartBeat.txt +fi 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..e4d93ba6487000c7c939ee57d79dd704dad96324 --- /dev/null +++ b/Control/CalypsoExample/Reconstruction/scripts/submit_faserMDC_reco.sh @@ -0,0 +1,203 @@ +#!/bin/bash +# Used with a condor file to submit to vanilla universe +# +# Usage: +# submit_faser_reco.sh file_path [release_directory] [working_directory] [nevents] +# +# Options: +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 +# +#---------------------------------------- +# Keep track of time +SECONDS=0 +# +# Parse command-line options +while [ -n "$1" ] +do + case "$1" in + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# 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 +logfile="${file_stem}.rec.log" +exec >& "$output_directory/${logfile}" +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 run/setup.sh +#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 + tagstr="" +else + tagstr="--reco=$tag" +fi +# +faser_reco.py "--nevents=$nevents" $tagstr "$file_path" +# +# Print out ending time +date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + echo "Output directory:" + ls -l + echo "copy *-xAOD.root to $outdest" + eos mkdir -p $outdest + # Keep this line from stopping script, so we might get a log file + # || true ensures script continues even if copy fails + eos cp *-xAOD.root ${outdest}/ || true +fi +# +# Copy log file second +if ! [ -z "$logdest" ] +then + cd .. + echo "Working directory:" + ls -l + echo "copy $logfile to $logdest" + eos mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + echo "Working directory:" + ls -l + echo "copy $logfile to $outdest" + eos mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi diff --git a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh index 6bb4b895732639182709dc0d237458704ddeb4fe..6924506133cddacd3ad7f4f88aec64121719b9b8 100755 --- a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh +++ b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh @@ -4,6 +4,12 @@ # Usage: # submit_faser_reco.sh file_path [release_directory] [working_directory] [nevents] # +# Options: +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# --geom - specify geometry +# --isMC - needed for MC reco +# # 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) @@ -16,8 +22,45 @@ # If this matches reco/r???? it will be passed to the reco job # #---------------------------------------- +# Keep track of time +SECONDS=0 # # Parse command-line options +while [ -n "$1" ] +do + case "$1" in + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + -g | --geom) + geom="$2"; + shift; + shift;; + + --isMC) + ismc=1 + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + echo "Unknown option $1" + shift;; + + *) break;; # Not an option, don't shift + esac +done +# +# Parse command-line arguments file_path=${1} release_directory=${2} working_directory=${3} @@ -66,13 +109,16 @@ read faser type run_number segment <<< "$file_stem" IFS=$defaultIFS # # Make output directory if needed -output_directory="$working_directory/Run-$run_number" +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" +logfile="${file_stem}.rec.log" +exec >& "$output_directory/$logfile" echo `date` - $HOSTNAME echo "File: $file_name" +echo "Filepath: $file_path" +echo "Geom: $geom" echo "Release: $release_directory" echo "Output: $output_directory" echo "Starting: $starting_directory" @@ -85,20 +131,24 @@ source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh # Always go back to the starting directory in case paths are relative cd "$starting_directory" cd "$release_directory" -asetup -source build/x8*/setup.sh +#asetup +#source build/x8*/setup.sh # # Do this by hand -# asetup --input="$release_directory/calypso/asetup.faser" Athena,22.0.40 -# source "$release_directory/build/x8*/setup.sh" -# +asetup --input=calypso/asetup.faser Athena,22.0.49 +source run/setup.sh +#source build/x86*/setup.sh # # Try to find a release tag 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 proc tag: $tag" fi # # Move to the run directory @@ -120,11 +170,60 @@ fi cd "$file_stem" # # Run job -if [[ -z "$rtag" ]]; then - faser_reco.py "--nevents=$nevents" "$file_path" +if [[ -z "$tag" ]]; then + tagstr="" +else + tagstr="--reco=$tag" +fi +# +if [[ -z "$geom" ]]; then + geomstr="" +else + geomstr="--geom $geom" +fi +# +if [[ -z "$ismc" ]]; then + mcstr="" else - faser_reco.py "--nevents=$nevents" "--reco=$rtag" "$file_path" + mcstr="--isMC" fi # +faser_reco.py "--nevents=$nevents" $geomstr $tagstr $mcstr "$file_path" +# # Print out ending time date +echo "Job finished after $SECONDS seconds" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +# Now copy output file +if ! [ -z "$outdest" ] +then + echo "Output directory:" + ls -l + echo "copy *-xAOD.root to $outdest" + eos mkdir -p $outdest + # Keep this line from stopping script, so we might get a log file + # || true ensures script continues even if copy fails + eos cp *-xAOD.root ${outdest}/ || true +fi +# +# Copy log file second +if ! [ -z "$logdest" ] +then + cd .. + echo "Working directory:" + ls -l + echo "copy $logfile to $logdest" + eos mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + echo "Working directory:" + ls -l + echo "copy $logfile to $outdest" + eos mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi diff --git a/Control/CalypsoExample/SimHitExample/CMakeLists.txt b/Control/CalypsoExample/SimHitExample/CMakeLists.txt index 19aa729b18603e2d40dd600d10b8d9ab3a645541..c4ff6c3836e75b95ce8ced1f754b18342a09a7c2 100644 --- a/Control/CalypsoExample/SimHitExample/CMakeLists.txt +++ b/Control/CalypsoExample/SimHitExample/CMakeLists.txt @@ -6,4 +6,5 @@ atlas_add_component( SimHitExample LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent ScintSimEvent FaserCaloSimEvent NeutrinoSimEvent ) -atlas_install_joboptions( share/*.py ) \ No newline at end of file +atlas_install_joboptions( share/*.py ) +atlas_install_python_modules( python/*.py ) \ No newline at end of file diff --git a/Control/CalypsoExample/SimHitExample/python/SimHitExampleConfig.py b/Control/CalypsoExample/SimHitExample/python/SimHitExampleConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..5e71b860f80281d8075e993cc3a41c535bfb4c71 --- /dev/null +++ b/Control/CalypsoExample/SimHitExample/python/SimHitExampleConfig.py @@ -0,0 +1,67 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS and FASER collaborations + +#!/usr/bin/env python +import sys +from AthenaCommon.Constants import VERBOSE, INFO +from AthenaConfiguration.ComponentFactory import CompFactory + +def SimHitAlgCfg(flags, name="SimHitAlg", **kwargs): + + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + a = FaserGeometryCfg(flags) + + # Configure the algorithm itself + SimHitAlg = CompFactory.SimHitAlg + a.addEventAlgo(SimHitAlg(name, **kwargs)) + + # Set up histogramming + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST DATAFILE='simHitAlg.root' OPT='RECREATE'"] + a.addService(thistSvc) + + 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.Files = ["my.HITS.pool.root"] # input file(s) + 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.Detector.GeometryEmulsion = True + ConfigFlags.Detector.GeometryTrench = True + ConfigFlags.lock() + +# Configure components +# Core framework + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + acc = MainServicesCfg(ConfigFlags) + +# Data input + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + acc.merge(PoolReadCfg(ConfigFlags)) + +# Algorithm + acc.merge(SimHitAlgCfg(ConfigFlags, McEventCollection = "TruthEvent", + PrintNeutrinoHits = False, + PrintTrackerHits = False, + PrintScintillatorHits = False, + PrintCalorimeterHits = False)) + +# 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/SimHitExample/share/SimHitExample_jobOptions.py b/Control/CalypsoExample/SimHitExample/share/SimHitExample_jobOptions.py index 85285711b027abd54d8704c10e6c569a6f26702b..ac6bc487f8bc3263a6d09a920e980da3c3437cd8 100644 --- a/Control/CalypsoExample/SimHitExample/share/SimHitExample_jobOptions.py +++ b/Control/CalypsoExample/SimHitExample/share/SimHitExample_jobOptions.py @@ -1,3 +1,7 @@ + +# Note: this job configuration method is obsolete +# Please see python/SimHitAlgConfig.py for the correct method to use + from AthenaCommon.GlobalFlags import globalflags globalflags.InputFormat.set_Value_and_Lock('pool') diff --git a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx index 100b0eeab94ffe94e8cb6f1119ca7ee39d5e5404..7fc371479fba5adee99cc327970f5226186a48e2 100644 --- a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx +++ b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.cxx @@ -18,9 +18,9 @@ StatusCode SimHitAlg::initialize() ATH_CHECK(histSvc()->regHist("/HIST/modulesSide1", m_moduleSide1)); ATH_CHECK(histSvc()->regHist("/HIST/modulesSide2", m_moduleSide2)); - m_plate_preshower = new TH2D("plate", "Scint Hit Plate", 3, -1, 1, 4, 0, 1 ); - m_plate_trigger = new TH2D("plate", "Scint Hit Plate", 3, -1, 1, 4, 0, 1 ); - m_plate_veto = new TH2D("plate", "Scint Hit Plate", 3, -1, 1, 4, 0, 1 ); + m_plate_preshower = new TH2D("preshowerplate", "Preshower Hit", 3, -1, 1, 4, 0, 1 ); + m_plate_trigger = new TH2D("triggerplate", "Trigger Hit", 3, -1, 1, 4, 0, 1 ); + m_plate_veto = new TH2D("vetoplate", "Veto Hit", 3, -1, 1, 4, 0, 1 ); ATH_CHECK(histSvc()->regHist("/HIST/plate_preshower", m_plate_preshower)); ATH_CHECK(histSvc()->regHist("/HIST/plate_trigger", m_plate_trigger)); ATH_CHECK(histSvc()->regHist("/HIST/plate_veto", m_plate_veto)); @@ -28,6 +28,9 @@ StatusCode SimHitAlg::initialize() m_ecalEnergy = new TH1D("ecalEnergy", "Ecal Energy Fraction", 100, 0.0, 0.20); ATH_CHECK(histSvc()->regHist("/HIST/ecal_energy", m_ecalEnergy)); + m_emulsionPDG = new TH1D("emulsionPDG", "Energy-weighted PDG code of emulsion hits", 4425, -2212.5, 2212.5); + ATH_CHECK(histSvc()->regHist("/HIST/emulsionPDG", m_emulsionPDG)); + // initialize data handle keys ATH_CHECK( m_mcEventKey.initialize() ); ATH_CHECK( m_faserSiHitKey.initialize() ); @@ -72,13 +75,13 @@ StatusCode SimHitAlg::execute() } SG::ReadHandle<ScintHitCollection> h_preshowerHits(m_preshowerHitKey); - ATH_MSG_INFO("Read ScintHitCollection/Preshower with " << h_preshowerHits->size() << " hits"); + ATH_MSG_INFO("Read ScintHitCollection/PreshowerHits with " << h_preshowerHits->size() << " hits"); SG::ReadHandle<ScintHitCollection> h_triggerHits(m_triggerHitKey); - ATH_MSG_INFO("Read ScintHitCollection/Trigger with " << h_triggerHits->size() << " hits"); + ATH_MSG_INFO("Read ScintHitCollection/TriggerHits with " << h_triggerHits->size() << " hits"); SG::ReadHandle<ScintHitCollection> h_vetoHits(m_vetoHitKey); - ATH_MSG_INFO("Read ScintHitCollectionVeto with " << h_vetoHits->size() << " hits"); - + ATH_MSG_INFO("Read ScintHitCollection/VetoHits with " << h_vetoHits->size() << " hits"); SG::ReadHandle<CaloHitCollection> h_ecalHits(m_ecalHitKey); + ATH_MSG_INFO("Read CaloHitCollection with " << h_ecalHits->size() << " hits"); // Since we have no pile-up, there should always be a single GenEvent in the container const HepMC::GenEvent* ev = (*h_mcEvents)[0]; @@ -101,7 +104,11 @@ StatusCode SimHitAlg::execute() //Loop over all hits; print for (const NeutrinoHit& hit : *h_emulsionHits) { - hit.print(); + if (m_printNeutrino) hit.print(); + if (hit.particleLink().isValid()) + { + m_emulsionPDG->Fill(hit.particleLink()->pdg_id(), hit.energyLoss()); + } } } @@ -112,7 +119,7 @@ StatusCode SimHitAlg::execute() // Loop over all hits; print and fill histogram for (const FaserSiHit& hit : *h_siHits) { - hit.print(); + if (m_printTracker) hit.print(); m_hist->Fill( hit.energyLoss() ); m_module->Fill( hit.getModule(), hit.getRow() ); if (hit.getSensor() == 0) @@ -130,7 +137,7 @@ StatusCode SimHitAlg::execute() if (h_preshowerHits->size()!=0){ for (const ScintHit& hit : *h_preshowerHits) { - hit.print(); + if (m_printScintillator) hit.print(); m_hist->Fill(hit.energyLoss()); m_plate_preshower->Fill(hit.getStation(),hit.getPlate(),hit.energyLoss()); @@ -140,7 +147,7 @@ StatusCode SimHitAlg::execute() if (h_triggerHits->size()!=0){ for (const ScintHit& hit : *h_triggerHits) { - hit.print(); + if (m_printScintillator) hit.print(); m_hist->Fill(hit.energyLoss()); m_plate_trigger->Fill(hit.getStation(),hit.getPlate(),hit.energyLoss()); @@ -150,7 +157,7 @@ StatusCode SimHitAlg::execute() if (h_vetoHits->size()!=0){ for (const ScintHit& hit : *h_vetoHits) { - hit.print(); + if (m_printScintillator) hit.print(); m_hist->Fill(hit.energyLoss()); m_plate_veto->Fill(hit.getStation(),hit.getPlate(),hit.energyLoss()); @@ -162,6 +169,7 @@ StatusCode SimHitAlg::execute() double ecalTotal = 0.0; for (const CaloHit& hit : *h_ecalHits) { + if (m_printCalorimeter) hit.print(); ecalTotal += hit.energyLoss(); } if (ePrimary > 0) m_ecalEnergy->Fill(ecalTotal/ePrimary); diff --git a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h index 476f2999a4c403d73d7d303c1ed45256e0f9f7f5..b385c87ed8f193dc0c1b90df941de6cfbaa441a8 100644 --- a/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h +++ b/Control/CalypsoExample/SimHitExample/src/SimHitAlg.h @@ -34,6 +34,9 @@ class SimHitAlg : public AthHistogramAlgorithm // Ecal histogram TH1* m_ecalEnergy; + // Emulsion PDG_ID + TH1* m_emulsionPDG; + // Read handle keys for data containers // Any other event data can be accessed identically // Note the key names ("BeamTruthEvent" or "SCT_Hits") are Gaudi properties and can be configured at run-time @@ -54,4 +57,9 @@ class SimHitAlg : public AthHistogramAlgorithm //EcalHits SG::ReadHandleKey<CaloHitCollection> m_ecalHitKey { this, "CaloHitCollection", "EcalHits" }; + + BooleanProperty m_printNeutrino { this, "PrintNeutrinoHits", false }; + BooleanProperty m_printTracker { this, "PrintTrackerHits", false }; + BooleanProperty m_printScintillator { this, "PrintScintillatorHits", false }; + BooleanProperty m_printCalorimeter { this, "PrintCalorimeterHits", false }; }; \ No newline at end of file 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..0fd9622db5de8630ffaef34bd2ae4b6eabe88a5c --- /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', 'Trench'] +# +# 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..03b8a836e5c07c336165f5e30a577aafc9aab76b --- /dev/null +++ b/Control/CalypsoExample/Simulation/scripts/submit_faserMDC_simulate.sh @@ -0,0 +1,221 @@ +#!/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) +# --out - specify output location (in EOS) to copy output HITS file +# --log - specify output location (in EOS) for log file +# +# 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 + + -l | --log) + logdest="$2"; + shift; + shift;; # Must eat 2 options here + + -o | --out) + outdest="$2"; + shift; + shift;; + + --) # End of options + shift; # Eat this + break;; # And stop parsing + + -*) + 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 +logfile=${file_stem}.sim.log +exec >& "$output_directory/$logfile" +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" +# +# Copy output to EOS if desired +export EOS_MGM_URL=root://eospublic.cern.ch +# +if ! [ -z "$outdest" ] +then + ls -l + echo "copy *-HITS.root to $outdest" + mkdir -p $outdest + eos cp *-HITS.root ${outdest}/ || true +fi +# +# Also copy log file +if ! [ -z "$logdest" ] +then + cd .. + ls -l + echo "copy $logfile to $logdest" + mkdir -p $logdest + eos cp $logfile $logdest/$logfile +elif ! [ -z "$outdest" ] +then + cd .. + ls -l + echo "copy $logfile to $outdest" + mkdir -p $outdest + eos cp $logfile $outdest/$logfile +fi + diff --git a/Control/CalypsoExample/TruthEventDumper/CMakeLists.txt b/Control/CalypsoExample/TruthEventDumper/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ceea9c78f5a8d088b1d17d9f3c6af2d325758f9c --- /dev/null +++ b/Control/CalypsoExample/TruthEventDumper/CMakeLists.txt @@ -0,0 +1,11 @@ +################################################################################ +# Package: TruthEventDumper +################################################################################ + +# Declare the package name: +atlas_subdir( TruthEventDumper ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +atlas_install_joboptions( share/*.py ) \ No newline at end of file diff --git a/Control/CalypsoExample/TruthEventDumper/python/TruthEventDumperAlg.py b/Control/CalypsoExample/TruthEventDumper/python/TruthEventDumperAlg.py new file mode 100644 index 0000000000000000000000000000000000000000..934433e2f375d6f0883a5a66e66dba70f1515427 --- /dev/null +++ b/Control/CalypsoExample/TruthEventDumper/python/TruthEventDumperAlg.py @@ -0,0 +1,39 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +import AthenaPython.PyAthena as PyAthena +from AthenaPython.PyAthena import StatusCode, McEventCollection, HepMC, CLHEP +import McParticleEvent.Pythonizations + +__author__ = "Dave Caser <dcasper@uci.edu>" + +class TruthEventDumperAlg(PyAthena.Alg): + def __init__(self, name="TruthEventDumper", MCEventKey="TruthEvent"): + super(TruthEventDumperAlg,self).__init__(name=name) + self.MCEventKey = MCEventKey + return + + def initialize(self): + # self.maxLow = 0 + # self.maxMid = 0 + # self.maxHi = 0 + return StatusCode.Success + + + def execute(self): + evtCollection = self.evtStore[self.MCEventKey] + for mcEvt in evtCollection: + mcEvt.print() + # for mcParticle in mcEvt.particles: + # barCode = mcParticle.barcode() + # self.maxLow = max(self.maxLow, barCode%200000) + # if barCode%1000000 > 200000: + # self.maxMid = max(self.maxMid, barCode%1000000 - 200000) + # self.maxHi = max(self.maxHi, barCode//1000000) + return StatusCode.Success + + def finalize(self): + # print("Low part: ", self.maxLow, " out of 200000 (",100*self.maxLow/200000,"% of overflow)") + # print("Mid part: ", self.maxMid, " out of ", 1000000 - 200000, " (",100*self.maxMid/(1000000-200000),"% of overflow") + # print("Hi part: ", self.maxHi, " out of ", (1<<31)//1000000, " (", 100*self.maxHi/((1<<31)//1000000),"% of overflow") + + return StatusCode.Success \ No newline at end of file diff --git a/Control/CalypsoExample/TruthEventDumper/python/__init__.py b/Control/CalypsoExample/TruthEventDumper/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d13ae164caa4e93bf2899cea4e67d0ec515784a2 --- /dev/null +++ b/Control/CalypsoExample/TruthEventDumper/python/__init__.py @@ -0,0 +1 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration diff --git a/Control/CalypsoExample/TruthEventDumper/share/TruthEventDumper_jobOptions.py b/Control/CalypsoExample/TruthEventDumper/share/TruthEventDumper_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..303f4b8d26db18b0cf96f30e500548ecc1a84208 --- /dev/null +++ b/Control/CalypsoExample/TruthEventDumper/share/TruthEventDumper_jobOptions.py @@ -0,0 +1,41 @@ +# +# Usage: athena.py -c'INPUT=["faser.1.gfaser.root","faser.2.gfaser.root"]; COLLECTION="TruthEvent"; MAXEVT=-1; SKIPEVT=0' TruthEventDumper/TruthEventDumper_jobOptions.py >& TruthEventDumper.log +# +# INPUT is mandatory (INPUT can be a list, as shown above) +# COLLECTION would normally be either "TruthEvent" (Geant4 particles) or "BeamTruthEvent" (generator particles) +# MAXEVT and SKIPEVT are self-explanatory and optional +# + +if not 'INPUT' in dir(): + print("Missing INPUT parameter") + exit() + +if not 'MAXEVT' in dir(): + MAXEVT = -1 + +if not 'SKIPEVT' in dir(): + SKIPEVT = 0 + +if not 'COLLECTION' in dir(): + COLLECTION = "TruthEvent" + +if not isinstance(INPUT, (list,tuple)): + INPUT = [INPUT] + pass + +from AthenaCommon.GlobalFlags import globalflags + +globalflags.InputFormat.set_Value_and_Lock('pool') + +import AthenaPoolCnvSvc.ReadAthenaPool + +svcMgr.EventSelector.InputCollections = INPUT + +from TruthEventDumper.TruthEventDumperAlg import TruthEventDumperAlg + +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() +job += TruthEventDumperAlg(MCEventKey=COLLECTION) + +theApp.EvtMax = MAXEVT +theApp.SkipEvents = SKIPEVT diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx index 0d06d587ddb18dc55bee24650e282af8fdd856e7..c9d8f9f90a8b826ec5f3dcdd89fe928d859f17ec 100644 --- a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx +++ b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.cxx @@ -30,7 +30,6 @@ RawWaveformAccess::initialize() ATH_CHECK( m_VetoWaveformContainer.initialize() ); ATH_CHECK( m_TriggerWaveformContainer.initialize() ); ATH_CHECK( m_PreshowerWaveformContainer.initialize() ); - ATH_CHECK( m_TestWaveformContainer.initialize() ); ATH_CHECK( m_ClockWaveformContainer.initialize() ); return StatusCode::SUCCESS; @@ -66,10 +65,6 @@ RawWaveformAccess::execute(const EventContext& ctx) const ATH_MSG_INFO("Found ReadHandle for PreshowerWaveforms"); ATH_MSG_INFO(*preshowerHandle); - SG::ReadHandle<RawWaveformContainer> testHandle(m_TestWaveformContainer, ctx); - ATH_MSG_INFO("Found ReadHandle for TestWaveforms"); - ATH_MSG_INFO(*testHandle); - SG::ReadHandle<RawWaveformContainer> clockHandle(m_ClockWaveformContainer, ctx); ATH_MSG_INFO("Found ReadHandle for ClockWaveforms"); ATH_MSG_INFO(*clockHandle); diff --git a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h index d26b1eac4afab5baa890c6de5eadda5b13b5acb3..07cc4deb42b978b655ebaa9fb1eb7738fbc5c390 100644 --- a/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h +++ b/Control/CalypsoExample/WaveformDataAccessExample/src/RawWaveformAccess.h @@ -38,8 +38,6 @@ class RawWaveformAccess: public AthReentrantAlgorithm { this, "TriggerWaveformContainerKey", "TriggerWaveforms", "ReadHandleKey for TriggerWaveforms Container"}; SG::ReadHandleKey<RawWaveformContainer> m_PreshowerWaveformContainer { this, "PreshowerWaveformContainerKey", "PreshowerWaveforms", "ReadHandleKey for PreshowerWaveforms Container"}; - SG::ReadHandleKey<RawWaveformContainer> m_TestWaveformContainer - { this, "TestWaveformContainerKey", "TestWaveforms", "ReadHandleKey for TestWaveforms Container"}; SG::ReadHandleKey<RawWaveformContainer> m_ClockWaveformContainer { this, "ClockWaveformContainerKey", "ClockWaveforms", "ReadHandleKey for ClockWaveforms Container"}; }; diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser01.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser01.py index 675f61f5b77cea6bc6fac3c42eb01f17bfc492b8..00f4b9c37cce80a4ca7cb4c669f48d102a199fd4 100644 --- a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser01.py +++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser01.py @@ -5,7 +5,7 @@ import sys from AthenaCommon.Constants import VERBOSE, INFO from AthenaConfiguration.ComponentFactory import CompFactory -def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): +def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", alignmentConstants={}, **kwargs): # Initialize GeoModel from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg @@ -32,7 +32,12 @@ def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): PoolContainerPrefix="ConditionsContainer", TopLevelContainerName = "<type>", SubLevelBranchName= "<key>" ) - kwargs.setdefault("AlignDbTool", CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, OutputLevel=VERBOSE)) + + trackerAlignDBTool = CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, + OutputLevel=VERBOSE, + AlignmentConstants = {}) + kwargs.setdefault("AlignDbTool", trackerAlignDBTool) + trackerAlignDBTool.AlignmentConstants = alignmentConstants a.addEventAlgo(WriteAlignmentAlg(name, **kwargs)) return a @@ -53,6 +58,10 @@ if __name__ == "__main__": ConfigFlags.IOVDb.DBConnection = "sqlite://;schema=" + ConfigFlags.GeoModel.FaserVersion + "_ALLP200.db;dbname=OFLP200" ConfigFlags.GeoModel.Align.Disable = True # Hack to avoid loading alignment when we want to create it from scratch ConfigFlags.addFlag("WriteAlignment.PoolFileName", ConfigFlags.GeoModel.FaserVersion + "_Align.pool.root") + +# Parse flags from command line and lock + ConfigFlags.addFlag("AlignDbTool.AlignmentConstants", {}) + ConfigFlags.fillFromArgs(sys.argv[1:]) ConfigFlags.lock() # Configure components @@ -60,7 +69,7 @@ if __name__ == "__main__": acc = MainServicesCfg(ConfigFlags) # Set things up to create a conditions DB with neutral Tracker alignment transforms - acc.merge(WriteAlignmentCfg(ConfigFlags, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"))) + acc.merge(WriteAlignmentCfg(ConfigFlags, alignmentConstants=ConfigFlags.AlignDbTool.AlignmentConstants, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"), )) # Configure verbosity # ConfigFlags.dump() @@ -71,3 +80,4 @@ if __name__ == "__main__": # Execute and finish sys.exit(int(acc.run(maxEvents=1).isFailure())) + diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py index b05c15632415e873e301a08d9f63332175ebfe20..2e944e3fc88b76d6794a7df7b9ce4469fc763d51 100644 --- a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py +++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py @@ -5,7 +5,7 @@ import sys from AthenaCommon.Constants import VERBOSE, INFO from AthenaConfiguration.ComponentFactory import CompFactory -def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): +def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", alignmentConstants={}, **kwargs): # Initialize GeoModel from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg @@ -32,7 +32,12 @@ def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): PoolContainerPrefix="ConditionsContainer", TopLevelContainerName = "<type>", SubLevelBranchName= "<key>" ) - kwargs.setdefault("AlignDbTool", CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, OutputLevel=VERBOSE)) + + trackerAlignDBTool = CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, + OutputLevel=VERBOSE, + AlignmentConstants = {}) + kwargs.setdefault("AlignDbTool", trackerAlignDBTool) + trackerAlignDBTool.AlignmentConstants = alignmentConstants a.addEventAlgo(WriteAlignmentAlg(name, **kwargs)) return a @@ -53,6 +58,10 @@ if __name__ == "__main__": ConfigFlags.IOVDb.DBConnection = "sqlite://;schema=" + ConfigFlags.GeoModel.FaserVersion + "_ALLP200.db;dbname=OFLP200" ConfigFlags.GeoModel.Align.Disable = True # Hack to avoid loading alignment when we want to create it from scratch ConfigFlags.addFlag("WriteAlignment.PoolFileName", ConfigFlags.GeoModel.FaserVersion + "_Align.pool.root") + +# Parse flags from command line and lock + ConfigFlags.addFlag("AlignDbTool.AlignmentConstants", {}) + ConfigFlags.fillFromArgs(sys.argv[1:]) ConfigFlags.lock() # Configure components @@ -60,7 +69,7 @@ if __name__ == "__main__": acc = MainServicesCfg(ConfigFlags) # Set things up to create a conditions DB with neutral Tracker alignment transforms - acc.merge(WriteAlignmentCfg(ConfigFlags, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"))) + acc.merge(WriteAlignmentCfg(ConfigFlags, alignmentConstants=ConfigFlags.AlignDbTool.AlignmentConstants, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"), )) # Configure verbosity # ConfigFlags.dump() diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_FaserTB00.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_FaserTB00.py index d57092f2dd8b8c1dcb3bd6568fdb3dac636d3cf2..84fb1b02e855907c7c525c64498b7d4d8b015f18 100644 --- a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_FaserTB00.py +++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_FaserTB00.py @@ -5,7 +5,7 @@ import sys from AthenaCommon.Constants import VERBOSE, INFO from AthenaConfiguration.ComponentFactory import CompFactory -def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): +def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", alignmentConstants={}, **kwargs): # Initialize GeoModel from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg @@ -32,7 +32,12 @@ def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", **kwargs): PoolContainerPrefix="ConditionsContainer", TopLevelContainerName = "<type>", SubLevelBranchName= "<key>" ) - kwargs.setdefault("AlignDbTool", CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, OutputLevel=VERBOSE)) + + trackerAlignDBTool = CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, + OutputLevel=VERBOSE, + AlignmentConstants = {}) + kwargs.setdefault("AlignDbTool", trackerAlignDBTool) + trackerAlignDBTool.AlignmentConstants = alignmentConstants a.addEventAlgo(WriteAlignmentAlg(name, **kwargs)) return a @@ -53,6 +58,10 @@ if __name__ == "__main__": ConfigFlags.IOVDb.DBConnection = "sqlite://;schema=" + ConfigFlags.GeoModel.FaserVersion + "_ALLP200.db;dbname=OFLP200" ConfigFlags.GeoModel.Align.Disable = True # Hack to avoid loading alignment when we want to create it from scratch ConfigFlags.addFlag("WriteAlignment.PoolFileName", ConfigFlags.GeoModel.FaserVersion + "_Align.pool.root") + +# Parse flags from command line and lock + ConfigFlags.addFlag("AlignDbTool.AlignmentConstants", {}) + ConfigFlags.fillFromArgs(sys.argv[1:]) ConfigFlags.lock() # Configure components @@ -60,7 +69,7 @@ if __name__ == "__main__": acc = MainServicesCfg(ConfigFlags) # Set things up to create a conditions DB with neutral Tracker alignment transforms - acc.merge(WriteAlignmentCfg(ConfigFlags, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"))) + acc.merge(WriteAlignmentCfg(ConfigFlags, alignmentConstants=ConfigFlags.AlignDbTool.AlignmentConstants, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"), )) # Configure verbosity # ConfigFlags.dump() 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-007833-00003-TrigMask08.raw b/Control/CalypsoExample/rawdata/Faser-Physics-007833-00003-TrigMask08.raw new file mode 100644 index 0000000000000000000000000000000000000000..55004da5cc7d612760d61e2fe6a7d2d9edede69a Binary files /dev/null and b/Control/CalypsoExample/rawdata/Faser-Physics-007833-00003-TrigMask08.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/Control/CalypsoExample/xAODTruthConversion/CMakeLists.txt b/Control/CalypsoExample/xAODTruthConversion/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d89706a2cc487690204f5c474fc6d3d91e533d24 --- /dev/null +++ b/Control/CalypsoExample/xAODTruthConversion/CMakeLists.txt @@ -0,0 +1,9 @@ +################################################################################ +# Package: xAODTruthConversion +################################################################################ + +# Declare the package name: +atlas_subdir( xAODTruthConversion ) + +# Install files from the package: +atlas_install_scripts( scripts/*.py ) diff --git a/Control/CalypsoExample/xAODTruthConversion/scripts/runTruthCnv.py b/Control/CalypsoExample/xAODTruthConversion/scripts/runTruthCnv.py new file mode 100644 index 0000000000000000000000000000000000000000..b51b4d4ba059d571921fe6328e13144ccf104f23 --- /dev/null +++ b/Control/CalypsoExample/xAODTruthConversion/scripts/runTruthCnv.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +import sys +from AthenaCommon.Constants import VERBOSE, INFO +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory + + +def GEN_AOD2xAODCfg(flags, name="GEN_AOD2xAOD", **kwargs): + acc = ComponentAccumulator() + + # Use digiSteeringConf from metadata to write full-PU truth + # Not available yet in metadata + + # from PyUtils.MetaReader import read_metadata + # infile = flags.Input.Files[0] + # thisFileMD = read_metadata(infile, None, 'full') + # metadata = thisFileMD[infile] + # digiSteeringConf = metadata['/Digitization/Parameters'].get("digiSteeringConf","") + # if digiSteeringConf == 'StandardInTimeOnlyGeantinoTruthPileUpToolsAlg': + # writeInTimePileUpTruth = True + + kwargs.setdefault('WriteTruthMetaData', False) + kwargs.setdefault('AODContainerName', 'TruthEvent') + kwargs.setdefault('EventInfo','McEventInfo') + + algo = CompFactory.xAODMaker.xAODTruthCnvAlg(name, **kwargs) + acc.addEventAlgo(algo, primary = True) + + from OutputStreamAthenaPool.OutputStreamConfig import addToESD,addToAOD + toAOD = ["xAOD::TruthEventContainer#*", "xAOD::TruthEventAuxContainer#*", + "xAOD::TruthVertexContainer#*", "xAOD::TruthVertexAuxContainer#*", + "xAOD::TruthParticleContainer#*", "xAOD::TruthParticleAuxContainer#*"] + toESD = [] + + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + if flags.Output.doWriteESD: + acc.merge(OutputStreamCfg(flags, "ESD", ItemList=toESD+toAOD, disableEventTag=True)) + if flags.Output.doWriteAOD: + acc.merge(OutputStreamCfg(flags, "AOD", ItemList=toAOD)) + return acc + + +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.Input.Files = ['my.HITS.pool.root'] + ConfigFlags.Output.doWriteAOD = True + ConfigFlags.Output.doWriteESD = False + ConfigFlags.Output.AODFileName = "my.AOD.pool.root" + + ConfigFlags.lock() + +# Configure components + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + acc = MainServicesCfg(ConfigFlags) + + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + acc.merge(PoolReadCfg(ConfigFlags)) + + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + acc.merge(PoolWriteCfg(ConfigFlags)) + +# Set up algorithms + + acc.merge(GEN_AOD2xAODCfg(ConfigFlags)) + + from xAODEventInfoCnv.xAODEventInfoCnvConfig import EventInfoCnvAlgCfg + acc.merge(EventInfoCnvAlgCfg(ConfigFlags, disableBeamSpot=True)) + + if ConfigFlags.Output.doWriteAOD: + ostream = acc.getEventAlgo("OutputStreamAOD") + else: + ostream = acc.getEventAlgo("OutputStreamESD") + + ostream.ItemList += ["xAOD::EventInfo#EventInfo","xAOD::EventAuxInfo#EventInfoAux."] + + algo = CompFactory.xAODReader.xAODTruthReader("TruthReader") + acc.addEventAlgo(algo) + +# 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/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml index 5b309fd7cccc278ab1f10a2010bbdaaea3eaf124..958fb2ba600c0384381a06460487cb5e83efac98 100644 --- a/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml +++ b/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml @@ -21,5 +21,19 @@ <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" /> </logicalservice> + <logicalservice name="COOLOFL_TDAQ"> + <service name="sqlite_file:data/sqlite200/CABP200.db" accessMode="read" /> + <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/CABP200.db" accessMode="read" /> + </logicalservice> + + <logicalservice name="COOLOFL_INDET"> + <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" /> + <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" /> + </logicalservice> + +<logicalservice name="COOLOFL_TRIGGER"> + <service name="sqlite_file:data/sqlite200/ALLP200.db" accessMode="read" /> + <service name="sqlite_file:///cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db" accessMode="read" /> +</logicalservice> </servicelist> diff --git a/Derviation/DerivationAlgs/CMakeLists.txt b/Derviation/DerivationAlgs/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5ef7b4b3e64410b5db7c39a08bbd16acec22562 --- /dev/null +++ b/Derviation/DerivationAlgs/CMakeLists.txt @@ -0,0 +1,15 @@ +################################################################################ +# Package: DerivationAlgs +################################################################################ + +# Declare the package name: +atlas_subdir( DerivationAlgs ) + +atlas_add_component( DerivationAlgs + src/*.cxx src/*.h + src/components/*.cxx + LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel StoreGateLib DerivationToolsLib) + +atlas_install_python_modules( python/*.py ) + + diff --git a/Derviation/DerivationAlgs/python/DerivationAlgsConfig.py b/Derviation/DerivationAlgs/python/DerivationAlgsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..a38fb966c9bcfb155b7a7951386988a4fff3235b --- /dev/null +++ b/Derviation/DerivationAlgs/python/DerivationAlgsConfig.py @@ -0,0 +1,79 @@ +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + +def DerivationAlgCfg(flags, stream, tools, **kwargs): + + acc = ComponentAccumulator() + + kwargs.setdefault("Tools", tools) + ##print ("SETTING", kwargs["Tools"], type(kwargs["Tools"][0])) + acc.addEventAlgo(CompFactory.Derive(stream + "_DerivationAlg", **kwargs)) + + return acc + +def DerivationOutputCfg(flags, stream, accept, items = [], extra_items = [], exclude_items = [], **kwargs): + + acc = ComponentAccumulator() + + if not items: + items = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + , "FaserSiHitCollection#*" # Strip hits, do we want this? + , "FaserSCT_RDO_Container#*" + , "xAOD::WaveformHitContainer#*" + , "xAOD::WaveformHitAuxContainer#*" + , "xAOD::WaveformClock#*" + , "xAOD::WaveformClockAuxInfo#*" + ] + + if not items and extra_items: + items.append(extra_items) + + # from PrimaryDPDMaker/python/Primary_DPD_OutputDefinitions.py in athena + # Once can use TakeItemsFromInput = True probably need to use + # acc.getEventAlgo(f"OutputStream{stream}").RemoveItem(exclude_list) + exclude_list = [] + if exclude_items: + for ex in exclude_items: + if ex in items: + exclude_list.append(ex) + + if ex.endswith("*"): + for it in items: + if it.startswith(ex.rstrip("*")): + exclude_list.append(it) + + # items = list(set(items) - set(exclude_list)) + + + #flags.unlock() + #flags.addFlag(f"Output.AOD{stream}FileName", f"my.{stream}.xAOD.root") + #flags.lock() + + acc.merge(OutputStreamCfg(flags, stream, items)) + acc.getEventAlgo(f"OutputStream{stream}").AcceptAlgs = [accept] + ## if not items: + ##acc.getEventAlgo(f"OutputStream{stream}").TakeItemsFromInput = True # crashes + ## if extra_items: + ##cc.getEventAlgo(f"OutputStream{stream}").RemoveItem(extra_items) + ## if exclude_list: + ##acc.getEventAlgo(f"OutputStream{stream}").AddItem(exclude_list) + + return acc + +def FullyConfiguredStream(flags, stream, tools, items = [], extra_items = [], **kwargs): + # TODO: + # - get items from input + why crash + + acc = ComponentAccumulator() + + acc.merge(DerivationAlgCfg(flags, stream, tools, **kwargs)) + acc.merge(DerivationOutputCfg(flags, stream, stream + "_DerivationAlg", items, extra_items)) + + return acc + + + diff --git a/Derviation/DerivationAlgs/share/runDerive.py b/Derviation/DerivationAlgs/share/runDerive.py new file mode 100644 index 0000000000000000000000000000000000000000..b8b22c187c15a39993a68aa722e5d6bae3362f7b --- /dev/null +++ b/Derviation/DerivationAlgs/share/runDerive.py @@ -0,0 +1,147 @@ + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + + +def DerivationAlgCfg(flags, name, frac, **kwargs): + + acc = ComponentAccumulator() + + tool = CompFactory.ExampleDerivationTool(name + "_TestTool", SaveFraction = frac) + print ("ZEBRA", tool.SaveFraction) + + kwargs.setdefault("Tools", [tool]) + acc.addEventAlgo(CompFactory.Derive(name, **kwargs)) + + return acc + +def DerivationAlgCfg2(flags, name, **kwargs): + + acc = ComponentAccumulator() + + tool = CompFactory.TriggerStreamTool(name + "_TriggerSteamTool") + kwargs.setdefault("Tools", [tool]) + acc.addEventAlgo(CompFactory.Derive(name, **kwargs)) + + return acc + + +if __name__ == "__main__": + + 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 + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + ConfigFlags.Input.Files = [ + "/eos/experiment/faser/rec/2022/p0008/007984/Faser-Physics-007984-00000-p0008-xAOD.root" + #"/bundle/data/FASER/Ti12data/filter/r0008/007983/Faser-Physics-007983-TrigMask08-r0008-xAOD.root" + ] + + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + 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 = "FASERNU-03" # FASER geometry + ConfigFlags.Common.isOnline = False + ConfigFlags.GeoModel.Align.Dynamic = False + ConfigFlags.Beam.NumberOfCollisions = 0. + + ConfigFlags.Detector.GeometryFaserSCT = True + + ConfigFlags.addFlag("Output.AODSTREAM1FileName", "my.STREAM1.xAOD.root") + ConfigFlags.addFlag("Output.AODSTREAM2FileName", "my.STREAM2.xAOD.root") + ConfigFlags.addFlag("Output.AODSTREAM3FileName", "my.STREAM3.xAOD.root") + #ConfigFlags.Output.STREAM1FileName = fileName + + ConfigFlags.lock() + + # Core components + cfg = MainServicesCfg(ConfigFlags) + cfg.merge(PoolReadCfg(ConfigFlags)) + cfg.merge(PoolWriteCfg(ConfigFlags)) + + # Derivation alg + cfg.merge(DerivationAlgCfg(ConfigFlags, "DerivationAlg1", 10)) + cfg.merge(DerivationAlgCfg(ConfigFlags, "DerivationAlg2", 90)) + cfg.merge(DerivationAlgCfg2(ConfigFlags, "DerivationAlg3")) + + # Writing + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + streamName1 = "AODSTREAM1" # Needs to have AOD in name + itemList1 = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + , "FaserSiHitCollection#*" # Strip hits, do we want this? + , "FaserSCT_RDO_Container#*" + , "xAOD::WaveformHitContainer#*" + , "xAOD::WaveformHitAuxContainer#*" + , "xAOD::WaveformClock#*" + , "xAOD::WaveformClockAuxInfo#*" +# , "FaserSCT_SpacePointContainer#*" # Crashes +# , "Tracker::FaserSCT_ClusterContainer#*" +# , "TrackCollection#*" + ] + + cfg.merge(OutputStreamCfg(ConfigFlags, streamName1, itemList1)) #, disableEventTag = True)) + cfg.getEventAlgo("OutputStreamAODSTREAM1").AcceptAlgs = ["DerivationAlg1"] + #cfg.getEventAlgo("OutputStreamAODSTREAM1").TakeItemsFromInput = True + + + # Writing + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + streamName2 = "AODSTREAM2" # Needs to have AOD in name + itemList2 = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + ] + cfg.merge(OutputStreamCfg(ConfigFlags, streamName2, itemList2)) #, disableEventTag = True)) + cfg.getEventAlgo("OutputStreamAODSTREAM2").AcceptAlgs = ["DerivationAlg2"] + + # Writing + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + streamName3 = "AODSTREAM3" # Needs to have AOD in name + itemList3 = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + ] + cfg.merge(OutputStreamCfg(ConfigFlags, streamName3, itemList3)) #, disableEventTag = True)) + cfg.getEventAlgo("OutputStreamAODSTREAM3").AcceptAlgs = ["DerivationAlg3"] + + + +# from OutputStreamAthenaPool.MultipleStreamManager import MSMgr +# streamName = "STREAM1" +# fileName = "streaming.STREAM1.root" +# testStream = MSMgr.NewPoolRootStream(streamName, fileName) +# testStream.AcceptAlgs(["DerivationAlg1"]) +# cfg.addEventAlgo(testStream) + +# # 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 + + # Execute and finish + cfg.printConfig() + + + sc = cfg.run(maxEvents=1000) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/Derviation/DerivationAlgs/share/run_streaming.py b/Derviation/DerivationAlgs/share/run_streaming.py new file mode 100644 index 0000000000000000000000000000000000000000..3ebacb7892ab51e1d2b5c775bae917dd9e4fa6c3 --- /dev/null +++ b/Derviation/DerivationAlgs/share/run_streaming.py @@ -0,0 +1,94 @@ +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +if __name__ == "__main__": + + 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 FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + ConfigFlags.Input.Files = [ + "/eos/experiment/faser/rec/2022/p0008/007984/Faser-Physics-007984-00000-p0008-xAOD.root" + ] + + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + 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 = "FASERNU-03" # FASER geometry + ConfigFlags.Common.isOnline = False + ConfigFlags.GeoModel.Align.Dynamic = False + ConfigFlags.Beam.NumberOfCollisions = 0. + + ConfigFlags.Detector.GeometryFaserSCT = True + + for stream in ["STREAM1", "STREAM2", "STREAM3"]: + ConfigFlags.addFlag(f"Output.AOD{stream}FileName", f"my.{stream}.xAOD.root") + + ConfigFlags.lock() + + # Core components + cfg = MainServicesCfg(ConfigFlags) + cfg.merge(PoolReadCfg(ConfigFlags)) + cfg.merge(PoolWriteCfg(ConfigFlags)) + cfg.merge(FaserGeometryCfg(ConfigFlags)) + + # Derivations + + from DerivationAlgs.DerivationAlgsConfig import FullyConfiguredStream + + name = "STREAM1" + + + cfg.merge(FullyConfiguredStream(ConfigFlags, stream = name, + tools = [CompFactory.ExampleDerivationTool(name + "_TestTool", SaveFraction = 10.)]) + ) + + name = "STREAM2" + cfg.merge(FullyConfiguredStream(ConfigFlags, stream = name, + tools = [ CompFactory.ExampleDerivationTool(name + "_TestTool", SaveFraction = 90.)], + items = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + ]) + ) + + name = "STREAM3" + cfg.merge(FullyConfiguredStream(ConfigFlags, stream = name, + tools = [CompFactory.TriggerStreamTool(name + "_TriggerTool")], + items = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + ]) + ) + + + # Hack to avoid problem with our use of MC databases when isMC = False + replicaSvc = cfg.getService("DBReplicaSvc") + replicaSvc.COOLSQLiteVetoPattern = "" + replicaSvc.UseCOOLSQLite = True + replicaSvc.UseCOOLFrontier = False + replicaSvc.UseGeomSQLite = True + + # Execute and finish + cfg.printConfig(withDetails = True, summariseProps = True, printDefaults = True) + + + sc = cfg.run(maxEvents=1000) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/Derviation/DerivationAlgs/src/Derive.cxx b/Derviation/DerivationAlgs/src/Derive.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b34492787d313c955bff97b12c82fb402cdbc98f --- /dev/null +++ b/Derviation/DerivationAlgs/src/Derive.cxx @@ -0,0 +1,53 @@ +#include "Derive.h" + + +Derive::Derive(const std::string& name, + ISvcLocator* pSvcLocator) + : AthFilterAlgorithm(name, pSvcLocator) { + + //declareProperty("Tools", m_tools); + +} + +StatusCode +Derive::initialize() { + ATH_MSG_INFO(name() << "::initalize()" ); + + ATH_CHECK( m_tools.retrieve() ); + return StatusCode::SUCCESS; +} + +StatusCode +Derive::finalize() { + ATH_MSG_INFO(name() << "::finalize()"); + ATH_MSG_INFO("Derivation" << name() << " accepted " << m_passed << " out of " << m_events << " events"); + + return StatusCode::SUCCESS; +} + +StatusCode +Derive::execute() { + ATH_MSG_DEBUG("Executing ... "); + + m_events++; + + bool acceptEvent(true); + + for (auto& tool : m_tools) { + + // Skimming - remove events + if (!tool->passed()) acceptEvent = false; + + // Thinning - remove info from event + ATH_CHECK(tool->removeBranch()); + + // Augmenting - add info to an event + ATH_CHECK(tool->addBranch()); + + } + + setFilterPassed(acceptEvent); + if (acceptEvent) m_passed++; + + return StatusCode::SUCCESS; +} diff --git a/Derviation/DerivationAlgs/src/Derive.h b/Derviation/DerivationAlgs/src/Derive.h new file mode 100644 index 0000000000000000000000000000000000000000..03b971dd0852e54ea7a90e5ffb1135aedcba07a7 --- /dev/null +++ b/Derviation/DerivationAlgs/src/Derive.h @@ -0,0 +1,64 @@ +#ifndef DERIVATIONALGS_DERIVE_H +#define DERIVATIONALGS_DERIVE_H + +// Base class +#include "AthenaBaseComps/AthFilterAlgorithm.h" + +// FASER +#include "DerivationTools/IDerivationTool.h" + +// Gaudi +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/IAlgTool.h" + +// Athena +#include "xAODEventInfo/EventInfo.h" +#include "StoreGate/ReadHandleKey.h" + +// ROOT +#include <TRandom3.h> + +// STL + +class Derive : public AthFilterAlgorithm { + +public: + // Constructor + Derive(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~Derive() = default; + + /** @name Usual algorithm methods */ + //@{ + virtual StatusCode initialize() override; + virtual StatusCode execute() override; + virtual StatusCode finalize() override; + //@} + + + private: + + /** @name Disallow default instantiation, copy, assignment */ + //@{ + Derive() = delete; + Derive(const Derive&) = delete; + Derive &operator=(const Derive&) = delete; + //@} + + /// + + /** @name Steerable tools */ + //@ + ToolHandleArray<IDerivationTool> m_tools {this, "Tools", {}, "List of tools"}; + //@} + + /** Number of events processed */ + int m_events {0}; + + /** Number of events selected */ + int m_passed {0}; + +}; + + +#endif // DERIVATIONALGS_DERIVE_H diff --git a/Derviation/DerivationAlgs/src/components/DerivationAlgs_entries.cxx b/Derviation/DerivationAlgs/src/components/DerivationAlgs_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c46a518fefa207cc65c90781eb1660a9438c8e32 --- /dev/null +++ b/Derviation/DerivationAlgs/src/components/DerivationAlgs_entries.cxx @@ -0,0 +1,3 @@ +#include "../Derive.h" + +DECLARE_COMPONENT( Derive ) diff --git a/Derviation/DerivationTools/CMakeLists.txt b/Derviation/DerivationTools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c167cb1598233f25fb51a5bcbea28c6f17a22c40 --- /dev/null +++ b/Derviation/DerivationTools/CMakeLists.txt @@ -0,0 +1,24 @@ +################################################################################ +# Package: DerivationTools +################################################################################ + +# Declare the package name: +atlas_subdir( DerivationTools ) + +# External dependencies: +find_package( ROOT ) + +# Component(s) in the package: +atlas_add_library( DerivationToolsLib + DerivationTools/*.h src/*.cxx src/*.h + PUBLIC_HEADERS DerivationTools + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES AthenaBaseComps AthenaKernel xAODFaserTrigger + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} + ) + +atlas_add_component( DerivationTools + src/components/*.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps GaudiKernel xAODEventInfo xAODFaserTrigger DerivationToolsLib) + diff --git a/Derviation/DerivationTools/DerivationTools/IDerivationTool.h b/Derviation/DerivationTools/DerivationTools/IDerivationTool.h new file mode 100644 index 0000000000000000000000000000000000000000..29970fe09230f02c11aea8b5c8663540bc8312fc --- /dev/null +++ b/Derviation/DerivationTools/DerivationTools/IDerivationTool.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** + * @file IDerivationTool.h + * Header file for the IDerivationTool class + * @author Carl Gwilliam, 2021 + */ + + +#ifndef DERIVATIONTOOLS_IDERIVATIONTOOL_H +#define DERIVATIONTOOLS_IDERIVATIONTOOL_H + +// Gaudi +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/ToolHandle.h" + + +///Interface for derivation tools +class IDerivationTool : virtual public IAlgTool +{ +public: + + // InterfaceID + DeclareInterfaceID(IDerivationTool, 1, 0); + + virtual ~IDerivationTool() = default; + + // Apply skimming + virtual bool passed() = 0; + + /// Apply thinning + virtual StatusCode removeBranch() = 0; + + /// Apply augmentation + virtual StatusCode addBranch() = 0; + + +private: + // None + +}; + + + + +#endif //DERIVATIONTOOLS_IDERIVATIONTOOL_H diff --git a/Derviation/DerivationTools/src/ExampleDerivationTool.cxx b/Derviation/DerivationTools/src/ExampleDerivationTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6f27c1861eba2d5ac40c617dc8ed17be2085b80b --- /dev/null +++ b/Derviation/DerivationTools/src/ExampleDerivationTool.cxx @@ -0,0 +1,48 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** + * @file ExamplederivationTool.cxx + * Implementation file for the ExamplederivationTool class + * @ author C. Gwilliam, 2021 + **/ + +#include "ExampleDerivationTool.h" + +// Constructor +ExampleDerivationTool::ExampleDerivationTool(const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ + //std::cout << "CTOR " << name << " with SaveFraction = " << m_fraction << std::endl; +} + +// Initialization +StatusCode +ExampleDerivationTool::initialize() { + ATH_MSG_INFO( name() << "::initalize()" ); + //std::cout << "INIT " << name() << " with SaveFraction = " << m_fraction << std::endl; + + return StatusCode::SUCCESS; +} + +bool +ExampleDerivationTool::passed(){ + + bool accept(false); + + m_events++; + + float frac = ((float)(m_passed+1))/(float)m_events * 100.0; + + if (frac > m_fraction) { + ATH_MSG_DEBUG("Filter failed " << m_passed << " " << m_events << " " << frac << " " << m_fraction); + accept = false; + } else { + ATH_MSG_DEBUG("Filter passed " << m_passed << " " << m_events << " " << frac << " " << m_fraction); + accept = true; + m_passed++; + } + + return accept; +} diff --git a/Derviation/DerivationTools/src/ExampleDerivationTool.h b/Derviation/DerivationTools/src/ExampleDerivationTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d89657fff0d590ec21320d318d3123a5553fd307 --- /dev/null +++ b/Derviation/DerivationTools/src/ExampleDerivationTool.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** @file TriggerStreamTool.h + * Header file for TriggerStreamTool.h + * + */ +#ifndef DERIVATIONTOOLS_EXAMPLEDERIVATIONTOOL_H +#define DERIVATIONTOOLS_EXAMPLEDERIVATIONTOOL_H + +//Athena +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationTools/IDerivationTool.h" + +//Gaudi +#include "GaudiKernel/ToolHandle.h" + +//STL + +class ExampleDerivationTool: public extends<AthAlgTool, IDerivationTool> { + public: + + /// Normal constructor for an AlgTool; 'properties' are also declared here + ExampleDerivationTool(const std::string& type, + const std::string& name, const IInterface* parent); + + /// Retrieve the necessary services in initialize + StatusCode initialize(); + + // Apply skimming + bool passed(); + + /// Apply thinning + StatusCode removeBranch() {return StatusCode::SUCCESS;} + + /// Apply augmentation + StatusCode addBranch() {return StatusCode::SUCCESS;} + + private: + + /** Fraction of events to save */ + Gaudi::Property<float> m_fraction {this, "SaveFraction", 100, "Fraction of events to save"}; + + /** Number of events processed */ + int m_events {0}; + + /** Number of events selected */ + int m_passed {0}; + +}; + +#endif // WAVEDIGITOOLS_WAVEFORMDIGITISATIONTOOL_H diff --git a/Derviation/DerivationTools/src/TriggerStreamTool.cxx b/Derviation/DerivationTools/src/TriggerStreamTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8345766320effb1ea0cac4fa1e70d155e407c069 --- /dev/null +++ b/Derviation/DerivationTools/src/TriggerStreamTool.cxx @@ -0,0 +1,35 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** + * @file TriggerStreamTool.cxx + * Implementation file for the TriggerStreamTool class + * @ author C. Gwilliam, 2021 + **/ + +#include "TriggerStreamTool.h" + +// Constructor +TriggerStreamTool::TriggerStreamTool(const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +// Initialization +StatusCode +TriggerStreamTool::initialize() { + ATH_MSG_INFO( name() << "::initalize() with mask = " << m_mask ); + + ATH_CHECK( m_triggerDataKey.initialize() ); + + return StatusCode::SUCCESS; +} + +bool +TriggerStreamTool::passed() { + + SG::ReadHandle<xAOD::FaserTriggerData> triggerData(m_triggerDataKey); + + return triggerData->tap() & m_mask; +} diff --git a/Derviation/DerivationTools/src/TriggerStreamTool.h b/Derviation/DerivationTools/src/TriggerStreamTool.h new file mode 100644 index 0000000000000000000000000000000000000000..bb229f60418707c2ad56eae717b7e0daca6dc26e --- /dev/null +++ b/Derviation/DerivationTools/src/TriggerStreamTool.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** @file TriggerStreamTool.h + * Header file for TriggerStreamTool.h + * + */ +#ifndef DERIVATIONTOOLS_TRIGGERSTREAMTOOL_H +#define DERIVATIONTOOLS_TRIGGERSTREAMTOOL_H + + +// FASER +#include "StoreGate/ReadHandleKey.h" +#include "xAODFaserTrigger/FaserTriggerData.h" + +//Athena +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationTools/IDerivationTool.h" + +//Gaudi +#include "GaudiKernel/ToolHandle.h" + +//STL + +class TriggerStreamTool: public extends<AthAlgTool, IDerivationTool> { + public: + + /// Normal constructor for an AlgTool; 'properties' are also declared here + TriggerStreamTool(const std::string& type, + const std::string& name, const IInterface* parent); + + /// Retrieve the necessary services in initialize + StatusCode initialize(); + + // Apply skimming + bool passed(); + + /// Apply thinning + StatusCode removeBranch() {return StatusCode::SUCCESS;} + + /// Apply augmentation + StatusCode addBranch() {return StatusCode::SUCCESS;} + + private: + + /** Trigger condition to apply */ + Gaudi::Property<int> m_mask {this, "TriggerMask", 0x8, "Trigger mask to apply"}; + + /// StoreGate key + SG::ReadHandleKey<xAOD::FaserTriggerData> m_triggerDataKey + { this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"}; + +}; + +#endif // WAVEDIGITOOLS_WAVEFORMDIGITISATIONTOOL_H diff --git a/Derviation/DerivationTools/src/components/DerivationTools_entries.cxx b/Derviation/DerivationTools/src/components/DerivationTools_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..91e58e594e7864bd61ddf7d196f1625d361a4c8b --- /dev/null +++ b/Derviation/DerivationTools/src/components/DerivationTools_entries.cxx @@ -0,0 +1,5 @@ +#include "../TriggerStreamTool.h" +#include "../ExampleDerivationTool.h" + +DECLARE_COMPONENT( TriggerStreamTool ) +DECLARE_COMPONENT( ExampleDerivationTool ) 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..fbee2144d985412d2624d31e745eec881f3fb54d 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, @@ -85,7 +95,9 @@ def _setupGeoModel(): # Deal with SCT alignment conditions folders and algorithms - conddb.addFolderSplitOnline("SCT","/Tracker/Onl/Align","/Tracker/Align",className="AlignableTransformContainer") + #conddb.addFolderSplitOnline("SCT","/Tracker/Onl/Align","/Tracker/Align",className="AlignableTransformContainer") + print("Override Alignment dbname to OFLP200, fix this when alignment available in CONDBR3") + conddb.addFolder("/Tracker/Align", "SCT_OFL",className="AlignableTransformContainer") from AthenaCommon.AlgSequence import AthSequencer condSeq = AthSequencer("AthCondSeq") if not hasattr(condSeq, "FaserSCT_AlignCondAlg"): @@ -112,6 +124,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..853e44f446950dcae32da726ed391f82df56ee98 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,"Trench", "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..2c32f3f63b25a4ae8d1aed8f37f6f887eff38a03 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.cxx @@ -213,37 +213,39 @@ StatusCode RDBMaterialManager::readMaterialsFromDB(ISvcLocator* pSvcLocator) if(m_sctmaterials->size()==0) { if(log.level()<=MSG::WARNING) log << MSG::WARNING << " Getting SCTMaterials with default tag" <<endmsg; - m_trackermaterials = iAccessSvc->getRecordsetPtr("SCTMaterials","SCTMaterials-00", "", "FASERDD"); + m_sctmaterials = 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; } @@ -442,13 +444,13 @@ GeoMaterial* RDBMaterialManager::getMaterial(const std::string & name) { tmp_matcomponents = m_scintmatcomponents; data_id = "SCINTMATERIALS_DATA_ID"; } - else if(name.find("tracker",0) == 0) - { - detector = "tracker"; - tmp_materials = m_trackermaterials; - tmp_matcomponents = m_trackermatcomponents; - data_id = "TRACKERMATERIALS_DATA_ID"; - } + // else if(name.find("tracker",0) == 0) + // { + // detector = "tracker"; + // tmp_materials = m_trackermaterials; + // tmp_matcomponents = m_trackermatcomponents; + // data_id = "TRACKERMATERIALS_DATA_ID"; + // } else if(name.find("sct",0) == 0) { detector = "sct"; @@ -457,13 +459,13 @@ GeoMaterial* RDBMaterialManager::getMaterial(const std::string & name) { data_id = "SCTMATERIALS_DATA_ID"; } - else if(name.find("calo",0) == 0) - { - detector = "calo"; - tmp_materials = m_calomaterials; - tmp_matcomponents = m_calomatcomponents; - data_id = "CALOMATERIALS_DATA_ID"; - } + // else if(name.find("calo",0) == 0) + // { + // detector = "calo"; + // tmp_materials = m_calomaterials; + // tmp_matcomponents = m_calomatcomponents; + // data_id = "CALOMATERIALS_DATA_ID"; + // } else {return 0 ;} for( ind = 0; ind < tmp_materials->size(); ind++) @@ -623,13 +625,13 @@ const GeoMaterial* RDBMaterialManager:: getMaterial(const std::string &name) co tmp_matcomponents = m_scintmatcomponents; data_id = "SCINTMATERIALS_DATA_ID"; } - else if(name.find("tracker",0) == 0) - { - detector = "tracker"; - tmp_materials = m_trackermaterials; - tmp_matcomponents = m_trackermatcomponents; - data_id = "TRACKERMATERIALS_DATA_ID"; - } + // else if(name.find("tracker",0) == 0) + // { + // detector = "tracker"; + // tmp_materials = m_trackermaterials; + // tmp_matcomponents = m_trackermatcomponents; + // data_id = "TRACKERMATERIALS_DATA_ID"; + // } else if(name.find("sct",0) == 0) { detector = "sct"; @@ -637,13 +639,13 @@ const GeoMaterial* RDBMaterialManager:: getMaterial(const std::string &name) co tmp_matcomponents = m_sctmatcomponents; data_id = "SCTMATERIALS_DATA_ID"; } - else if(name.find("calo",0) == 0) - { - detector = "calo"; - tmp_materials = m_calomaterials; - tmp_matcomponents = m_calomatcomponents; - data_id = "CALOMATERIALS_DATA_ID"; - } + // else if(name.find("calo",0) == 0) + // { + // detector = "calo"; + // tmp_materials = m_calomaterials; + // tmp_matcomponents = m_calomatcomponents; + // data_id = "CALOMATERIALS_DATA_ID"; + // } else {return 0 ;} for( ind = 0; ind < tmp_materials->size(); ind++) diff --git a/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.h b/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.h index 4e64f5dccf0b837d3093e7245dc09eb298a6b5d0..49bafe149abb22395efada29bde49c23c7c8c67a 100644 --- a/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.h +++ b/DetectorDescription/GeoModel/GeoModelSvc/src/RDBMaterialManager.h @@ -87,12 +87,12 @@ class RDBMaterialManager: public StoredMaterialManager { IRDBRecordset_ptr m_neutrinomatcomponents; IRDBRecordset_ptr m_scintmaterials; IRDBRecordset_ptr m_scintmatcomponents; - IRDBRecordset_ptr m_trackermaterials; - IRDBRecordset_ptr m_trackermatcomponents; + // IRDBRecordset_ptr m_trackermaterials; + // IRDBRecordset_ptr m_trackermatcomponents; IRDBRecordset_ptr m_sctmaterials; IRDBRecordset_ptr m_sctmatcomponents; - IRDBRecordset_ptr m_calomaterials; - IRDBRecordset_ptr m_calomatcomponents; + // IRDBRecordset_ptr m_calomaterials; + // IRDBRecordset_ptr m_calomatcomponents; mutable std::vector < GeoElement *> m_elementVector; mutable StoredMaterialManager::MaterialMap m_materialMap; diff --git a/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py b/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py index e2315ae1c6f5ff50b973e6c08377a3cee9da9ef4..5da32c10e6281b4d8547923fd8e5f71095c7e409 100644 --- a/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py +++ b/Event/FaserByteStreamCnvSvc/python/FaserByteStreamCnvSvcConfig.py @@ -50,6 +50,10 @@ def FaserByteStreamCnvSvcCfg(configFlags, **kwargs): from WaveByteStream.WaveByteStreamConfig import WaveByteStreamCfg result.merge(WaveByteStreamCfg(configFlags)) +# Configure TrackerByteStream converter + from TrackerByteStream.TrackerByteStreamConfig import TrackerByteStreamCfg + result.merge(TrackerByteStreamCfg(configFlags)) + # Load ByteStreamEventStorageInputSvc bsInputSvc = CompFactory.FaserByteStreamInputSvc result.addService(bsInputSvc(name = "FaserByteStreamInputSvc")) 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/FaserCosmicGenerator/README.md b/Generators/FaserCosmicGenerator/README.md index 512c32c60d6d875dba083a0fc2e5dc34e7dc8499..49199a3cef6173c5f4fed4c41de452ef7713c6ff 100644 --- a/Generators/FaserCosmicGenerator/README.md +++ b/Generators/FaserCosmicGenerator/README.md @@ -2,7 +2,7 @@ ## Setup -In Athena 22.0.40, the scipy module is missing from the LCG environment for some reason. +In Athena 22.0.49, the scipy module is missing from the LCG environment for some reason. To use the generator, the following command is required after the usual steps to setup the release: diff --git a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py index f5ba68bcba67791b3d7fa6792518ba74b90d1bb6..ac30494a4815f5bb06a5d67408b4c0551297a63b 100644 --- a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py +++ b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py @@ -12,6 +12,10 @@ from AthenaConfiguration.ComponentFactory import CompFactory from AthenaCommon.SystemOfUnits import TeV from AthenaCommon.PhysicalConstants import pi +### add radial pos sampler ### with gaussian beam implemented +from FaserParticleGun.RadialPosSampler import RadialPosSampler + + def FaserParticleGunCommonCfg(ConfigFlags, **kwargs) : cfg = ComponentAccumulator(AthSequencer("AthBeginSeq", Sequential = True)) @@ -34,18 +38,53 @@ def FaserParticleGunSingleParticleCfg(ConfigFlags, **kwargs) : pg = cfg.getPrimary() + pg.sampler.n = kwargs.setdefault("n", 1) pg.sampler.pid = kwargs.setdefault("pid", -13) pg.sampler.mom = PG.EThetaMPhiSampler(energy = kwargs.setdefault("energy", 1*TeV), 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), + + 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 + +def FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs) : + cfg = FaserParticleGunCommonCfg(ConfigFlags, **kwargs) + + pg = cfg.getPrimary() + + pg.sampler.pid = kwargs.setdefault("pid", 13) + pg.sampler.mom = PG.EThetaMPhiSampler(energy = kwargs.setdefault("energy", 1*TeV), + theta = kwargs.setdefault("theta", 0.0), + phi = kwargs.setdefault("phi", 0.0), + mass = kwargs.setdefault("mass", 105.7) ) + + if "radius" in kwargs: + pg.sampler.pos = RadialPosSampler(x = kwargs.setdefault("x", 0.0), + y = kwargs.setdefault("y", 0.0), + z = kwargs.setdefault("z", 0.0), + r = kwargs.setdefault("radius", 1.0), + t = kwargs.setdefault("t", 0.0) ) + else: + pg.sampler.pos = PG.PosSampler(x = kwargs.setdefault("x", 0.0), + y = kwargs.setdefault("y", 0.0), + z = kwargs.setdefault("z", 0.0), t = kwargs.setdefault("t", 0.0) ) return cfg +''' def FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs) : cfg = FaserParticleGunCommonCfg(ConfigFlags, **kwargs) @@ -62,7 +101,7 @@ def FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs) : t = kwargs.setdefault("t", 0.0) ) return cfg - +''' def FaserParticleGunCosmicsCfg(ConfigFlags, **kwargs) : # Supported keyword arguments: # @@ -109,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) @@ -118,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..4cc449e65e7a8285db742e1d05516ddd0915b206 --- /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, weights = np.array(self.before["w"])/self.nsamples, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["E"], bins = ebins, weights = np.array(self.after["w"])/self.nsamples, 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, weights = np.array(self.before["w"])/self.nsamples, histtype='step', color = "g", fill = False, label = "before") + plt.hist(thetaXout, bins = tbins, weights = np.array(self.after["w"])/self.nsamples, 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, weights = np.array(self.before["w"])/self.nsamples, histtype='step', color = "g", fill = False, label = "before") + plt.hist(thetaYout, bins = tbins, weights = np.array(self.after["w"])/self.nsamples, 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, weights = np.array(self.before["w"])/self.nsamples, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["x"], bins = xbins, weights = np.array(self.after["w"])/self.nsamples, 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, weights = np.array(self.before["w"])/self.nsamples, histtype='step', color = "g", fill = False, label = "before") + plt.hist(self.after["y"], bins = xbins, weights = np.array(self.after["w"])/self.nsamples, 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..8170bbd33b732f1972d3fbdedea626c61948d95d --- /dev/null +++ b/Generators/ForeseeGenerator/python/Validate.py @@ -0,0 +1,260 @@ +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() + elif i == 0 and p.end_vertex(): + llp_vtx = p.end_vertex().point3d() + + if p.production_vertex(): + vertices.append(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..f02f4311f69d07a29a2de4bf26ac2ee93ea13206 --- /dev/null +++ b/Generators/ForeseeGenerator/share/generate_forsee_events.py @@ -0,0 +1,416 @@ +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 = 2 # 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.] + ) + + self.model.set_br_1d( + modes = [self.mode], + filenames=[f"files/models/{self.modelname}/br/{self.mode}.txt"] + ) + + 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, + ) + + self.model.set_br_1d( + modes = ["e_e", "mu_mu"], + finalstates = [[11, -11], [13, -13]], + filenames=["model/br/e_e.txt", "model/br/mu_mu.txt"], + #filenames=[f"model/br/all.txt"] + ) + + 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, + ) + + if self.version == 1: + self.model.set_br_1d( + modes = [self.mode], + filenames=[f"files/models/{self.modelname}/br/{self.mode}.txt"] + ) + else: + self.model.set_br_1d( + modes = ["gamma_gamma"], + finalstates = [[22, 22]], + filenames=["model/br/gamma_gamma.txt"] + #filenames=[f"model/br/all.txt"] + ) + + 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 + ) + else: + self.model.set_ctau_1d( + filename=f"model/ctau.txt", + coupling_ref=1 + ) + + # 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 = -1.5, seed = self.seed, decaychannels = [self.mode]) + + cfgname = f"{self.foresee.dirpath}/Models/{self.modelname}/" + filename.replace(".hepmc", ".cfg") + print(f"save config to file: {cfgname}") + with open(cfgname, "w") as f: + f.write(" ".join(sys.argv)) + + return + + +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: + if len(data) == 1: + couplings = float(data[0]) + else: + sys.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, args.hepmc) + + 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/GenieReader/CMakeLists.txt b/Generators/GenieReader/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e2fddd3866d318e776ba8417f1694413dcb1cac8 --- /dev/null +++ b/Generators/GenieReader/CMakeLists.txt @@ -0,0 +1,11 @@ +################################################################################ +# Package: ReadGenie +################################################################################ + +# Declare the package name: +atlas_subdir( GenieReader ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + +atlas_install_joboptions( share/*.py ) \ No newline at end of file diff --git a/Generators/GenieReader/python/GenieReaderAlg.py b/Generators/GenieReader/python/GenieReaderAlg.py new file mode 100644 index 0000000000000000000000000000000000000000..c97ea494b089a25ff88e4c2a1f2abdd4bf472c6b --- /dev/null +++ b/Generators/GenieReader/python/GenieReaderAlg.py @@ -0,0 +1,76 @@ +# 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 AthenaPython.PyAthena import StatusCode, EventInfo, EventID, EventType +from AthenaCommon.SystemOfUnits import GeV, m +import ROOT + +__author__ = "Dave Caser <dcasper@uci.edu>" + +class GenieReader(EvgenAlg): + def __init__(self, name="GenieReader", MCEventKey="BeamTruthEvent"): + super(GenieReader,self).__init__(name=name) + self.McEventKey = MCEventKey + return + + def fillEvent(self, evt): + try: + from AthenaPython.PyAthena import HepMC3 as HepMC + except ImportError: + from AthenaPython.PyAthena import HepMC as HepMC + evt.weights().push_back(1.0) + + treeEventInfo = self.evtStore["TTreeEventInfo"] + treeEventId = treeEventInfo.event_ID() + runNumber = treeEventId.run_number() + eventNumber = treeEventId.event_number() + # print("found run/event number ", runNumber, "/", eventNumber) + + mcEventType = EventType() + mcEventType.add_type(EventType.IS_SIMULATION) + + mcEventId = EventID(run_number = runNumber, event_number = eventNumber) + 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) + + pos = HepMC.FourVector(self.evtStore["vx"]*m, self.evtStore["vy"]*m, self.evtStore["vz"]*m, 0) + gv = HepMC.GenVertex(pos) + ROOT.SetOwnership(gv, False) + evt.add_vertex(gv) + + nParticles = self.evtStore["n"] + pdgc = list(self.evtStore["pdgc"]) + status = list(self.evtStore["status"]) + px = list(self.evtStore["px"]) + py = list(self.evtStore["py"]) + pz = list(self.evtStore["pz"]) + E = list(self.evtStore["E"]) + M = list(self.evtStore["M"]) + + for i in range(nParticles): + gp = HepMC.GenParticle() + mom = HepMC.FourVector(px[i]*GeV, py[i]*GeV, pz[i]*GeV, E[i]*GeV) + gp.set_momentum(mom) + gp.set_generated_mass(M[i]*GeV) + gp.set_pdg_id(pdgc[i]) + genie_status = status[i] + if (genie_status == 0): # initial particle + hepmc_status = 4 + elif (genie_status == 1): # stable final particle + hepmc_status = 1 + elif (genie_status == 3): # decayed particle + hepmc_status = 2 + else: # catch-all informational particle + hepmc_status = 3 + gp.set_status(hepmc_status) + ROOT.SetOwnership(gp, False) + if (hepmc_status == 4): + gv.add_particle_in(gp) + else: + gv.add_particle_out(gp) + + return StatusCode.Success diff --git a/Generators/GenieReader/python/__init__.py b/Generators/GenieReader/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d13ae164caa4e93bf2899cea4e67d0ec515784a2 --- /dev/null +++ b/Generators/GenieReader/python/__init__.py @@ -0,0 +1 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration diff --git a/Generators/GenieReader/share/GenieReader_jobOptions.py b/Generators/GenieReader/share/GenieReader_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..649e705b66eb05f7b5ac2b331890a914794bec60 --- /dev/null +++ b/Generators/GenieReader/share/GenieReader_jobOptions.py @@ -0,0 +1,40 @@ +# +# Usage: athena.py -c'INPUT=["faser.1.gfaser.root","faser.2.gfaser.root"]; OUTPUT="gFaser.EVNT.pool.root"; EVTMAX=100' GenieReader/GenieReader_jobOptions.py >& GenieReader.log +# +# INPUT and OUTPUT are mandatory (INPUT can be a list, as shown above) +# EVTMAX can be omitted; then all input files are read to the end +# + +if not 'INPUT' in dir(): + print("Missing INPUT parameter") + exit() + +if not isinstance(INPUT, (list,tuple)): + INPUT = [INPUT] + pass + +if not 'OUTPUT' in dir(): + print("Missing OUTPUT parameter") + exit() + +import AthenaRootComps.ReadAthenaRoot + +svcMgr.EventSelector.InputCollections = INPUT +svcMgr.EventSelector.TupleName = "gFaser" + +from GenieReader.GenieReaderAlg import GenieReader + +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() +job += GenieReader() + +from AthenaPoolCnvSvc.WriteAthenaPool import AthenaPoolOutputStream +ostream = AthenaPoolOutputStream( "StreamEVGEN" , OUTPUT, noTag=True ) +ostream.ItemList.remove("EventInfo#*") +ostream.ItemList += [ "EventInfo#McEventInfo", + "McEventCollection#*" ] +print(ostream.ItemList) +if not 'EVTMAX' in dir(): + EVTMAX = -1 + +theApp.EvtMax = EVTMAX 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..affee04ea519250ba08f5c32c4b6596a3422fab6 --- /dev/null +++ b/Generators/HEPMCReader/python/HepMCReaderConfig.py @@ -0,0 +1,76 @@ +#!/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/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx index 36ff6569e3c56cd9551bae75145d1c3d5a610f2e..715a49b37efc4f942c879339debf9f67993aef39 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx @@ -4,6 +4,7 @@ #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" #include "NeutrinoHitCollectionCnv.h" @@ -18,12 +19,16 @@ NeutrinoHitCollection_PERS* NeutrinoHitCollectionCnv::createPersistent(NeutrinoH NeutrinoHitCollection* NeutrinoHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "NeutrinoHitCollectionConverter" ); NeutrinoHitCollectionCnv_p1 converter_p1; + NeutrinoHitCollectionCnv_p1a converter_p1a; static const pool::Guid p1_guid("2CA7AF71-1494-4378-BED4-AFB5C54398AA"); - // static const pool::Guid p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779"); + static const pool::Guid p1a_guid("0A3CD37D-64CE-405D-98CF-595D678B14B7"); NeutrinoHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { + if( this->compareClassGuid(p1a_guid)) { + std::unique_ptr< NeutrinoHitCollection_p1a > col_vect( this->poolReadObject< NeutrinoHitCollection_p1a >() ); + trans_cont = converter_p1a.createTransient( col_vect.get(), mlog ); + } else if( this->compareClassGuid(p1_guid)) { std::unique_ptr< NeutrinoHitCollection_p1 > col_vect( this->poolReadObject< NeutrinoHitCollection_p1 >() ); trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); } else { diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h index 5ccd3e1bb8675b5f5542032781af7d737aa1a378..a8158c01a6ef7b93b6e32915d758aa9bcad984ed 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h @@ -6,14 +6,14 @@ #define NEUTRINOHITCOLLECTIONCNV #include "NeutrinoSimEvent/NeutrinoHitCollection.h" -#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h" -#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef NeutrinoHitCollection_p1 NeutrinoHitCollection_PERS; -typedef NeutrinoHitCollectionCnv_p1 NeutrinoHitCollectionCnv_PERS; +typedef NeutrinoHitCollection_p1a NeutrinoHitCollection_PERS; +typedef NeutrinoHitCollectionCnv_p1a NeutrinoHitCollectionCnv_PERS; class NeutrinoHitCollectionCnv : public T_AthenaPoolCustomCnv<NeutrinoHitCollection, NeutrinoHitCollection_PERS > { friend class CnvFactory<NeutrinoHitCollectionCnv>; diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt index defef98b76adfaf00e4b4c1da37c685cee6e2d7c..332a16c77b33035a064668b13fe3fe41ad4061ff 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/CMakeLists.txt @@ -22,5 +22,5 @@ atlas_add_dictionary( NeutrinoSimEventTPCnvDict NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h NeutrinoSimEventTPCnv/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv NeutrinoSimEvent TestTools StoreGateLib SGtests Identifier NeutrinoSimEventTPCnv ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv NeutrinoSimEvent TestTools StoreGateLib SGtests Identifier NeutrinoSimEventTPCnv AthenaKernel ) diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..5666f66e7e644581cc53cf2ec88a4a0f9f54fb83 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef NEUTRINOHITCOLLECTIONCNV_P1A_H +#define NEUTRINOHITCOLLECTIONCNV_P1A_H + +// NeutrinoHitCollectionCnv_p1a, T/P separation of Neutrino Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "NeutrinoSimEvent/NeutrinoHitCollection.h" +#include "NeutrinoHitCollection_p1a.h" + + +class NeutrinoHitCollectionCnv_p1a : public T_AthenaPoolTPCnvBase<NeutrinoHitCollection, NeutrinoHitCollection_p1a> +{ + public: + + NeutrinoHitCollectionCnv_p1a() {}; + + virtual NeutrinoHitCollection* createTransient(const NeutrinoHitCollection_p1a* persObj, MsgStream &log); + + virtual void persToTrans(const NeutrinoHitCollection_p1a* persCont, + NeutrinoHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const NeutrinoHitCollection* transCont, + NeutrinoHitCollection_p1a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..639ff984017e9c002a4d5317c652744751fa1f76 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef NEUTRINOHITCOLLECTION_P1A_H +#define NEUTRINOHITCOLLECTION_P1A_H + +/* + +Authors: Davide Costanzo Rob Duxfield + +*/ + +#include <vector> +#include <string> + +class NeutrinoHitCollection_p1a +{ + public: +/// Default constructor + NeutrinoHitCollection_p1a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned short> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +NeutrinoHitCollection_p1a::NeutrinoHitCollection_p1a () {} + +#endif diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h index 064ad71ac526d7f0a0d826df691f65f1ae648f98..15b7afc5bd3fc0d02690b6edbb5f6fab2012f1d5 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h @@ -15,6 +15,9 @@ #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" + #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h" #endif // NEUTRINOEVENTTPCNV_NEUTRINOSIMEVENTTPCNVDICT_H diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml index 6808c217a9a651ba26b4147a58409380ea0cc49b..3332a0a0c69d1929fd89b854102086d5b6745af0 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml @@ -4,4 +4,5 @@ <class name="NeutrinoHit_p1" /> <class name="std::vector<NeutrinoHit_p1>" /> <class name="NeutrinoHitCollection_p1" id="2CA7AF71-1494-4378-BED4-AFB5C54398AA" /> + <class name="NeutrinoHitCollection_p1a" id="0A3CD37D-64CE-405D-98CF-595D678B14B7" /> </lcgdict> diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx index 3b85676a61cd4235918207a9deb82659ed1bc5bc..444ad41777263c39b68a5e7a3cd613d787f25e32 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1.cxx @@ -14,7 +14,10 @@ #include "CLHEP/Geometry/Point3D.h" // Gaudi #include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + // Athena +#include "AthenaKernel/ExtendedEventContext.h" #include "StoreGate/StoreGateSvc.h" // * * * stolen from eflowRec * * * // @@ -60,7 +63,7 @@ const double NeutrinoHitCollectionCnv_p1::m_2bHalfMaximum = pow(2.0, 15.0); const int NeutrinoHitCollectionCnv_p1::m_2bMaximum = (unsigned short)(-1); -void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* transCont, NeutrinoHitCollection_p1* persCont, MsgStream &/*log*/) +void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* transCont, NeutrinoHitCollection_p1* persCont, MsgStream &log) { // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and // persistifies the end point of each hit plus the start point of the first hit in each string. @@ -77,6 +80,8 @@ void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* trans static const double dRcut = 1.0e-7; static const double dTcut = 1.0; + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); const HepMcParticleLink * lastLink=nullptr; int lastId = -1; double stringFirstTheta = 0.0; @@ -102,7 +107,18 @@ void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* trans lastLink = &(siHit->particleLink()); persCont->m_barcode.push_back(lastLink->barcode()); - persCont->m_mcEvtIndex.push_back(lastLink->eventIndex()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); if (idx > 0) { @@ -113,7 +129,7 @@ void NeutrinoHitCollectionCnv_p1::transToPers(const NeutrinoHitCollection* trans if ( (int)siHit->identify() != lastId ) { - // store id once for set of consecutive hits with same barcode + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode lastId = siHit->identify(); persCont->m_id.push_back(lastId); @@ -250,6 +266,8 @@ NeutrinoHitCollection* NeutrinoHitCollectionCnv_p1::createTransient(const Neutri void NeutrinoHitCollectionCnv_p1::persToTrans(const NeutrinoHitCollection_p1* persCont, NeutrinoHitCollection* transCont, MsgStream &/*log*/) { + const EventContext& ctx = Gaudi::Hive::currentContext(); + unsigned int hitCount = 0; unsigned int angleCount = 0; unsigned int idxBC = 0; @@ -299,7 +317,11 @@ void NeutrinoHitCollectionCnv_p1::persToTrans(const NeutrinoHitCollection_p1* pe HepGeom::Point3D<double> endThis( endLast + r ); - HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), HepMcParticleLink::IS_INDEX ); + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); endLast = endThis; diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6ef0bb107e46e922ad7b667bf2ae239dfe8cd695 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx @@ -0,0 +1,334 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "NeutrinoSimEvent/NeutrinoHit.h" +#include "NeutrinoSimEvent/NeutrinoHitCollection.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "AthenaKernel/ExtendedEventContext.h" +#include "StoreGate/StoreGateSvc.h" + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double NeutrinoHitCollectionCnv_p1a::m_persEneUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_persLenUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_persAngUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_2bHalfMaximum = pow(2.0, 15.0); +const int NeutrinoHitCollectionCnv_p1a::m_2bMaximum = (unsigned short)(-1); + + +void NeutrinoHitCollectionCnv_p1a::transToPers(const NeutrinoHitCollection* transCont, NeutrinoHitCollection_p1a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (NeutrinoHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + NeutrinoHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); +} + + +NeutrinoHitCollection* NeutrinoHitCollectionCnv_p1a::createTransient(const NeutrinoHitCollection_p1a* persObj, MsgStream &log) { + std::unique_ptr<NeutrinoHitCollection> trans(std::make_unique<NeutrinoHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void NeutrinoHitCollectionCnv_p1a::persToTrans(const NeutrinoHitCollection_p1a* persCont, NeutrinoHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + + if (persCont->m_nHits[i]) { + + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } +} diff --git a/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py b/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py index 391e572abaef8cc7df72ec56a692c694aab32d74..e61195b70b006059df083bb30ff93b0bd4769daf 100644 --- a/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py +++ b/Neutrino/NeutrinoG4/EmulsionG4_SD/python/EmulsionG4_SDToolConfig.py @@ -17,5 +17,7 @@ def EmulsionSensorSDCfg(ConfigFlags, name="EmulsionSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["Emulsion::FrontFilm", "Emulsion::BackFilm"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, EmulsionSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.EmulsionSensorSDTool(name, **kwargs)) + return result + diff --git a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h index 1d28bd3eab46c2d8cc82be856f3fde2aac51f8a3..2b331c5acf1e12cefa934ccf4a6e3a8b45906d0c 100644 --- a/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h +++ b/Neutrino/NeutrinoSimEvent/NeutrinoSimEvent/NeutrinoHit.h @@ -180,4 +180,4 @@ inline float hitTime(const NeutrinoHit& hit) return (float) hit.meanTime(); } -#endif // CALOSIMEVENT_CALOHIT_H +#endif // NEUTRINOSIMEVENT_NEUTRINOHIT_H diff --git a/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx b/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx index 0101b412737265fff81b6c1c3fbf467c163fdc96..2fb0fe887a9f062f25b063a50fbd90980328b312 100644 --- a/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx +++ b/Neutrino/NeutrinoSimEvent/src/NeutrinoHit.cxx @@ -149,8 +149,19 @@ int NeutrinoHit::getModule() const { void NeutrinoHit::print() const { std::cout << "*** Neutrino Hit" << std::endl; std::cout << " Module Number " << getModule() << std::endl; - std::cout << " Base Number " << getBase() << std::endl; + std::cout << " Base Number " << getBase() << std::endl; std::cout << " Film Number " << getFilm() << std::endl; + std::cout << " Energy (MeV) " << energyLoss() << std::endl; + if (particleLink().isValid()) + { + std::cout << " Barcode " << particleLink().barcode() << std::endl; + const HepMC::GenParticle* particle = (particleLink()); + std::cout << " PDG ID " << particle->pdg_id() << std::endl; + } + else + { + std::cout << "Barcode/PDG ID Unknown " << std::endl; + } } int NeutrinoHit::trackNumber() const diff --git a/PhysicsAnalysis/NeutrinoSearch/CMakeLists.txt b/PhysicsAnalysis/NeutrinoSearch/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cff2ab8575553261c18eb0736c211528e44f22bb --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(NeutrinoSearch) + +atlas_add_component( + NeutrinoSearch + src/NeutrinoSearchAlg.h + src/NeutrinoSearchAlg.cxx + src/component/NeutrinoSearch_entries.cxx + LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserWaveform ScintIdentifier FaserCaloIdentifier GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerSimData TrackerIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives TrackerRIO_OnTrack +) + +atlas_install_python_modules(python/*.py) +# atlas_install_scripts(test/*.py) diff --git a/PhysicsAnalysis/NeutrinoSearch/python/FilterSearchConfig.py b/PhysicsAnalysis/NeutrinoSearch/python/FilterSearchConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..9b76c14b8b6682b6cfe77ed3331467d4f9737cfe --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/python/FilterSearchConfig.py @@ -0,0 +1,530 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +def NeutrinoSearchAlgCfg(flags, **kwargs): + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + acc = FaserGeometryCfg(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") + + NeutrinoSearchAlg = CompFactory.NeutrinoSearchAlg("NeutrinoSearchAlg",**kwargs) + NeutrinoSearchAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(NeutrinoSearchAlg) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST2 DATAFILE='FilterSearch.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc + +if __name__ == "__main__": + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + # Configure + ConfigFlags.Input.Files = [ + '/run/media/dcasper/Data/faser/data/Faser-Physics-007613-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007705-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007720-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007725-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007728-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007729-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007730-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007733-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007734-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007802-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00032-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00034-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00036-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00038-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00039-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00040-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00041-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00042-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007833-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00032-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00034-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00036-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00038-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00039-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00040-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00041-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00042-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00044-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00045-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00046-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00047-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00048-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00049-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00050-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00051-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00052-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00053-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00054-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00055-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007835-00061-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007836-00000-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007837-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007838-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007840-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007841-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007842-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007843-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007844-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007845-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007846-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007847-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00000-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00001-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00002-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007848-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007849-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00002-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00027-TrigMask08-r0008-xAOD.root', + # '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00028-TrigMask08-r0008-xAOD.root', # not closed? + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00032-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00034-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00036-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00038-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00039-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00040-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00041-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00042-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00044-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00045-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00046-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00047-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00048-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00049-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00050-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00051-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00052-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00053-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00054-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007918-00055-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00001-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00002-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00038-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00044-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00045-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00046-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00047-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00048-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00049-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00050-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00051-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00052-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00053-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00054-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00055-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00056-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00057-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00058-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00059-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00060-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00061-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00062-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00063-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00064-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00065-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00066-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00067-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00068-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00069-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00070-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00071-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00072-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00073-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00074-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00075-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00076-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00077-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00078-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00079-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00080-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00081-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00082-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00083-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00084-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00085-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00086-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00087-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00088-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00089-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00090-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00091-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00092-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00093-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00094-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00095-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00096-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00097-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00098-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00099-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00100-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00101-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00102-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00103-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00104-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00105-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00106-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00107-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00108-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00109-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007930-00110-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00014-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00020-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00032-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00034-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00036-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00038-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00039-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00040-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00041-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00042-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00044-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00045-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00046-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00047-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007961-00048-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007972-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007973-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007974-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007975-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007976-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007977-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007978-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007979-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007980-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007981-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007982-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007983-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00000-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00001-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00002-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00005-TrigMask08-r0008-xAOD.root', + # '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00006-TrigMask08-r0008-xAOD.root', # not closed? + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007984-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00003-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00004-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00005-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00006-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00007-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00008-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00009-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00010-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00011-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00012-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00013-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00015-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00016-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00017-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00018-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00019-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00021-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00022-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00023-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00024-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00025-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00026-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00027-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00028-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00029-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00030-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00031-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00032-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00033-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00034-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00035-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00036-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00037-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00039-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00040-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00041-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00042-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00043-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00044-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00045-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00046-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00047-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00048-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00049-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00050-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00051-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00052-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00053-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00054-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00055-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00056-TrigMask08-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/data/Faser-Physics-007985-00057-TrigMask08-r0008-xAOD.root', + + + ] + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + 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 = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(NeutrinoSearchAlgCfg(ConfigFlags, UseFlukaWeights=True)) + + # # 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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/PhysicsAnalysis/NeutrinoSearch/python/FlukaSearchConfig.py b/PhysicsAnalysis/NeutrinoSearch/python/FlukaSearchConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..4e196a3794670d241bf8a26b91d409d260ac193d --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/python/FlukaSearchConfig.py @@ -0,0 +1,140 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +def NeutrinoSearchAlgCfg(flags, **kwargs): + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + acc = FaserGeometryCfg(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") + + NeutrinoSearchAlg = CompFactory.NeutrinoSearchAlg("NeutrinoSearchAlg",**kwargs) + NeutrinoSearchAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(NeutrinoSearchAlg) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST2 DATAFILE='FlukaSearch.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc + +if __name__ == "__main__": + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + # Configure + ConfigFlags.Input.Files = [ + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00000-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00001-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00002-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00003-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00004-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00005-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00006-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00007-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00008-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00009-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00010-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00011-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00012-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00013-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00014-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00015-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00016-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00017-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00018-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00019-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00020-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00021-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00022-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00023-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00024-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00025-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00026-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210001/rec/r0008/FaserMC-MDC_Fluka_unit30_Nm_71m_m3750_v3-210001-00027-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00000-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00001-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00002-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00003-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00004-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00005-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00006-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00007-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00008-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00009-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00010-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00011-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00012-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00013-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00014-s0005-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/fluka/210002/rec/r0008/FaserMC-MDC_Fluka_unit30_Pm_71m_m3750_v3-210002-00015-s0005-r0008-xAOD.root' + ] + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + ConfigFlags.Input.ProjectName = "data21" # Needed to bypass autoconfig + ConfigFlags.Input.isMC = True # Needed to bypass autoconfig + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(NeutrinoSearchAlgCfg(ConfigFlags, UseFlukaWeights=True)) + + # # 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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/PhysicsAnalysis/NeutrinoSearch/python/GenieSearchConfig.py b/PhysicsAnalysis/NeutrinoSearch/python/GenieSearchConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..a80de32bbc0643dbaca1ac12e28688535951b709 --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/python/GenieSearchConfig.py @@ -0,0 +1,104 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +def NeutrinoSearchAlgCfg(flags, **kwargs): + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + acc = FaserGeometryCfg(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") + + NeutrinoSearchAlg = CompFactory.NeutrinoSearchAlg("NeutrinoSearchAlg",**kwargs) + NeutrinoSearchAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(NeutrinoSearchAlg) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST2 DATAFILE='GenieSearch.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc + +if __name__ == "__main__": + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + # Configure + ConfigFlags.Input.Files = [ + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00000-00007-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00008-00015-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00016-00023-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00024-00031-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00032-00039-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00040-00047-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00048-00055-s0006-r0008-xAOD.root', + '/run/media/dcasper/Data/faser/genie/rec/FaserMC-MDC_Genie_all_150invfb_v1-200001-00056-00063-s0006-r0008-xAOD.root' + ] + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + ConfigFlags.Input.ProjectName = "data21" # Needed to bypass autoconfig + ConfigFlags.Input.isMC = True # Needed to bypass autoconfig + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(NeutrinoSearchAlgCfg(ConfigFlags, UseGenieWeights=True)) + + # # 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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e782dda9e3eb7d97da42edb1b5a79528268dac9f --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx @@ -0,0 +1,637 @@ +#include "NeutrinoSearchAlg.h" +#include "TrkTrack/Track.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/TriggerID.h" +#include "ScintIdentifier/PreshowerID.h" +#include "FaserCaloIdentifier/EcalID.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Identifier/Identifier.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "xAODTruth/TruthParticle.h" +#include <cmath> + + + +NeutrinoSearchAlg::NeutrinoSearchAlg(const std::string &name, + ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), + AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name) {} + + +StatusCode NeutrinoSearchAlg::initialize() +{ + ATH_CHECK(m_truthEventContainer.initialize()); + ATH_CHECK(m_truthParticleContainer.initialize()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_vetoNuContainer.initialize()); + ATH_CHECK(m_vetoContainer.initialize()); + ATH_CHECK(m_triggerContainer.initialize()); + ATH_CHECK(m_preshowerContainer.initialize()); + ATH_CHECK(m_ecalContainer.initialize()); + ATH_CHECK(m_clusterContainer.initialize()); + ATH_CHECK(m_simDataCollection.initialize()); + + ATH_CHECK(detStore()->retrieve(m_sctHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_vetoNuHelper, "VetoNuID")); + ATH_CHECK(detStore()->retrieve(m_vetoHelper, "VetoID")); + ATH_CHECK(detStore()->retrieve(m_triggerHelper, "TriggerID")); + ATH_CHECK(detStore()->retrieve(m_preshowerHelper, "PreshowerID")); + ATH_CHECK(detStore()->retrieve(m_ecalHelper, "EcalID")); + + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + ATH_CHECK(m_extrapolationTool.retrieve()); + + if (m_useFlukaWeights) + { + m_baseEventCrossSection = (m_flukaCrossSection * kfemtoBarnsPerMilliBarn)/m_flukaCollisions; + } + else if (m_useGenieWeights) + { + m_baseEventCrossSection = 1.0/m_genieLuminosity; + } + else + { + m_baseEventCrossSection = 1.0; + } + + m_tree = new TTree("tree", "tree"); + m_tree->Branch("run_number", &m_run_number, "run_number/I"); + m_tree->Branch("event_number", &m_event_number, "event_number/I"); + + m_tree->Branch("VetoNuPmt0", &m_vetoNu0, "vetoNu0/D"); + m_tree->Branch("VetoNuPmt1", &m_vetoNu1, "vetoNu1/D"); + + m_tree->Branch("VetoPmt00", &m_veto00, "veto00/D"); + m_tree->Branch("VetoPmt01", &m_veto01, "veto01/D"); + m_tree->Branch("VetoUpstream", &m_vetoUpstream, "vetoUpstream/D"); + m_tree->Branch("VetoPmt10", &m_veto10, "veto10/D"); + m_tree->Branch("VetoPmt11", &m_veto11, "veto11/D"); + m_tree->Branch("VetoDownstream", &m_vetoDownstream, "vetoDownstream/D"); + + m_tree->Branch("TriggerPmt00", &m_trigger00, "trigger00/D"); + m_tree->Branch("TriggerPmt01", &m_trigger01, "trigger01/D"); + m_tree->Branch("TriggerPmt10", &m_trigger10, "trigger10/D"); + m_tree->Branch("TriggerPmt11", &m_trigger11, "trigger11/D"); + m_tree->Branch("TriggerTotal", &m_triggerTotal, "triggerTotal/D"); + + m_tree->Branch("PreshowerPmt0", &m_preshower0, "preshower0/D"); + m_tree->Branch("PreshowerPmt1", &m_preshower1, "preshower1/D"); + + m_tree->Branch("EcalPmt00", &m_ecal00, "ecal00/D"); + m_tree->Branch("EcalPmt01", &m_ecal01, "ecal01/D"); + m_tree->Branch("EcalPmt10", &m_ecal10, "ecal10/D"); + m_tree->Branch("EcalPmt11", &m_ecal11, "ecal11/D"); + m_tree->Branch("EcalTotal", &m_ecalTotal, "ecalTotal/D"); + + m_tree->Branch("Clust0", &m_station0Clusters, "clust0/I"); + m_tree->Branch("Clust1", &m_station1Clusters, "clust0/I"); + m_tree->Branch("Clust2", &m_station2Clusters, "clust0/I"); + m_tree->Branch("Clust3", &m_station3Clusters, "clust0/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("p", &m_p, "p/D"); + m_tree->Branch("charge", &m_charge, "charge/I"); + m_tree->Branch("chi2", &m_chi2, "chi2/D"); + m_tree->Branch("ndof", &m_ndof, "ndof/I"); + m_tree->Branch("longTracks", &m_longTracks, "longTracks/I"); + m_tree->Branch("pTruthLepton", &m_truthLeptonMomentum, "pTruthLepton/D"); + m_tree->Branch("truthBarcode", &m_truthBarcode, "truthBarcode/I"); + m_tree->Branch("truthPdg", &m_truthPdg, "truthPdg/I"); + m_tree->Branch("CrossSection", &m_crossSection, "crossSection/D"); + + ATH_CHECK(histSvc()->regTree("/HIST2/tree", m_tree)); + + if (m_enforceBlinding) + { + ATH_MSG_INFO("Blinding will be enforced for real data."); + } + else + { + ATH_MSG_INFO("Blinding will NOT be enforced for real data."); + } + + return StatusCode::SUCCESS; +} + + +StatusCode NeutrinoSearchAlg::execute(const EventContext &ctx) const +{ + + clearTree(); + + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + + bool realData = true; + + // Work out effective cross section for MC + SG::ReadHandle<xAOD::TruthEventContainer> truthEventContainer { m_truthEventContainer, ctx }; + if (truthEventContainer.isValid() && truthEventContainer->size() > 0) + { + realData = false; + if (m_useFlukaWeights) + { + double flukaWeight = truthEventContainer->at(0)->weights()[0]; + ATH_MSG_ALWAYS("Found fluka weight = " << flukaWeight); + m_crossSection = m_baseEventCrossSection * flukaWeight; + } + else if (m_useGenieWeights) + { + m_crossSection = m_baseEventCrossSection; + } + else + { + ATH_MSG_WARNING("Monte carlo event with no weighting scheme specified. Setting crossSection (weight) to " << m_baseEventCrossSection << " fb."); + m_crossSection = m_baseEventCrossSection; + } + } + + // Find the primary lepton (if any) + SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainer { m_truthParticleContainer, ctx }; + if (truthParticleContainer.isValid() && truthParticleContainer->size() > 0) + { + for (auto particle : *truthParticleContainer) + { + if ( particle->absPdgId() == 11 || particle->absPdgId() == 13 || particle->absPdgId() == 15 ) + { + if (particle->status() == 1 && (particle->nParents() == 0 || particle->nParents() == 2) ) + m_truthLeptonMomentum = particle->p4().P(); + + break; + } + } + } + + SG::ReadHandle<xAOD::WaveformHitContainer> vetoNuContainer { m_vetoNuContainer, ctx }; + ATH_CHECK(vetoNuContainer.isValid()); + + // If real data, check for blinding before we do anything else + + bool blinded = realData; + for (auto hit : *vetoNuContainer) + { + if (!waveformHitOK(hit)) continue; + blinded = false; + auto id = hit->identify(); + if (m_vetoNuHelper->plate(id) == 0) + { + m_vetoNu0 += hit->integral(); + } + else if (m_vetoNuHelper->plate(id) == 1) + { + m_vetoNu1 += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid VetoNu plate number: " << m_vetoNuHelper->plate(id)); + return StatusCode::FAILURE; + } + } + + if (m_enforceBlinding && blinded) return StatusCode::SUCCESS; + + SG::ReadHandle<xAOD::WaveformHitContainer> vetoContainer { m_vetoContainer, ctx }; + ATH_CHECK(vetoContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> triggerContainer { m_triggerContainer, ctx }; + ATH_CHECK(triggerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> preshowerContainer { m_preshowerContainer, ctx }; + ATH_CHECK(preshowerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> ecalContainer { m_ecalContainer, ctx }; + ATH_CHECK(ecalContainer.isValid()); + + for (auto hit : *vetoContainer) + { + if (!waveformHitOK(hit)) continue; + auto id = hit->identify(); + auto station = m_vetoHelper->station(id); + auto plate = m_vetoHelper->plate(id); + if (station == 0) + { + if (plate == 0) + { + m_veto00 += hit->integral(); + m_vetoUpstream += hit->integral(); + } + else if (plate == 1) + { + m_veto01 += hit->integral(); + m_vetoUpstream += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Veto plate number: " << plate); + } + } + else if (station == 1) + { + if (plate == 0) + { + m_veto10 += hit->integral(); + m_vetoDownstream += hit->integral(); + } + else if (plate == 1) + { + m_veto11 += hit->integral(); + m_vetoDownstream += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Veto plate number: " << plate); + } + } + else + { + ATH_MSG_FATAL("Invalid Veto station number: " << station); + return StatusCode::FAILURE; + } + } + + for (auto hit : *triggerContainer) + { + if (!waveformHitOK(hit)) continue; + auto id = hit->identify(); + auto plate = m_triggerHelper->plate(id); + auto pmt = m_triggerHelper->pmt(id); + if (plate == 0) + { + if (pmt == 0) + { + m_trigger00 += hit->integral(); + m_triggerTotal += hit->integral(); + } + else if (pmt == 1) + { + m_trigger01 += hit->integral(); + m_triggerTotal += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Trigger pmt number: " << pmt); + } + } + else if (plate == 1) + { + if (pmt == 0) + { + m_trigger10 += hit->integral(); + m_triggerTotal += hit->integral(); + } + else if (pmt == 1) + { + m_trigger11 += hit->integral(); + m_triggerTotal += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Trigger pmt number: " << pmt); + } + } + else + { + ATH_MSG_FATAL("Invalid Trigger plate number: " << plate); + return StatusCode::FAILURE; + } + } + + for (auto hit : *preshowerContainer) + { + if (!waveformHitOK(hit)) continue; + auto id = hit->identify(); + if (m_preshowerHelper->plate(id) == 0) + { + m_preshower0 += hit->integral(); + } + else if (m_preshowerHelper->plate(id) == 1) + { + m_preshower1 += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Preshower plate number: " << m_preshowerHelper->plate(id)); + return StatusCode::FAILURE; + } + } + + for (auto hit : *ecalContainer) + { + if (!waveformHitOK(hit)) continue; + auto id = hit->identify(); + auto row = m_ecalHelper->row(id); + auto mod = m_ecalHelper->module(id); + if (row == 0) + { + if (mod == 0) + { + m_ecal00 += hit->integral(); + m_ecalTotal += hit->integral(); + } + else if (mod == 1) + { + m_ecal01 += hit->integral(); + m_ecalTotal += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Ecal module number: " << mod); + } + } + else if (row == 1) + { + if (mod == 0) + { + m_ecal10 += hit->integral(); + m_ecalTotal += hit->integral(); + } + else if (mod == 1) + { + m_ecal11 += hit->integral(); + m_ecalTotal += hit->integral(); + } + else + { + ATH_MSG_FATAL("Invalid Ecal module number: " << mod); + } + } + else + { + ATH_MSG_FATAL("Invalid Ecal row number: " << row); + return StatusCode::FAILURE; + } + } + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer { m_clusterContainer, ctx }; + ATH_CHECK(clusterContainer.isValid()); + + for (auto collection : *clusterContainer) + { + Identifier id = collection->identify(); + int station = m_sctHelper->station(id); + int clusters = (int) collection->size(); + switch (station) + { + case 0: + m_station0Clusters += clusters; + break; + case 1: + m_station1Clusters += clusters; + break; + case 2: + m_station2Clusters += clusters; + break; + case 3: + m_station3Clusters += clusters; + break; + default: + ATH_MSG_FATAL("Unknown tracker station number " << station); + break; + } + } + + + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection, ctx}; + ATH_CHECK(trackCollection.isValid()); + + const Trk::TrackParameters* candidateParameters {nullptr}; + const Trk::Track* candidateTrack {nullptr}; + + for (const Trk::Track* track : *trackCollection) + { + if (track == nullptr) continue; + std::set<int> stationMap; + std::set<std::pair<int, int>> layerMap; + + // Check for hit in the three downstream stations + for (auto measurement : *(track->measurementsOnTrack())) + { + const Tracker::FaserSCT_ClusterOnTrack* cluster = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(measurement); + if (cluster != nullptr) + { + Identifier id = cluster->identify(); + int station = m_sctHelper->station(id); + int layer = m_sctHelper->layer(id); + stationMap.emplace(station); + layerMap.emplace(station, layer); + } + } + if (stationMap.count(1) == 0 || stationMap.count(2) == 0 || stationMap.count(3) == 0) continue; + + int nLayers = std::count_if(layerMap.begin(), layerMap.end(), [](std::pair<int,int> p){return p.first != 0;}); + if (nLayers < m_minTrackerLayers) continue; + m_longTracks++; + const Trk::TrackParameters* upstreamParameters {nullptr}; + for (auto params : *(track->trackParameters())) + { + if (upstreamParameters == nullptr || params->position().z() < upstreamParameters->position().z()) upstreamParameters = params; + } + if (candidateParameters == nullptr || upstreamParameters->momentum().mag() > candidateParameters->momentum().mag()) + { + candidateParameters = upstreamParameters; + candidateTrack = track; + m_chi2 = track->fitQuality()->chiSquared(); + m_ndof = track->fitQuality()->numberDoF(); + } + } + + SG::ReadHandle<TrackerSimDataCollection> simDataCollection {m_simDataCollection, ctx}; +// ATH_MSG_INFO("SimData valid? " << simDataCollection.isValid()); + if (candidateTrack != nullptr && simDataCollection.isValid()) + { + std::map<int, float> truthMap; + for (auto measurement : *(candidateTrack->measurementsOnTrack())) + { + const Tracker::FaserSCT_ClusterOnTrack* cluster = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(measurement); + if (cluster != nullptr) + { + // ATH_MSG_INFO("ClusterOnTrack is OK"); + cluster->dump(msg()); + +// Hack to work around issue with cluster navigation + + auto idRDO = cluster->identify(); + + if (simDataCollection->count(idRDO) > 0) + { + // ATH_MSG_INFO("rdo entry found"); + const auto& simdata = simDataCollection->find(idRDO)->second; + const auto& deposits = simdata.getdeposits(); + //loop through deposits and record contributions + HepMcParticleLink primary{}; + for( const auto& depositPair : deposits) + { + // ATH_MSG_INFO("Deposit found"); + float eDep = depositPair.second; + int barcode = depositPair.first->barcode(); + // if( depositPair.second > highestDep) + // { + // highestDep = depositPair.second; + // barcode = depositPair.first->barcode(); + // primary = depositPair.first; + // depositPair.first->print(std::cout); + // ATH_MSG_INFO("pdg id "<<depositPair.first->pdg_id()); + // } + if (truthMap.count(barcode) > 0) + { + truthMap[barcode] += eDep; + } + else + { + truthMap[barcode] = eDep; + } + } + } + + + + + // // const Tracker::FaserSCT_Cluster* origCluster = dynamic_cast<const Tracker::FaserSCT_Cluster*>(cluster->prepRawData()); + // auto origCluster = cluster->prepRawData(); + // if (origCluster != nullptr) + // { + // ATH_MSG_INFO("Orig Cluster is OK"); + // auto rdoList = origCluster->rdoList(); + // for (auto idRDO : rdoList) + // { + // ATH_MSG_INFO("rdoList not empty"); + // if (simDataCollection->count(idRDO) > 0) + // { + // ATH_MSG_INFO("rdo entry found"); + // const auto& simdata = simDataCollection->find(idRDO)->second; + // const auto& deposits = simdata.getdeposits(); + // //loop through deposits and record contributions + // HepMcParticleLink primary{}; + // for( const auto& depositPair : deposits) + // { + // ATH_MSG_INFO("Deposit found"); + // float eDep = depositPair.second; + // int barcode = depositPair.first->barcode(); + // // if( depositPair.second > highestDep) + // // { + // // highestDep = depositPair.second; + // // barcode = depositPair.first->barcode(); + // // primary = depositPair.first; + // // depositPair.first->print(std::cout); + // // ATH_MSG_INFO("pdg id "<<depositPair.first->pdg_id()); + // // } + // if (truthMap.count(barcode) > 0) + // { + // truthMap[barcode] += eDep; + // } + // else + // { + // truthMap[barcode] = eDep; + // } + // } + // } + // } + // } + } + } + std::vector<std::pair<int, float>> truth(truthMap.begin(), truthMap.end()); + std::sort(truth.begin(), truth.end(), [](auto v1, auto v2) { return v1.second > v2.second; }); + if (truth.size()>0) ATH_MSG_ALWAYS("Selected track truth info:"); + for (auto v : truth) + { + auto truthParticle = (*(std::find_if(truthParticleContainer->cbegin(), truthParticleContainer->cend(), [v](const xAOD::TruthParticle* p){ return p->barcode() == v.first; }))); + if (m_truthPdg == 0) m_truthPdg = truthParticle->pdgId(); + if (m_truthBarcode == 0) m_truthBarcode = v.first; + ATH_MSG_ALWAYS("truth info: barcode = " << v.first << " ( " << truthParticle->p4().P()/1000 << " GeV/c, Id code = " << truthParticle->pdgId() << ") -> deposited energy: " << v.second/1000); + } + } + + if (candidateParameters != nullptr) + { + m_x = candidateParameters->position().x(); + m_y = candidateParameters->position().y(); + m_z = candidateParameters->position().z(); + m_px = candidateParameters->momentum().x(); + m_py = candidateParameters->momentum().y(); + m_pz = candidateParameters->momentum().z(); + m_p = sqrt(m_px * m_px + m_py * m_py + m_pz * m_pz); + m_charge = (int) candidateParameters->charge(); + } + + // Here we apply the signal selection + // Very simple/unrealistic to start + if (m_vetoUpstream == 0 || m_vetoDownstream == 0 || + m_triggerTotal == 0 || + m_preshower0 == 0 || m_preshower1 == 0 || + // m_ecalTotal == 0 || + candidateParameters == nullptr) + return StatusCode::SUCCESS; + + m_tree->Fill(); + + return StatusCode::SUCCESS; +} + + +StatusCode NeutrinoSearchAlg::finalize() +{ + return StatusCode::SUCCESS; +} + +bool NeutrinoSearchAlg::waveformHitOK(const xAOD::WaveformHit* hit) const +{ + if (hit->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED) || hit->status_bit(xAOD::WaveformStatus::SECONDARY)) return false; + return true; +} + +void +NeutrinoSearchAlg::clearTree() const +{ + m_run_number = 0; + m_event_number = 0; + m_vetoNu0 = 0; + m_vetoNu1 = 0; + m_veto00 = 0; + m_veto01 = 0; + m_veto10 = 0; + m_veto11 = 0; + m_vetoUpstream = 0; + m_vetoDownstream = 0; + m_trigger00 = 0; + m_trigger01 = 0; + m_trigger10 = 0; + m_trigger11 = 0; + m_triggerTotal = 0; + m_preshower0 = 0; + m_preshower1 = 0; + m_ecal00 = 0; + m_ecal01 = 0; + m_ecal10 = 0; + m_ecal11 = 0; + m_ecalTotal = 0; + m_station0Clusters = 0; + m_station1Clusters = 0; + m_station2Clusters = 0; + m_station3Clusters = 0; + m_crossSection = 0; + m_chi2 = 0; + m_ndof = 0; + m_px = 0; + m_py = 0; + m_pz = 0; + m_p = 0; + m_charge = 0; + m_x = 0; + m_y = 0; + m_z = 0; + m_longTracks = 0; + m_truthLeptonMomentum = 0; + m_truthBarcode = 0; + m_truthPdg = 0; +} \ No newline at end of file diff --git a/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.h b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..d1732eb1238a15bb7b2fb397869b3c4486aa50b3 --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.h @@ -0,0 +1,136 @@ +#ifndef NEUTRINOSEARCH_NEUTRINOSEARCHALG_H +#define NEUTRINOSEARCH_NEUTRINOSEARCHALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrkTrack/TrackCollection.h" +#include "xAODFaserWaveform/WaveformHitContainer.h" +#include "xAODFaserWaveform/WaveformHit.h" +#include "xAODTruth/TruthEventContainer.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" + + +class TTree; +class FaserSCT_ID; +class VetoNuID; +class VetoID; +class TriggerID; +class PreshowerID; +class EcalID; +namespace TrackerDD +{ + class SCT_DetectorManager; +} + +class NeutrinoSearchAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + NeutrinoSearchAlg(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~NeutrinoSearchAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + + bool waveformHitOK(const xAOD::WaveformHit* hit) const; + void clearTree() const; + + ServiceHandle <ITHistSvc> m_histSvc; + + SG::ReadHandleKey<xAOD::TruthEventContainer> m_truthEventContainer { this, "EventContainer", "TruthEvents", "Truth event container name." }; + SG::ReadHandleKey<xAOD::TruthParticleContainer> m_truthParticleContainer { this, "ParticleContainer", "TruthParticles", "Truth particle container name." }; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollection {this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + + SG::ReadHandleKey<TrackCollection> m_trackCollection { this, "TrackCollection", "CKFTrackCollection", "Input track collection name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_vetoNuContainer { this, "VetoNuContainer", "VetoNuWaveformHits", "VetoNu hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_vetoContainer { this, "VetoContainer", "VetoWaveformHits", "Veto hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_triggerContainer { this, "TriggerContainer", "TriggerWaveformHits", "Trigger hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_preshowerContainer { this, "PreshowerContainer", "PreshowerWaveformHits", "Preshower hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_ecalContainer { this, "EcalContainer", "CaloWaveformHits", "Ecal hit container name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainer { this, "ClusterContainer", "SCT_ClusterContainer", "Tracker cluster container name" }; + + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { this, "ExtrapolationTool", "FaserActsExtrapolationTool" }; + const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr}; + + const FaserSCT_ID* m_sctHelper; + const VetoNuID* m_vetoNuHelper; + const VetoID* m_vetoHelper; + const TriggerID* m_triggerHelper; + const PreshowerID* m_preshowerHelper; + const EcalID* m_ecalHelper; + + // TODO: use realistic thresholds for MIP +// DoubleProperty m_vetoNuThreshold { this, "VetoNuThreshold", 0, "Threshold for VetoNu pmts" }; +// DoubleProperty m_vetoThreshold { this, "VetoThreshold", 0, "Threshold for Veto pmts" }; +// DoubleProperty m_triggerThreshold { this, "TriggerThreshold", 0, "Threshold for Trigger pmts" }; +// DoubleProperty m_preshowerThreshold { this, "PreshowerThreshold", 0, "Threshold for Preshower pmts" }; +// DoubleProperty m_ecalThreshold { this, "EcalThreshold", 0, "Threshold for Ecal pmts" }; + IntegerProperty m_minTrackerLayers { this, "MinTrackerLayers", 7, "Minimum number of layers with hits on track" }; + + BooleanProperty m_useFlukaWeights { this, "UseFlukaWeights", false, "Flag to weight events according to value stored in HepMC::GenEvent" }; + BooleanProperty m_useGenieWeights { this, "UseGenieWeights", false, "Flag to weight events according to Genie luminosity" }; + IntegerProperty m_flukaCollisions { this, "FlukaCollisions", 137130000, "Number of proton-proton collisions in FLUKA sample." }; + DoubleProperty m_flukaCrossSection { this, "FlukaCrossSection", 80.0, "Fluka p-p inelastic cross-section in millibarns." }; + DoubleProperty m_genieLuminosity { this, "GenieLuminosity", 150.0, "Genie luminosity in inverse fb." }; + +// BooleanProperty m_enforceBlinding { this, "EnforceBlinding", true, "Ignore data events with no VetoNu signals." }; + const bool m_enforceBlinding {true}; + + double m_baseEventCrossSection {1.0}; + const double kfemtoBarnsPerMilliBarn {1.0e12}; + + mutable TTree* m_tree; + mutable unsigned int m_run_number; + mutable unsigned int m_event_number; + mutable double m_vetoNu0; + mutable double m_vetoNu1; + mutable double m_veto00; + mutable double m_veto01; + mutable double m_vetoUpstream; + mutable double m_veto10; + mutable double m_veto11; + mutable double m_vetoDownstream; + mutable double m_trigger00; + mutable double m_trigger01; + mutable double m_trigger10; + mutable double m_trigger11; + mutable double m_triggerTotal; + mutable double m_preshower0; + mutable double m_preshower1; + mutable double m_ecal00; + mutable double m_ecal01; + mutable double m_ecal10; + mutable double m_ecal11; + mutable double m_ecalTotal; + mutable int m_station0Clusters; + mutable int m_station1Clusters; + mutable int m_station2Clusters; + mutable int m_station3Clusters; + + 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 double m_p; + mutable int m_charge; + mutable double m_chi2; + mutable int m_ndof; + mutable int m_longTracks; + mutable double m_truthLeptonMomentum; + mutable int m_truthBarcode; + mutable int m_truthPdg; + mutable double m_crossSection; + +}; + +inline const ServiceHandle <ITHistSvc> &NeutrinoSearchAlg::histSvc() const { + return m_histSvc; +} + +#endif // NEUTRINOSEARCH_NEUTRINOSEARCHALG_H diff --git a/PhysicsAnalysis/NeutrinoSearch/src/component/NeutrinoSearch_entries.cxx b/PhysicsAnalysis/NeutrinoSearch/src/component/NeutrinoSearch_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d47072b60eb09ca5e38a86763f85ff0c5bc36e94 --- /dev/null +++ b/PhysicsAnalysis/NeutrinoSearch/src/component/NeutrinoSearch_entries.cxx @@ -0,0 +1,3 @@ +#include "../NeutrinoSearchAlg.h" + +DECLARE_COMPONENT(NeutrinoSearchAlg) \ No newline at end of file diff --git a/PhysicsAnalysis/NtupleDumper/CMakeLists.txt b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..944ed9689053915dd526251fabf1c5b1af5dfa4e --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(NtupleDumper) + +atlas_add_component( + NtupleDumper + src/NtupleDumperAlg.h + src/NtupleDumperAlg.cxx + src/component/NtupleDumper_entries.cxx + LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserWaveform xAODFaserTrigger ScintIdentifier FaserCaloIdentifier GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerSimData TrackerIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives TrackerRIO_OnTrack TrackerSpacePoint +) + +atlas_install_python_modules(python/*.py) +atlas_install_scripts(scripts/*.py) diff --git a/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py b/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..5bc52c41df03c934465f97658a39aeb342350631 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py @@ -0,0 +1,104 @@ +""" + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + +def NtupleDumperAlgCfg(flags, **kwargs): + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + acc = FaserGeometryCfg(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") + + NtupleDumperAlg = CompFactory.NtupleDumperAlg("NtupleDumperAlg",**kwargs) + NtupleDumperAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(NtupleDumperAlg) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += ["HIST2 DATAFILE='Data-tuple.root' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc + +if __name__ == "__main__": + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + # Set up logging and new style config + log.setLevel(INFO) + Configurable.configurableRun3Behavior = True + + # Configure + ConfigFlags.Input.Files = [ + '/eos/experiment/faser/rec/2022/p0008//008119/Faser-Physics-008119-00168-p0008-xAOD.root', + + + ] + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + 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 = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(NtupleDumperAlgCfg(ConfigFlags, UseFlukaWeights=True)) + + # silencio + AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr() + AthenaEventLoopMgr.EventPrintoutInterval=500 + acc.addService(AthenaEventLoopMgr) + + # # 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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/PhysicsAnalysis/NtupleDumper/scripts/analyzeNtuple.py b/PhysicsAnalysis/NtupleDumper/scripts/analyzeNtuple.py new file mode 100755 index 0000000000000000000000000000000000000000..7d735f1599e455001162fff0e5a33acad16d2e35 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/analyzeNtuple.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +# Set up (Py)ROOT. +import ROOT +import glob +import sys +import pandas as pd + + +# Define a Landau convoluted with a gaussian for MIP fitting +landguas_conv = ROOT.TF1Convolution("landau","gaus",-10,100,True) # the functions have to be close to zero at min and max bin of convolution or else circular Fourier transform will move convolve values at max and min +landguas_conv.SetNofPointsFFT(10000) +landgaus = ROOT.TF1("landgaus",landguas_conv, -10, 100, landguas_conv.GetNpar()) +landgaus.SetParNames("Landau constant","Landau MPV","Landau width","Gaussian mean","Gaussian width") + +user_input = str(sys.argv[1]) # set to either 'all_high', 'all_low', or a run number + +t = ROOT.TChain("nt") +nfiles = 0 +all_run_paths = glob.glob("/eos/project/f/faser-commissioning/DeionsNtuples/*") + +if user_input=="all_high": + runconfig = "High_gain" + print("processing high-gain runs") + gain = 30.0 + for run_path in all_run_paths: + nfiles += t.Add(run_path+"/Data-tuple-High_gain*.root") # chain all ntuples from all runs that are high gain + rootFile = ROOT.TFile("/eos/project/f/faser-commissioning/DeionsNtuples/7930/Data-tuple-High_gain-007930-00000-100.root"); # load file from largest high gain run to get noise histograms +elif user_input=="all_low": + runconfig = "Low_gain" + print("processing low-gain runs") + gain = 1.0 + for run_path in all_run_paths: + nfiles += t.Add(run_path+"/Data-tuple-Low_gain*.root") # chain all ntuples from all runs that are high gain + rootFile = ROOT.TFile("/eos/project/f/faser-commissioning/DeionsNtuples/8137/Data-tuple-Low_gain-008137-00000-100.root"); # load file from largest low gain run to get noise histograms +else: # assume user_input is a run number + # get run configuration from table oon Brian's website + table_runs = pd.read_html('http://aagaard.web.cern.ch/aagaard/FASERruns.html') # load in run tables from website + df = table_runs[0] # table_runs is a list of all tables on the website, we only want the first one + runconfig=str(df.at[df.loc[df['Run'] == int(user_input)].index[0],'Configuration'].replace(' ','_')) # get config from website run log telling if run is High_gain or Low_gain calo + print("processing run "+runconfig+" ("+runconfig+")") + if runconfig=="High_gain": + gain = 30.0 + elif runconfig=="Low_gain": + gain = 1.0 + else: + print("run config is neither 'High_gain' nor 'Low_gain', calo histogram ranges may be messed up") + gain = 1.0 # assume low gain + + nfiles += t.Add("/eos/project/f/faser-commissioning/DeionsNtuples/"+user_input+"/*.root") # chain all ntuples from all runs that are high gain + rootFile = ROOT.TFile("/eos/project/f/faser-commissioning/DeionsNtuples/"+user_input+"/Data-tuple-"+runconfig+"-00"+user_input+"-00000-100.root"); # load file from largest low gain run to get noise histograms + + + + +print("number of files chained together = ",nfiles) + +#ROOT.gROOT.SetStyle("ATLAS") +#ROOT.gStyle.SetOptStat(111110) #take away option box in histograms +#ROOT.gStyle.SetOptTitle(1) +#ROOT.gStyle.SetOptFit(1) + +# Define histograms here +hCaloCharge = [] +hCaloPeak = [] +hXYvsEcalo = [] +for chan in range(4): + hCaloCharge.append(ROOT.TH1F("hCalo"+str(chan)+"charge", "Charge in calo ch"+str(chan)+";Q (pC);# of events",100,0.2*gain,2.0*gain)) + hCaloPeak.append(ROOT.TH1F("hCalo"+str(chan)+"peak", "Peak in calo ch"+str(chan)+";peak (mV);# of events",100,1.0*gain,5.0*gain)) + hXYvsEcalo.append(ROOT.TProfile2D("hXYvsEcalo"+str(chan)+"" , "Calo ch"+str(chan)+" Charge vs Pos;X pos (mm);Y pos (mm)",26, -130.0, 130.0, 26, -130.0, 130.0)) + +hCaloChargeTotal = ROOT.TH1F("hCaloChargeTotal", "Charge in Calo;Charge (pC);# of events",100,0.2*gain,2.0*gain) +hCaloEdep = ROOT.TH1F("hCaloEdep", "Edep in Calo;Edep (GeV);# of events",100,0.0,1.8) + +hCaloThetaX = ROOT.TH1F("hCaloThetaX", "Track #theta_{x} at Calo face;#theta_{x} (radians);# of tracks",100,-0.1,0.1) +hCaloThetaY = ROOT.TH1F("hCaloThetaY", "Track #theta_{y} at Calo face;#theta_{y} (radians);# of tracks",100,-0.1,0.1) + +hTrackPvsPYdiff = ROOT.TProfile("hTrackPvsPYdiff" , "Track #Deltap_{Y}/p vs p;Track p (MeV);(pY_{upstream} - pY_{downstream}) / p_{total}",100, 1000.0, 200000.0) +hTrackPvsPXdiff = ROOT.TProfile("hTrackPvsPXdiff" , "Track #Deltap_{X}/p vs p;Track p (MeV);(pX_{upstream} - pX_{downstream}) / p_{total}",100, 1000.0, 200000.0) + +#t.Print() # will show you all variables in ttree + +i = 0 +for event in t: + i += 1 + + if i%1000 == 0: + print( "Processing event #%i of %i" % (i, t.GetEntries() ) ) + + if event.longTracks > 0: # only process events with at least one track that has hits in last 3 tracking stations + for j in range(event.longTracks): # loop over all long tracks in the event (long = has hits in last 3 tracking stations) + if event.Track_p0[j] != 0.0: + hTrackPvsPYdiff.Fill(event.Track_p0[j],(event.Track_py0[j] - event.Track_py1[j])/event.Track_p0[j]) + hTrackPvsPXdiff.Fill(event.Track_p0[j],(event.Track_px0[j] - event.Track_px1[j])/event.Track_p0[j]) + + #print("track charge = %i and nLayers = %i" % (event.Track_charge[j],event.Track_nLayers[j])) + #print("track upstream (x,y,z) (px,py,pz) = (%f,%f,%f) (%f,%f,%f)" % (event.Track_x0[j],event.Track_y0[j],event.Track_z0[j],event.Track_px0[j],event.Track_py0[j],event.Track_pz0[j])) + #print("track downstream (x,y,z) (px,py,pz) = (%f,%f,%f) (%f,%f,%f)" % (event.Track_x1[j],event.Track_y1[j],event.Track_z1[j],event.Track_px1[j],event.Track_py1[j],event.Track_pz1[j])) + + #print("track at vetoNu (x,y) (thetaX,thetaY) = (%f,%f) (%f,%f)" % (event.Track_X_atVetoNu[j],event.Track_Y_atVetoNu[j],event.Track_ThetaX_atVetoNu[j],event.Track_ThetaY_atVetoNu[j])) + #print("track at Calo (x,y) (thetaX,thetaY) = (%f,%f) (%f,%f)" % (event.Track_X_atCalo[j],event.Track_Y_atCalo[j],event.Track_ThetaX_atCalo[j],event.Track_ThetaY_atCalo[j])) + + #print("number of track segments = ",event.TrackSegments) + #for j in range(event.TrackSegments): + #print("trackseg (x,y,z) (px,py,pz) = (%f,%f,%f) (%f,%f,%f)" % (event.TrackSegment_x[j],event.TrackSegment_y[j],event.TrackSegment_z[j],event.TrackSegment_px[j],event.TrackSegment_py[j],event.TrackSegment_pz[j])) + #print("trackseg chi2 = %i and ndof = %i" % (event.TrackSegment_Chi2[j],event.TrackSegment_nDoF[j])) + + #print("number of SpacePoints = ",event.SpacePoints) + #for j in range(event.SpacePoints): + #print("Spacepoint #",j) + #print("SpacePoint (x,y,z) = (%f,%f,%f)" % (event.SpacePoint_x[j],event.SpacePoint_y[j],event.SpacePoint_z[j])) + + hCaloEdep.Fill(event.Calo_total_Edep) + hCaloChargeTotal.Fill(event.Calo_total_charge) + + x_calo = event.Track_X_atCalo[0] + y_calo = event.Track_Y_atCalo[0] + + hCaloThetaX.Fill(event.Track_ThetaX_atCalo[0]) + hCaloThetaY.Fill(event.Track_ThetaY_atCalo[0]) + + if abs(event.Track_ThetaX_atCalo[0]) > 0.1 or abs(event.Track_ThetaX_atCalo[0]) > 0.1: continue + + for chan,charge in enumerate([event.Calo0_raw_charge,event.Calo1_raw_charge,event.Calo2_raw_charge,event.Calo3_raw_charge]): + if charge > 0.2*gain and charge < 2.0*gain: + hXYvsEcalo[chan].Fill(x_calo,y_calo,charge) + + if x_calo > -60.0 and x_calo < -20.0 and y_calo > -80.0 and y_calo < -10.0: + hCaloCharge[0].Fill(event.Calo0_raw_charge) + hCaloPeak[0].Fill(event.Calo0_raw_peak) + elif x_calo > 70.0 and x_calo < 100.0 and y_calo > -90.0 and y_calo < -10.0: + hCaloCharge[1].Fill(event.Calo1_raw_charge) + hCaloPeak[1].Fill(event.Calo1_raw_peak) + elif x_calo > -60.0 and x_calo < -20.0 and y_calo > 20.0 and y_calo < 110.0: + hCaloCharge[2].Fill(event.Calo2_raw_charge) + hCaloPeak[2].Fill(event.Calo2_raw_peak) + elif x_calo > 70.0 and x_calo < 100.0 and y_calo > 20.0 and y_calo < 110.0: + hCaloCharge[3].Fill(event.Calo3_raw_charge) + hCaloPeak[3].Fill(event.Calo3_raw_peak) + +# if i > 10000: +# break + +# create a list of histograms of random event integrals +hRandomCharge = [] +for chan in range(15): + hRandomCharge.append(rootFile.Get("hRandomCharge"+str(chan))) + +# Now make some plots +filename = "analyze-"+runconfig+"-Ntuples.pdf" + +c = ROOT.TCanvas() +c.Print(filename+'[') +hCaloEdep.Draw() +ROOT.gPad.SetLogy() +c.Print(filename) + +c = ROOT.TCanvas() +hCaloChargeTotal.Draw() +c.Print(filename) + +c = ROOT.TCanvas() +c.Divide(2,2) +for chan in range(4): + c.cd(1+chan) + hXYvsEcalo[chan].GetZaxis().SetRangeUser(hCaloCharge[chan].GetMean() - 0.3*hCaloCharge[chan].GetStdDev(),hCaloCharge[chan].GetMean() + 0.4*hCaloCharge[chan].GetStdDev()) + hXYvsEcalo[chan].Draw('COLZ') +c.Print(filename) + +leg = [] +c = ROOT.TCanvas() +c.Divide(2,2) +for chan in range(4): + c.cd(1+chan) + hCaloCharge[chan].Fit("landau") + landgaus.SetParameters(hCaloCharge[chan].GetFunction("landau").GetParameter(0),hCaloCharge[chan].GetFunction("landau").GetParameter(1),hCaloCharge[chan].GetFunction("landau").GetParameter(2),0.0,hRandomCharge[chan].GetStdDev()) + landgaus.SetParLimits(0,0.1*hCaloCharge[chan].GetFunction("landau").GetParameter(0),20.0*hCaloCharge[chan].GetFunction("landau").GetParameter(0)) + landgaus.SetParLimits(1,0.5*hCaloCharge[chan].GetFunction("landau").GetParameter(1),1.2*hCaloCharge[chan].GetFunction("landau").GetParameter(1)) + landgaus.SetParLimits(2,0.1*hCaloCharge[chan].GetFunction("landau").GetParameter(2),1.2*hCaloCharge[chan].GetFunction("landau").GetParameter(2)) + landgaus.FixParameter(3,0.0) + landgaus.FixParameter(4,hRandomCharge[chan].GetStdDev()) # fix gaussian smearing to the noise seen in randomly triggered events + hCaloCharge[chan].Fit("landgaus","+") + hCaloCharge[chan].GetFunction("landgaus").SetLineColor(4) + hCaloCharge[chan].Draw() + + leg.append( ROOT.TLegend(0.55,0.55,0.89,0.75) ) + leg[chan].AddEntry(hCaloCharge[chan].GetFunction("landau"),"Landau MPV = "+str(hCaloCharge[chan].GetFunction("landau").GetParameter(1))[:6]+" #pm "+str(hCaloCharge[chan].GetFunction("landau").GetParError(1))[:6],"L") + leg[chan].AddEntry(hCaloCharge[chan].GetFunction("landgaus"),"Landguas MPV = "+str(hCaloCharge[chan].GetFunction("landgaus").GetParameter(1))[:6]+" #pm "+str(hCaloCharge[chan].GetFunction("landgaus").GetParError(1))[:6],"L") + leg[chan].AddEntry(hCaloCharge[chan].GetFunction("landgaus"),"Landguas gaussian width = "+str(hCaloCharge[chan].GetFunction("landgaus").GetParameter(4))[:6],"") + leg[chan].SetBorderSize(0) + leg[chan].Draw() +c.Print(filename) + +leg = [] +c = ROOT.TCanvas() +c.Divide(2,2) +for chan in range(4): + c.cd(1+chan) + hCaloPeak[chan].Fit("landau") + hCaloPeak[chan].Draw() + + leg.append( ROOT.TLegend(0.55,0.55,0.89,0.75) ) + leg[chan].AddEntry(hCaloPeak[chan].GetFunction("landau"),"Landau MPV = "+str(hCaloPeak[chan].GetFunction("landau").GetParameter(1))[:6]+" #pm "+str(hCaloPeak[chan].GetFunction("landau").GetParError(1))[:6],"L") + leg[chan].SetBorderSize(0) + leg[chan].Draw() +c.Print(filename) + +c = ROOT.TCanvas() +c.Divide(1,2) +c.cd(1) +hCaloThetaX.Draw() +c.cd(2) +hCaloThetaY.Draw() +c.Print(filename) + +c = ROOT.TCanvas() +c.Divide(1,2) +c.cd(1) +hTrackPvsPYdiff.GetYaxis().SetRangeUser(hTrackPvsPYdiff.GetMean(2) - hTrackPvsPYdiff.GetStdDev(2), hTrackPvsPYdiff.GetMean(2) + hTrackPvsPYdiff.GetStdDev(2)) +hTrackPvsPYdiff.Draw() +c.cd(2) +hTrackPvsPXdiff.GetYaxis().SetRangeUser(hTrackPvsPXdiff.GetMean(2) - hTrackPvsPXdiff.GetStdDev(2), hTrackPvsPXdiff.GetMean(2) + hTrackPvsPXdiff.GetStdDev(2)) +hTrackPvsPXdiff.Draw() +c.Print(filename) + +c = ROOT.TCanvas() +c.Divide(4,4) +for chan in range(15): + c.cd(1+chan) + hRandomCharge[chan].Draw() +c.Print(filename) + +# Must close file at the end +c.Print(filename+']') + diff --git a/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py new file mode 100755 index 0000000000000000000000000000000000000000..c8ab9bb76af0be2c537fd201c6ffb2387bbbd319 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +""" + Copyright (C) 2002-2022 CERN for the benefit of the FASER collaboration +""" + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg + + +def NtupleDumperAlgCfg(flags, OutName, **kwargs): + # Initialize GeoModel + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + acc = FaserGeometryCfg(flags) + + acc.merge(MagneticFieldSvcCfg(flags)) + # acc.merge(FaserActsTrackingGeometrySvcCfg(flags)) + # acc.merge(FaserActsAlignmentCondAlgCfg(flags)) + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 10000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + + NtupleDumperAlg = CompFactory.NtupleDumperAlg("NtupleDumperAlg",**kwargs) + NtupleDumperAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(NtupleDumperAlg) + + thistSvc = CompFactory.THistSvc() + thistSvc.Output += [f"HIST2 DATAFILE='{OutName}' OPT='RECREATE'"] + acc.addService(thistSvc) + + return acc + +if __name__ == "__main__": + + import glob + import sys + import ROOT + + runno=int(sys.argv[1]) + num=int(sys.argv[2]) + filesPerJob=int(sys.argv[3]) + run_config=str(sys.argv[4]) + + ptag="p0008" + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + # Set up logging and new style config + log.setLevel(INFO) + Configurable.configurableRun3Behavior = True + + dataDir=f"/eos/experiment/faser/rec/2022/{ptag}/{runno:06d}" + files=sorted(glob.glob(f"{dataDir}/Faser-Physics*")) + fileListInitial=files[num*filesPerJob:(num+1)*filesPerJob] + fileList=[] + for fName in fileListInitial: + try: + fh=ROOT.TFile(fName) + fileList.append(fName) + except OSError: + print("Warning bad file: ",fName) + + log.info(f"Analyzing Run {runno} files {num*filesPerJob} to {(num+1)*filesPerJob} (num={num})") + log.info(f"Got {len(fileList)} files out of {len(fileListInitial)}") + + outName=f"Data-tuple-{run_config}-{runno:06d}-{num:05d}-{filesPerJob}.root" + + # Configure + ConfigFlags.Input.Files = fileList + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + 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 = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(NtupleDumperAlgCfg(ConfigFlags, outName, UseFlukaWeights=True, CaloConfig=run_config)) + + AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr() + AthenaEventLoopMgr.EventPrintoutInterval=1000 + acc.addService(AthenaEventLoopMgr) + + # # 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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.sh b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.sh new file mode 100755 index 0000000000000000000000000000000000000000..dc42bc521c678a3bed8536e93b6b68ad25549ca7 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +runno=$1 +num=$2 +filesPerJob=$3 +runconfig=$4 + +WD=$PWD + +cd /afs/cern.ch/user/d/dfellers/faser +source setup.sh +cd build +source x86_64-centos7-gcc11-opt/setup.sh +cd $WD +echo "Starting analysis" +analyzeRun.py $runno $num $filesPerJob $runconfig +cp Data-tuple*.root /eos/project/f/faser-commissioning/DeionsNtuples/$runno/ diff --git a/PhysicsAnalysis/NtupleDumper/scripts/submitAllJobsThatHaveErrorLogs.py b/PhysicsAnalysis/NtupleDumper/scripts/submitAllJobsThatHaveErrorLogs.py new file mode 100755 index 0000000000000000000000000000000000000000..5f0805b7d876e4573c5cbab096deba0364314726 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/submitAllJobsThatHaveErrorLogs.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import glob +import os +import sys +import pandas as pd + +print("NtupleDumping all condor jobs that produced non-empty error logs") + +table_runs = pd.read_html('http://aagaard.web.cern.ch/aagaard/FASERruns.html') # load in run tables from website +df = table_runs[0] # table_runs is a list of all tables on the website, we only want the first table + +# make a liist of all runs and batch job numbers that failed and thus have error logs that are not empty +run_list = [] +allErrorLogs_list = glob.glob('/afs/cern.ch/user/d/dfellers/faser/ntuple-dumper/run/logs/*/*err') +for error_log in allErrorLogs_list: + if os.path.getsize(error_log) != 0: + print('Error Log is not empty: ', error_log) + run_num = int(error_log.split('/')[-2].split('-')[-1]) + bath_num = int(error_log.split('.')[-2]) + run_list.append([run_num,bath_num]) + +print("list to be re-submitted:", run_list) + +ptag="p0008" +filesPerJob=100 + +for i,run_info in enumerate(run_list): + runno = run_info[0] + batch_number = run_info[1] + + runconfig=str(df.at[df.loc[df['Run'] == runno].index[0],'Configuration'].replace(' ','_')) # get config from website run log telling if run is High_gain or Low_gain calo + + print("%i of %i runs processed. Currently processing run %i-%i (%s)"%(i,len(run_list),runno,batch_number,runconfig)) + + batchFile=f"batch/Run-{runno:06d}-{batch_number}.sub" + fh=open(batchFile,"w") + pwd=os.getenv("PWD") + fh.write(f""" + executable = {pwd}/analyzeRun.sh + arguments = {runno} {batch_number} {filesPerJob} {runconfig} + output = {pwd}/logs/Run-{runno:06d}/batch.{batch_number}.out + error = {pwd}/logs/Run-{runno:06d}/batch.{batch_number}.err + log = {pwd}/logs/Run-{runno:06d}/batch.log + requirements = (Arch == "X86_64" && OpSysAndVer =?= "CentOS7") + getenv = False + transfer_output_files = "" + +JobFlavour = "workday" + queue 1 + """) + fh.close() + os.system(f"echo condor_submit {batchFile}") + os.system(f"condor_submit {batchFile}") diff --git a/PhysicsAnalysis/NtupleDumper/scripts/submitAllStableRuns.py b/PhysicsAnalysis/NtupleDumper/scripts/submitAllStableRuns.py new file mode 100755 index 0000000000000000000000000000000000000000..92f49d3392476a245892a5a322c8cfd5c352fde3 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/submitAllStableRuns.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +import glob +import os +import sys +import pandas as pd + +print("NtupleDumping all stable-beam runs found at http://aagaard.web.cern.ch/aagaard/FASERruns.html") + +table_runs = pd.read_html('http://aagaard.web.cern.ch/aagaard/FASERruns.html') # load in run tables from website +df = table_runs[0] # table_runs is a list of all tables on the website, we only want the first table +df.columns = [c.replace(' ', '_') for c in df.columns] # rename the columns such that names with spaces are replaced with '_' (needed to access 'Stable_Beam' column) +df.drop(df[df.Stable_Beam != 'Yes'].index, inplace=True) # drop all runs that are not stable beam runs +df.drop(df[(df.Configuration != 'Low gain') & (df.Configuration != 'High gain')].index, inplace=True) # drop all runs that are not 'Low gain' or 'High gain' + +run_list = df['Run'].tolist() + +ptag="p0008" +filesPerJob=100 + +for i,runno in enumerate(run_list): + runconfig=str(df.at[df.loc[df['Run'] == runno].index[0],'Configuration'].replace(' ','_')) # get config from website run log telling if run is High_gain or Low_gain calo + + print("%i of %i runs processed. Currently processing run %i (%s)"%(i,len(run_list),runno,runconfig)) + + os.system(f"mkdir -p logs/Run-{runno:06d}") + os.system(f"mkdir -p batch") + os.system(f"mkdir -p /eos/project/f/faser-commissioning/DeionsNtuples/{runno}") + + dataDir=f"/eos/experiment/faser/rec/2022/{ptag}/{runno:06d}" + files=glob.glob(f"{dataDir}/Faser-Physics*") + numFiles=len(files) + numJobs=numFiles//filesPerJob+(numFiles%filesPerJob!=0) + batchFile=f"batch/Run-{runno:06d}.sub" + fh=open(batchFile,"w") + pwd=os.getenv("PWD") + fh.write(f""" + executable = {pwd}/analyzeRun.sh + arguments = {runno} $(ProcId) {filesPerJob} {runconfig} + output = {pwd}/logs/Run-{runno:06d}/batch.$(ProcId).out + error = {pwd}/logs/Run-{runno:06d}/batch.$(ProcId).err + log = {pwd}/logs/Run-{runno:06d}/batch.log + requirements = (Arch == "X86_64" && OpSysAndVer =?= "CentOS7") + getenv = False + transfer_output_files = "" + +JobFlavour = "workday" + queue {numJobs} + """) + fh.close() + os.system(f"echo condor_submit {batchFile}") + os.system(f"condor_submit {batchFile}") + diff --git a/PhysicsAnalysis/NtupleDumper/scripts/submitRun.py b/PhysicsAnalysis/NtupleDumper/scripts/submitRun.py new file mode 100755 index 0000000000000000000000000000000000000000..b408759504ab5a1afc1df332154250cfcd7b4325 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/scripts/submitRun.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +import glob +import os +import sys +import pandas as pd + +table_runs = pd.read_html('http://aagaard.web.cern.ch/aagaard/FASERruns.html') # load in run tables from website +df = table_runs[0] # table_runs is a list of all tables on the website, we only want the first one + +ptag="p0008" +filesPerJob=100 + +runno=int(sys.argv[1]) +runconfig=str(df.at[df.loc[df['Run'] == runno].index[0],'Configuration'].replace(' ','_')) # get config from website run log telling if run is High_gain or Low_gain calo + +os.system(f"mkdir -p logs/Run-{runno:06d}") +os.system(f"mkdir -p batch") +os.system(f"mkdir -p /eos/project/f/faser-commissioning/DeionsNtuples/{runno}") + +dataDir=f"/eos/experiment/faser/rec/2022/{ptag}/{runno:06d}" +files=glob.glob(f"{dataDir}/Faser-Physics*") +numFiles=len(files) +numJobs=numFiles//filesPerJob+(numFiles%filesPerJob!=0) +batchFile=f"batch/Run-{runno:06d}.sub" +fh=open(batchFile,"w") +pwd=os.getenv("PWD") +fh.write(f""" +executable = {pwd}/analyzeRun.sh +arguments = {runno} $(ProcId) {filesPerJob} {runconfig} +output = {pwd}/logs/Run-{runno:06d}/batch.$(ProcId).out +error = {pwd}/logs/Run-{runno:06d}/batch.$(ProcId).err +log = {pwd}/logs/Run-{runno:06d}/batch.log +requirements = (Arch == "X86_64" && OpSysAndVer =?= "CentOS7") +getenv = False +transfer_output_files = "" ++JobFlavour = "workday" +queue {numJobs} +""") +fh.close() +os.system(f"echo condor_submit {batchFile}") + diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d1a07f428c73dfb7d6c7f1bf69ab20b73f12a196 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx @@ -0,0 +1,890 @@ +#include "NtupleDumperAlg.h" +#include "TrkTrack/Track.h" +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/TriggerID.h" +#include "ScintIdentifier/PreshowerID.h" +#include "FaserCaloIdentifier/EcalID.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "Identifier/Identifier.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "xAODTruth/TruthParticle.h" +#include <cmath> +#include <TH1F.h> + + +NtupleDumperAlg::NtupleDumperAlg(const std::string &name, + ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), + AthHistogramming(name), + m_histSvc("THistSvc/THistSvc", name) {} + + +void NtupleDumperAlg::addBranch(const std::string &name, + float* var) { + m_tree->Branch(name.c_str(),var,(name+"/F").c_str()); +} +void NtupleDumperAlg::addBranch(const std::string &name, + unsigned int* var) { + m_tree->Branch(name.c_str(),var,(name+"/I").c_str()); +} + +void NtupleDumperAlg::addWaveBranches(const std::string &name, + int nchannels, + int first) { + for(int ch=0;ch<nchannels;ch++) { + std::string base=name+std::to_string(ch)+"_"; + addBranch(base+"time",&m_wave_localtime[first]); + addBranch(base+"peak",&m_wave_peak[first]); + addBranch(base+"width",&m_wave_width[first]); + addBranch(base+"charge",&m_wave_charge[first]); + addBranch(base+"raw_peak",&m_wave_raw_peak[first]); + addBranch(base+"raw_charge",&m_wave_raw_charge[first]); + addBranch(base+"baseline",&m_wave_baseline_mean[first]); + addBranch(base+"baseline_rms",&m_wave_baseline_rms[first]); + addBranch(base+"status",&m_wave_status[first]); + first++; + } +} + +void NtupleDumperAlg::FillWaveBranches(const xAOD::WaveformHitContainer &wave) const { + for (auto hit : wave) { + if ((hit->hit_status()&2)==0) { // dont store secoondary hits as they can overwrite the primary hit + int ch=hit->channel(); + m_wave_localtime[ch]=hit->localtime()+m_clock_phase; + m_wave_peak[ch]=hit->peak(); + m_wave_width[ch]=hit->width(); + m_wave_charge[ch]=hit->integral()/50; + + m_wave_raw_peak[ch]=hit->raw_peak(); + m_wave_raw_charge[ch]=hit->raw_integral()/50; + m_wave_baseline_mean[ch]=hit->baseline_mean(); + m_wave_baseline_rms[ch]=hit->baseline_rms(); + m_wave_status[ch]=hit->hit_status(); + } + } +} + +StatusCode NtupleDumperAlg::initialize() +{ + ATH_CHECK(m_truthEventContainer.initialize()); + ATH_CHECK(m_truthParticleContainer.initialize()); + ATH_CHECK(m_trackCollection.initialize()); + ATH_CHECK(m_trackSegmentCollection.initialize()); + ATH_CHECK(m_vetoNuContainer.initialize()); + ATH_CHECK(m_vetoContainer.initialize()); + ATH_CHECK(m_triggerContainer.initialize()); + ATH_CHECK(m_preshowerContainer.initialize()); + ATH_CHECK(m_ecalContainer.initialize()); + ATH_CHECK(m_clusterContainer.initialize()); + ATH_CHECK(m_simDataCollection.initialize()); + ATH_CHECK(m_FaserTriggerData.initialize()); + ATH_CHECK(m_ClockWaveformContainer.initialize()); + + ATH_CHECK(detStore()->retrieve(m_sctHelper, "FaserSCT_ID")); + ATH_CHECK(detStore()->retrieve(m_vetoNuHelper, "VetoNuID")); + ATH_CHECK(detStore()->retrieve(m_vetoHelper, "VetoID")); + ATH_CHECK(detStore()->retrieve(m_triggerHelper, "TriggerID")); + ATH_CHECK(detStore()->retrieve(m_preshowerHelper, "PreshowerID")); + ATH_CHECK(detStore()->retrieve(m_ecalHelper, "EcalID")); + + ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT")); + ATH_CHECK(m_extrapolationTool.retrieve()); + ATH_CHECK(m_trackingGeometryTool.retrieve()); + + ATH_CHECK(m_spacePointContainerKey.initialize()); + + if (m_useFlukaWeights) + { + m_baseEventCrossSection = (m_flukaCrossSection * kfemtoBarnsPerMilliBarn)/m_flukaCollisions; + } + else if (m_useGenieWeights) + { + m_baseEventCrossSection = 1.0/m_genieLuminosity; + } + else + { + m_baseEventCrossSection = 1.0; + } + + m_tree = new TTree("nt", "NtupleDumper tree"); + m_tree->Branch("run", &m_run_number, "run/I"); + m_tree->Branch("eventID", &m_event_number, "eventID/I"); + m_tree->Branch("eventTime", &m_event_time, "eventTime/I"); + m_tree->Branch("BCID", &m_bcid, "BCID/I"); + + m_tree->Branch("TBP", &m_tbp, "TBP/I"); + m_tree->Branch("TAP", &m_tap, "TAP/I"); + m_tree->Branch("inputBits", &m_inputBits, "inputBits/I"); + m_tree->Branch("inputBitsNext", &m_inputBitsNext, "inputBitsNext/I"); + + addWaveBranches("VetoNu",2,4); + addWaveBranches("VetoSt1",2,6); + addWaveBranches("VetoSt2",1,14); + addWaveBranches("Timing",4,8); + addWaveBranches("Preshower",2,12); + addWaveBranches("Calo",4,0); + addBranch("Calo_total_charge", &m_calo_total); + addBranch("Calo_total_raw_charge", &m_calo_rawtotal); + + addBranch("Calo0_Edep", &m_Calo0_Edep); + addBranch("Calo1_Edep", &m_Calo1_Edep); + addBranch("Calo2_Edep", &m_Calo2_Edep); + addBranch("Calo3_Edep", &m_Calo3_Edep); + addBranch("Calo_total_Edep", &m_Calo_Total_Edep); + addBranch("Preshower12_Edep", &m_Preshower12_Edep); + addBranch("Preshower13_Edep", &m_Preshower13_Edep); + + addBranch("nClusters0",&m_station0Clusters); + addBranch("nClusters1",&m_station1Clusters); + addBranch("nClusters2",&m_station2Clusters); + addBranch("nClusters3",&m_station3Clusters); + + addBranch("SpacePoints",&m_nspacepoints); + m_tree->Branch("SpacePoint_x", &m_spacepointX); + m_tree->Branch("SpacePoint_y", &m_spacepointY); + m_tree->Branch("SpacePoint_z", &m_spacepointZ); + + addBranch("TrackSegments",&m_ntracksegs); + m_tree->Branch("TrackSegment_Chi2", &m_trackseg_Chi2); + m_tree->Branch("TrackSegment_nDoF", &m_trackseg_DoF); + m_tree->Branch("TrackSegment_x", &m_trackseg_x); + m_tree->Branch("TrackSegment_y", &m_trackseg_y); + m_tree->Branch("TrackSegment_z", &m_trackseg_z); + m_tree->Branch("TrackSegment_px", &m_trackseg_px); + m_tree->Branch("TrackSegment_py", &m_trackseg_py); + m_tree->Branch("TrackSegment_pz", &m_trackseg_pz); + + m_tree->Branch("longTracks", &m_longTracks, "longTracks/I"); + m_tree->Branch("Track_Chi2", &m_Chi2); + m_tree->Branch("Track_nDoF", &m_DoF); + m_tree->Branch("Track_x0", &m_xup); + m_tree->Branch("Track_y0", &m_yup); + m_tree->Branch("Track_z0", &m_zup); + m_tree->Branch("Track_px0", &m_pxup); + m_tree->Branch("Track_py0", &m_pyup); + m_tree->Branch("Track_pz0", &m_pzup); + m_tree->Branch("Track_p0", &m_pup); + m_tree->Branch("Track_x1", &m_xdown); + m_tree->Branch("Track_y1", &m_ydown); + m_tree->Branch("Track_z1", &m_zdown); + m_tree->Branch("Track_px1", &m_pxdown); + m_tree->Branch("Track_py1", &m_pydown); + m_tree->Branch("Track_pz1", &m_pzdown); + m_tree->Branch("Track_p1", &m_pdown); + m_tree->Branch("Track_charge", &m_charge); + m_tree->Branch("Track_nLayers", &m_nLayers); + + m_tree->Branch("Track_InStation0",&m_nHit0); + m_tree->Branch("Track_InStation1",&m_nHit1); + m_tree->Branch("Track_InStation2",&m_nHit2); + m_tree->Branch("Track_InStation3",&m_nHit3); + + m_tree->Branch("Track_X_atVetoNu", &m_xVetoNu); + m_tree->Branch("Track_Y_atVetoNu", &m_yVetoNu); + m_tree->Branch("Track_ThetaX_atVetoNu", &m_thetaxVetoNu); + m_tree->Branch("Track_ThetaY_atVetoNu", &m_thetayVetoNu); + + m_tree->Branch("Track_X_atVetoStation1", &m_xVetoStation1); + m_tree->Branch("Track_Y_atVetoStation1", &m_yVetoStation1); + m_tree->Branch("Track_ThetaX_atVetoStation1", &m_thetaxVetoStation1); + m_tree->Branch("Track_ThetaY_atVetoStation1", &m_thetayVetoStation1); + + m_tree->Branch("Track_X_atVetoStation2", &m_xVetoStation2); + m_tree->Branch("Track_Y_atVetoStation2", &m_yVetoStation2); + m_tree->Branch("Track_ThetaX_atVetoStation2", &m_thetaxVetoStation2); + m_tree->Branch("Track_ThetaY_atVetoStation2", &m_thetayVetoStation2); + + m_tree->Branch("Track_X_atTrig", &m_xTrig); + m_tree->Branch("Track_Y_atTrig", &m_yTrig); + m_tree->Branch("Track_ThetaX_atTrig", &m_thetaxTrig); + m_tree->Branch("Track_ThetaY_atTrig", &m_thetayTrig); + + m_tree->Branch("Track_X_atPreshower1", &m_xPreshower1); + m_tree->Branch("Track_Y_atPreshower1", &m_yPreshower1); + m_tree->Branch("Track_ThetaX_atPreshower1", &m_thetaxPreshower1); + m_tree->Branch("Track_ThetaY_atPreshower1", &m_thetayPreshower1); + + m_tree->Branch("Track_X_atPreshower2", &m_xPreshower2); + m_tree->Branch("Track_Y_atPreshower2", &m_yPreshower2); + m_tree->Branch("Track_ThetaX_atPreshower2", &m_thetaxPreshower2); + m_tree->Branch("Track_ThetaY_atPreshower2", &m_thetayPreshower2); + + m_tree->Branch("Track_X_atCalo", &m_xCalo); + m_tree->Branch("Track_Y_atCalo", &m_yCalo); + m_tree->Branch("Track_ThetaX_atCalo", &m_thetaxCalo); + m_tree->Branch("Track_ThetaY_atCalo", &m_thetayCalo); + + m_tree->Branch("pTruthLepton", &m_truthLeptonMomentum, "pTruthLepton/D"); + m_tree->Branch("truthBarcode", &m_truthBarcode, "truthBarcode/I"); + m_tree->Branch("truthPdg", &m_truthPdg, "truthPdg/I"); + m_tree->Branch("CrossSection", &m_crossSection, "crossSection/D"); + + ATH_CHECK(histSvc()->regTree("/HIST2/tree", m_tree)); + + // Register histograms + m_HistRandomCharge[0] = new TH1F("hRandomCharge0", "Calo ch0 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[1] = new TH1F("hRandomCharge1", "Calo ch1 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[2] = new TH1F("hRandomCharge2", "Calo ch2 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[3] = new TH1F("hRandomCharge3", "Calo ch3 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[4] = new TH1F("hRandomCharge4", "VetoNu ch4 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[5] = new TH1F("hRandomCharge5", "VetoNu ch5 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[6] = new TH1F("hRandomCharge6", "Veto ch6 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[7] = new TH1F("hRandomCharge7", "Veto ch7 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[8] = new TH1F("hRandomCharge8", "Trig ch8 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[9] = new TH1F("hRandomCharge9", "Trig ch9 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[10] = new TH1F("hRandomCharge10", "Trig ch10 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[11] = new TH1F("hRandomCharge11", "Trig ch11 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[12] = new TH1F("hRandomCharge12", "Preshower ch12 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[13] = new TH1F("hRandomCharge13", "Preshower ch13 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + m_HistRandomCharge[14] = new TH1F("hRandomCharge14", "Veto ch14 Charge from Random Events;charge (pC);Events/bin", 100, -1.0, 1.0); + + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge0", m_HistRandomCharge[0])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge1", m_HistRandomCharge[1])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge2", m_HistRandomCharge[2])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge3", m_HistRandomCharge[3])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge4", m_HistRandomCharge[4])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge5", m_HistRandomCharge[5])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge6", m_HistRandomCharge[6])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge7", m_HistRandomCharge[7])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge8", m_HistRandomCharge[8])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge9", m_HistRandomCharge[9])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge10", m_HistRandomCharge[10])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge11", m_HistRandomCharge[11])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge12", m_HistRandomCharge[12])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge13", m_HistRandomCharge[13])); + ATH_CHECK(histSvc()->regHist("/HIST2/RandomCharge14", m_HistRandomCharge[14])); + + m_MIP_sim_Edep_calo = 0.0585; // MIP deposits 0.0585 GeV of energy in calo + m_MIP_sim_Edep_preshower = 0.004894; // MIP deposits 0.004894 GeV of energy in a preshower layer + + if (m_doBlinding) { + ATH_MSG_INFO("Blinding will be enforced for real data."); + } else { + ATH_MSG_INFO("Blinding will NOT be enforced for real data."); + } + + return StatusCode::SUCCESS; +} + + +StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const +{ + clearTree(); + + // check if real data or simulation data + bool realData = true; + SG::ReadHandle<xAOD::TruthEventContainer> truthEventContainer { m_truthEventContainer, ctx }; + if (truthEventContainer.isValid() && truthEventContainer->size() > 0) + { + realData = false; + } + + // if real data, store charge in histograms from random events and only fill ntuple from coincidence events + if (realData) { //no trigger simulation yet + SG::ReadHandle<xAOD::FaserTriggerData> triggerData(m_FaserTriggerData, ctx); + m_tap=triggerData->tap(); + if (m_tap==16) { // random trigger, store charge of scintillators in histograms + // Read in Waveform containers + SG::ReadHandle<xAOD::WaveformHitContainer> vetoNuContainer { m_vetoNuContainer, ctx }; + ATH_CHECK(vetoNuContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> vetoContainer { m_vetoContainer, ctx }; + ATH_CHECK(vetoContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> triggerContainer { m_triggerContainer, ctx }; + ATH_CHECK(triggerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> preshowerContainer { m_preshowerContainer, ctx }; + ATH_CHECK(preshowerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> ecalContainer { m_ecalContainer, ctx }; + ATH_CHECK(ecalContainer.isValid()); + + if (vetoNuContainer.isValid()) { + for (auto hit : *vetoNuContainer) { + int ch=hit->channel(); + m_HistRandomCharge[ch]->Fill(hit->raw_integral()/50.0); + } + } + if (vetoContainer.isValid()) { + for (auto hit : *vetoContainer) { + int ch=hit->channel(); + m_HistRandomCharge[ch]->Fill(hit->raw_integral()/50.0); + } + } + if (triggerContainer.isValid()) { + for (auto hit : *triggerContainer) { + int ch=hit->channel(); + m_HistRandomCharge[ch]->Fill(hit->raw_integral()/50.0); + } + } + if (preshowerContainer.isValid()) { + for (auto hit : *preshowerContainer) { + int ch=hit->channel(); + m_HistRandomCharge[ch]->Fill(hit->raw_integral()/50.0); + } + } + if (ecalContainer.isValid()) { + for (auto hit : *ecalContainer) { + int ch=hit->channel(); + m_HistRandomCharge[ch]->Fill(hit->raw_integral()/50.0); + } + } + + return StatusCode::SUCCESS; // finished with this event + + } else if ( ((m_tap&8)==0) && (((m_tap&4)==0)||((m_tap&2)==0)) && (((m_tap&4)==0)||((m_tap&1)==0)) && (((m_tap&2)==0)||((m_tap&1)==0)) ) { // don't process events that don't trigger coincidence triggers: 1=calo, 2=veotnu|neto1|preshower, 4=TimingLayer, 8=(VetoNu|Veto2)&Preshower + return StatusCode::SUCCESS; + } + m_tbp=triggerData->tbp(); + m_tap=triggerData->tap(); + m_inputBits=triggerData->inputBits(); + m_inputBitsNext=triggerData->inputBitsNextClk(); + } + + m_run_number = ctx.eventID().run_number(); + m_event_number = ctx.eventID().event_number(); + m_event_time = ctx.eventID().time_stamp(); + m_bcid = ctx.eventID().bunch_crossing_id(); + + if (!realData) { // if simulation find MC cross section and primary lepton + // Work out effective cross section for MC + if (m_useFlukaWeights) + { + double flukaWeight = truthEventContainer->at(0)->weights()[0]; + ATH_MSG_ALWAYS("Found fluka weight = " << flukaWeight); + m_crossSection = m_baseEventCrossSection * flukaWeight; + } + else if (m_useGenieWeights) + { + m_crossSection = m_baseEventCrossSection; + } + else + { + //ATH_MSG_WARNING("Monte carlo event with no weighting scheme specified. Setting crossSection (weight) to " << m_baseEventCrossSection << " fb."); + m_crossSection = m_baseEventCrossSection; + } + + // Find the primary lepton (if any) + SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainer { m_truthParticleContainer, ctx }; + if (truthParticleContainer.isValid() && truthParticleContainer->size() > 0) + { + for (auto particle : *truthParticleContainer) + { + if ( particle->absPdgId() == 11 || particle->absPdgId() == 13 || particle->absPdgId() == 15 ) + { + if (particle->status() == 1 && (particle->nParents() == 0 || particle->nParents() == 2) ) + { + m_truthLeptonMomentum = particle->p4().P(); + break; + } + } + } + } + } + + if (realData) { // correct waveform time with clock phase + SG::ReadHandle<xAOD::WaveformClock> clockHandle(m_ClockWaveformContainer, ctx); + ATH_CHECK(clockHandle.isValid()); + + if (clockHandle->phase() < -2.0) { // wrap around clock pahse so -pi goes to pi + m_clock_phase = ((clockHandle->phase() + 3.14159) / 3.14159) * 12.5; + } else { + m_clock_phase = (clockHandle->phase() / 3.14159) * 12.5; + } + } + + SG::ReadHandle<xAOD::WaveformHitContainer> vetoNuContainer { m_vetoNuContainer, ctx }; + ATH_CHECK(vetoNuContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> vetoContainer { m_vetoContainer, ctx }; + ATH_CHECK(vetoContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> triggerContainer { m_triggerContainer, ctx }; + ATH_CHECK(triggerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> preshowerContainer { m_preshowerContainer, ctx }; + ATH_CHECK(preshowerContainer.isValid()); + + SG::ReadHandle<xAOD::WaveformHitContainer> ecalContainer { m_ecalContainer, ctx }; + ATH_CHECK(ecalContainer.isValid()); + + FillWaveBranches(*vetoNuContainer); + FillWaveBranches(*vetoContainer); + FillWaveBranches(*triggerContainer); + FillWaveBranches(*preshowerContainer); + FillWaveBranches(*ecalContainer); + + m_calo_total=m_wave_charge[0]+m_wave_charge[1]+m_wave_charge[2]+m_wave_charge[3]; + m_calo_rawtotal=m_wave_raw_charge[0]+m_wave_raw_charge[1]+m_wave_raw_charge[2]+m_wave_raw_charge[3]; + + // do calibration of calo channels from pC to GeV deposited + if (m_CaloConfig == "High_gain") { + m_Calo0_Edep = (m_wave_charge[0] / 23.709) * m_MIP_sim_Edep_calo; + m_Calo1_Edep = (m_wave_charge[1] / 24.333) * m_MIP_sim_Edep_calo; + m_Calo2_Edep = (m_wave_charge[2] / 24.409) * m_MIP_sim_Edep_calo; + m_Calo3_Edep = (m_wave_charge[3] / 25.555) * m_MIP_sim_Edep_calo; + } else if (m_CaloConfig == "Low_gain") { // assume low gain calo + m_Calo0_Edep = (m_wave_charge[0] / 0.7909) * m_MIP_sim_Edep_calo; + m_Calo1_Edep = (m_wave_charge[1] / 0.8197) * m_MIP_sim_Edep_calo; + m_Calo2_Edep = (m_wave_charge[2] / 0.8256) * m_MIP_sim_Edep_calo; + m_Calo3_Edep = (m_wave_charge[3] / 0.8821) * m_MIP_sim_Edep_calo; + } else { + ATH_MSG_WARNING("Run config is neither High_gain nor Low_gain, it is " << m_CaloConfig << ", calo calibration will be zero"); + } + m_Calo_Total_Edep = m_Calo0_Edep + m_Calo1_Edep + m_Calo2_Edep + m_Calo3_Edep; + + // do calibration of preshower channels from pC to GeV deposited + m_Preshower12_Edep = (m_wave_charge[12] / 5.0) * m_MIP_sim_Edep_preshower; // 5 pC per MIP is rough measurement + m_Preshower13_Edep = (m_wave_charge[12] / 5.0) * m_MIP_sim_Edep_preshower; + + if (realData && m_doBlinding) { // enforce blinding such that events with large calo signals are skipped and not in the output root file + if ((m_Calo_Total_Edep/0.155) > 10.0) { // only save events with a shower less than a 10 GeV e- (assume 10 GeV electron deposits 15.5% of their energy in calo) + return StatusCode::SUCCESS; + } + } + + SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer { m_clusterContainer, ctx }; + ATH_CHECK(clusterContainer.isValid()); + + FaserActsGeometryContext faserGeometryContext = m_trackingGeometryTool->getNominalGeometryContext(); + auto gctx = faserGeometryContext.context(); + + for (auto collection : *clusterContainer) + { + Identifier id = collection->identify(); + int station = m_sctHelper->station(id); + int clusters = (int) collection->size(); + switch (station) + { + case 0: + m_station0Clusters += clusters; + // following lines commented out depict how to access cluster position + //for (auto cluster : *collection) { + // if (cluster == nullptr) continue; + // auto pos = cluster->globalPosition(); + // m_station0ClusterX.push_back(pos.x()); + //} + break; + case 1: + m_station1Clusters += clusters; + break; + case 2: + m_station2Clusters += clusters; + break; + case 3: + m_station3Clusters += clusters; + break; + default: + ATH_MSG_FATAL("Unknown tracker station number " << station); + break; + } + } + + SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey, ctx}; + ATH_CHECK(spacePointContainer.isValid()); + for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) { + m_nspacepoints += spacePointCollection->size(); + for (const Tracker::FaserSCT_SpacePoint *spacePoint: *spacePointCollection) { + auto pos = spacePoint->globalPosition(); + m_spacepointX.push_back(pos.x()); + m_spacepointY.push_back(pos.y()); + m_spacepointZ.push_back(pos.z()); + } + } + + SG::ReadHandle<TrackCollection> trackSegmentCollection {m_trackSegmentCollection, ctx}; + ATH_CHECK(trackSegmentCollection.isValid()); + for (const Trk::Track* trackSeg : *trackSegmentCollection) { + if (trackSeg == nullptr) continue; + m_ntracksegs += 1; + m_trackseg_Chi2.push_back(trackSeg->fitQuality()->chiSquared()); + m_trackseg_DoF.push_back(trackSeg->fitQuality()->numberDoF()); + auto SegParameters = trackSeg->trackParameters()->front(); + const Amg::Vector3D SegPosition = SegParameters->position(); + const Amg::Vector3D SegMomentum = SegParameters->momentum(); + m_trackseg_x.push_back(SegPosition.x()); + m_trackseg_y.push_back(SegPosition.y()); + m_trackseg_z.push_back(SegPosition.z()); + m_trackseg_px.push_back(SegMomentum.x()); + m_trackseg_py.push_back(SegMomentum.y()); + m_trackseg_pz.push_back(SegMomentum.z()); + } + + SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection, ctx}; + ATH_CHECK(trackCollection.isValid()); + const Trk::TrackParameters* candidateParameters {nullptr}; + const Trk::TrackParameters* candidateDownParameters {nullptr}; + for (const Trk::Track* track : *trackCollection) + { + if (track == nullptr) continue; + std::set<std::pair<int, int>> layerMap; + std::set<int> stationMap; + + // Check for hit in the three downstream stations + for (auto measurement : *(track->measurementsOnTrack())) { + const Tracker::FaserSCT_ClusterOnTrack* cluster = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(measurement); + if (cluster != nullptr) { + Identifier id = cluster->identify(); + int station = m_sctHelper->station(id); + int layer = m_sctHelper->layer(id); + stationMap.emplace(station); + layerMap.emplace(station, layer); + } + } + if (stationMap.count(1) == 0 || stationMap.count(2) == 0 || stationMap.count(3) == 0) continue; + + int nLayers = std::count_if(layerMap.begin(), layerMap.end(), [](std::pair<int,int> p){return p.first != 0;}); + const Trk::TrackParameters* upstreamParameters = track->trackParameters()->front(); + const Trk::TrackParameters* downstreamParameters = track->trackParameters()->back(); + + if (candidateParameters == nullptr || upstreamParameters->momentum().mag() > candidateParameters->momentum().mag()) + { + candidateParameters = upstreamParameters; + candidateDownParameters = downstreamParameters; + } + + if ((candidateParameters == nullptr) || (candidateDownParameters == nullptr)) continue; + + m_nLayers.push_back(nLayers); + + m_Chi2.push_back(track->fitQuality()->chiSquared()); + m_DoF.push_back(track->fitQuality()->numberDoF()); + + m_nHit0.push_back(stationMap.count(0)); + m_nHit1.push_back(stationMap.count(1)); + m_nHit2.push_back(stationMap.count(2)); + m_nHit3.push_back(stationMap.count(3)); + + m_charge.push_back( (int) candidateParameters->charge() ); + + m_xup.push_back(candidateParameters->position().x()); + m_yup.push_back(candidateParameters->position().y()); + m_zup.push_back(candidateParameters->position().z()); + m_pxup.push_back(candidateParameters->momentum().x()); + m_pyup.push_back(candidateParameters->momentum().y()); + m_pzup.push_back(candidateParameters->momentum().z()); + m_pup.push_back(sqrt( pow(candidateParameters->momentum().x(),2) + pow(candidateParameters->momentum().y(),2) + pow(candidateParameters->momentum().z(),2) )); + + m_xdown.push_back(candidateDownParameters->position().x()); + m_ydown.push_back(candidateDownParameters->position().y()); + m_zdown.push_back(candidateDownParameters->position().z()); + m_pxdown.push_back(candidateDownParameters->momentum().x()); + m_pydown.push_back(candidateDownParameters->momentum().y()); + m_pzdown.push_back(candidateDownParameters->momentum().z()); + m_pdown.push_back(sqrt( pow(candidateDownParameters->momentum().x(),2) + pow(candidateDownParameters->momentum().y(),2) + pow(candidateDownParameters->momentum().z(),2) )); + + // fill extrapolation vectors with filler values that get changed iif the track extrapolation succeeds + m_xVetoNu.push_back(-10000); + m_yVetoNu.push_back(-10000); + m_thetaxVetoNu.push_back(-10000); + m_thetayVetoNu.push_back(-10000); + m_xVetoStation1.push_back(-10000); + m_yVetoStation1.push_back(-10000); + m_thetaxVetoStation1.push_back(-10000); + m_thetayVetoStation1.push_back(-10000); + m_xVetoStation2.push_back(-10000); + m_yVetoStation2.push_back(-10000); + m_thetaxVetoStation2.push_back(-10000); + m_thetayVetoStation2.push_back(-10000); + m_xTrig.push_back(-10000); + m_yTrig.push_back(-10000); + m_thetaxTrig.push_back(-10000); + m_thetayTrig.push_back(-10000); + m_xPreshower1.push_back(-10000); + m_yPreshower1.push_back(-10000); + m_thetaxPreshower1.push_back(-10000); + m_thetayPreshower1.push_back(-10000); + m_xPreshower2.push_back(-10000); + m_yPreshower2.push_back(-10000); + m_thetaxPreshower2.push_back(-10000); + m_thetayPreshower2.push_back(-10000); + m_xCalo.push_back(-10000); + m_yCalo.push_back(-10000); + m_thetaxCalo.push_back(-10000); + m_thetayCalo.push_back(-10000); + + // extrapolate track from IFT + if (stationMap.count(0) > 0) { // extrapolation crashes if the track does not start in the IFT, as it is too far away to extrapolate + Amg::Vector3D position = candidateParameters->position(); + Amg::Vector3D momentum = candidateParameters->momentum(); + Acts::BoundVector params = Acts::BoundVector::Zero(); + params[Acts::eBoundLoc0] = -position.y(); + params[Acts::eBoundLoc1] = position.x(); + params[Acts::eBoundPhi] = momentum.phi(); + params[Acts::eBoundTheta] = momentum.theta(); + params[Acts::eBoundQOverP] = candidateParameters->charge() / momentum.mag(); + params[Acts::eBoundTime] = 0; + auto startSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, position.z()), Acts::Vector3(0, 0, 1)); + Acts::BoundTrackParameters startParameters(std::move(startSurface), params, candidateParameters->charge()); + + auto targetSurface_VetoNu = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, -3112.0), Acts::Vector3(0, 0, 1)); // -3112 mm is z position of VetoNu planes touching + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_VetoNu =m_extrapolationTool->propagate(ctx, startParameters, *targetSurface_VetoNu, Acts::backward); + if (targetParameters_VetoNu != nullptr) { + auto targetPosition_VetoNu = targetParameters_VetoNu->position(gctx); + auto targetMomentum_VetoNu = targetParameters_VetoNu->momentum(); + m_xVetoNu[m_longTracks] = targetPosition_VetoNu.x(); + m_yVetoNu[m_longTracks] = targetPosition_VetoNu.y(); + m_thetaxVetoNu[m_longTracks] = atan(targetMomentum_VetoNu[0]/targetMomentum_VetoNu[2]); + m_thetayVetoNu[m_longTracks] = atan(targetMomentum_VetoNu[1]/targetMomentum_VetoNu[2]); + } else { + ATH_MSG_INFO("vetoNu null targetParameters"); + } + + auto targetSurface_Veto1 = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, -1769.65), Acts::Vector3(0, 0, 1)); // -1769.65 mm is z position of center of operational layer in Veto station 1 + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Veto1 =m_extrapolationTool->propagate(ctx, startParameters, *targetSurface_Veto1, Acts::forward); + if (targetParameters_Veto1 != nullptr) { + auto targetPosition_Veto1 = targetParameters_Veto1->position(gctx); + auto targetMomentum_Veto1 = targetParameters_Veto1->momentum(); + m_xVetoStation1[m_longTracks] = targetPosition_Veto1.x(); + m_yVetoStation1[m_longTracks] = targetPosition_Veto1.y(); + m_thetaxVetoStation1[m_longTracks] = atan(targetMomentum_Veto1[0]/targetMomentum_Veto1[2]); + m_thetayVetoStation1[m_longTracks] = atan(targetMomentum_Veto1[1]/targetMomentum_Veto1[2]); + } else { + ATH_MSG_INFO("veto1 null targetParameters"); + } + + auto targetSurface_Veto2 = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, -1609.65), Acts::Vector3(0, 0, 1)); // -1609.65 mm is z position of where planes touch in Veto station 2 + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Veto2 =m_extrapolationTool->propagate(ctx, startParameters, *targetSurface_Veto2, Acts::forward); + if (targetParameters_Veto2 != nullptr) { + auto targetPosition_Veto2 = targetParameters_Veto2->position(gctx); + auto targetMomentum_Veto2 = targetParameters_Veto2->momentum(); + m_xVetoStation2[m_longTracks] = targetPosition_Veto2.x(); + m_yVetoStation2[m_longTracks] = targetPosition_Veto2.y(); + m_thetaxVetoStation2[m_longTracks] = atan(targetMomentum_Veto2[0]/targetMomentum_Veto2[2]); + m_thetayVetoStation2[m_longTracks] = atan(targetMomentum_Veto2[1]/targetMomentum_Veto2[2]); + } else { + ATH_MSG_INFO("veto2 null targetParameters"); + } + + auto targetSurface_Trig = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, 0.0), Acts::Vector3(0, 0, 1)); // 0 mm is z position of Trig planes overlapping + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Trig =m_extrapolationTool->propagate(ctx, startParameters, *targetSurface_Trig, Acts::forward); // must extrapolate forward to trig plane if track starts in IFT + if (targetParameters_Trig != nullptr) { + auto targetPosition_Trig = targetParameters_Trig->position(gctx); + auto targetMomentum_Trig = targetParameters_Trig->momentum(); + m_xTrig[m_longTracks] = targetPosition_Trig.x(); + m_yTrig[m_longTracks] = targetPosition_Trig.y(); + m_thetaxTrig[m_longTracks] = atan(targetMomentum_Trig[0]/targetMomentum_Trig[2]); + m_thetayTrig[m_longTracks] = atan(targetMomentum_Trig[1]/targetMomentum_Trig[2]); + } else { + ATH_MSG_INFO("Trig null targetParameters"); + } + + } + + // extrapolate track from tracking station 3 + if (stationMap.count(3) > 0) { // extrapolation crashes if the track does not end in the Station 3, as it is too far away to extrapolate + Amg::Vector3D positionDown = candidateDownParameters->position(); + Amg::Vector3D momentumDown = candidateDownParameters->momentum(); + Acts::BoundVector paramsDown = Acts::BoundVector::Zero(); + paramsDown[Acts::eBoundLoc0] = -positionDown.y(); + paramsDown[Acts::eBoundLoc1] = positionDown.x(); + paramsDown[Acts::eBoundPhi] = momentumDown.phi(); + paramsDown[Acts::eBoundTheta] = momentumDown.theta(); + paramsDown[Acts::eBoundQOverP] = candidateDownParameters->charge() / momentumDown.mag(); + paramsDown[Acts::eBoundTime] = 0; + auto startSurfaceDown = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, positionDown.z()), Acts::Vector3(0, 0, 1)); + Acts::BoundTrackParameters startParametersDown(std::move(startSurfaceDown), paramsDown, candidateDownParameters->charge()); + + auto targetSurface_Preshower1 = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, 2582.68), Acts::Vector3(0, 0, 1)); // 2582.68 mm is z position of center of upstream preshower layer + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Preshower1 =m_extrapolationTool->propagate(ctx, startParametersDown, *targetSurface_Preshower1, Acts::forward); + if (targetParameters_Preshower1 != nullptr) { + auto targetPosition_Preshower1 = targetParameters_Preshower1->position(gctx); + auto targetMomentum_Preshower1 = targetParameters_Preshower1->momentum(); + m_xPreshower1[m_longTracks] = targetPosition_Preshower1.x(); + m_yPreshower1[m_longTracks] = targetPosition_Preshower1.y(); + m_thetaxPreshower1[m_longTracks] = atan(targetMomentum_Preshower1[0]/targetMomentum_Preshower1[2]); + m_thetayPreshower1[m_longTracks] = atan(targetMomentum_Preshower1[1]/targetMomentum_Preshower1[2]); + } else { + ATH_MSG_INFO("Preshower1 null targetParameters"); + } + + auto targetSurface_Preshower2 = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, 2657.68), Acts::Vector3(0, 0, 1)); // 2657.68 mm is z position of center of downstream preshower layer + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Preshower2 =m_extrapolationTool->propagate(ctx, startParametersDown, *targetSurface_Preshower2, Acts::forward); + if (targetParameters_Preshower2 != nullptr) { + auto targetPosition_Preshower2 = targetParameters_Preshower2->position(gctx); + auto targetMomentum_Preshower2 = targetParameters_Preshower2->momentum(); + m_xPreshower2[m_longTracks] = targetPosition_Preshower2.x(); + m_yPreshower2[m_longTracks] = targetPosition_Preshower2.y(); + m_thetaxPreshower2[m_longTracks] = atan(targetMomentum_Preshower2[0]/targetMomentum_Preshower2[2]); + m_thetayPreshower2[m_longTracks] = atan(targetMomentum_Preshower2[1]/targetMomentum_Preshower2[2]); + } else { + ATH_MSG_INFO("Preshower2 null targetParameters"); + } + + auto targetSurface_Calo = Acts::Surface::makeShared<Acts::PlaneSurface>(Acts::Vector3(0, 0, 2760.0), Acts::Vector3(0, 0, 1)); // 2760 mm is estimated z position of calorimeter face + std::unique_ptr<const Acts::BoundTrackParameters> targetParameters_Calo =m_extrapolationTool->propagate(ctx, startParametersDown, *targetSurface_Calo, Acts::forward); + if (targetParameters_Calo != nullptr) { + auto targetPosition_Calo = targetParameters_Calo->position(gctx); + auto targetMomentum_Calo = targetParameters_Calo->momentum(); + m_xCalo[m_longTracks] = targetPosition_Calo.x(); + m_yCalo[m_longTracks] = targetPosition_Calo.y(); + m_thetaxCalo[m_longTracks] = atan(targetMomentum_Calo[0]/targetMomentum_Calo[2]) ; + m_thetayCalo[m_longTracks] = atan(targetMomentum_Calo[1]/targetMomentum_Calo[2]) ; + } else { + ATH_MSG_INFO("Calo null targetParameters"); + } + } + + m_longTracks++; + } + + /* + // Here we apply the signal selection + // Very simple/unrealistic to start + if (m_vetoUpstream == 0 || m_vetoDownstream == 0 || + m_triggerTotal == 0 || + m_preshower0 == 0 || m_preshower1 == 0 || + // m_ecalTotal == 0 || + candidateParameters == nullptr) + return StatusCode::SUCCESS; + */ + m_tree->Fill(); + + return StatusCode::SUCCESS; +} + + +StatusCode NtupleDumperAlg::finalize() +{ + return StatusCode::SUCCESS; +} + +bool NtupleDumperAlg::waveformHitOK(const xAOD::WaveformHit* hit) const +{ + if (hit->status_bit(xAOD::WaveformStatus::THRESHOLD_FAILED) || hit->status_bit(xAOD::WaveformStatus::SECONDARY)) return false; + return true; +} + +void +NtupleDumperAlg::clearTree() const +{ + m_run_number = 0; + m_event_number = 0; + m_event_time = 0; + m_bcid = 0; + + m_tbp=0; + m_tap=0; + m_inputBits=0; + m_inputBitsNext=0; + + for(int ii=0;ii<15;ii++) { + m_wave_localtime[ii]=0; + m_wave_peak[ii]=0; + m_wave_width[ii]=0; + m_wave_charge[ii]=0; + + m_wave_raw_peak[ii]=0; + m_wave_raw_charge[ii]=0; + m_wave_baseline_mean[ii]=0; + m_wave_baseline_rms[ii]=0; + m_wave_status[ii]=0; + } + + m_calo_total=0; + m_calo_rawtotal=0; + + m_Calo0_Edep=0; + m_Calo1_Edep=0; + m_Calo2_Edep=0; + m_Calo3_Edep=0; + m_Calo_Total_Edep=0; + m_Preshower12_Edep=0; + m_Preshower13_Edep=0; + + m_clock_phase=0; + + m_station0Clusters = 0; + m_station1Clusters = 0; + m_station2Clusters = 0; + m_station3Clusters = 0; + m_crossSection = 0; + + m_nspacepoints = 0; + m_spacepointX.clear(); + m_spacepointY.clear(); + m_spacepointZ.clear(); + + m_ntracksegs = 0; + m_trackseg_Chi2.clear(); + m_trackseg_DoF.clear(); + m_trackseg_x.clear(); + m_trackseg_y.clear(); + m_trackseg_z.clear(); + m_trackseg_px.clear(); + m_trackseg_py.clear(); + m_trackseg_pz.clear(); + + m_xup.clear(); + m_yup.clear(); + m_zup.clear(); + m_pxup.clear(); + m_pyup.clear(); + m_pzup.clear(); + m_pup.clear(); + + m_xdown.clear(); + m_ydown.clear(); + m_zdown.clear(); + m_pxdown.clear(); + m_pydown.clear(); + m_pzdown.clear(); + m_pdown.clear(); + + m_Chi2.clear(); + m_DoF.clear(); + m_charge.clear(); + m_nLayers.clear(); + m_longTracks = 0; + + m_nHit0.clear(); + m_nHit1.clear(); + m_nHit2.clear(); + m_nHit3.clear(); + + m_xVetoNu.clear(); + m_yVetoNu.clear(); + m_thetaxVetoNu.clear(); + m_thetayVetoNu.clear(); + + m_xVetoStation1.clear(); + m_yVetoStation1.clear(); + m_thetaxVetoStation1.clear(); + m_thetayVetoStation1.clear(); + + m_xVetoStation2.clear(); + m_yVetoStation2.clear(); + m_thetaxVetoStation2.clear(); + m_thetayVetoStation2.clear(); + + m_xTrig.clear(); + m_yTrig.clear(); + m_thetaxTrig.clear(); + m_thetayTrig.clear(); + + m_xPreshower1.clear(); + m_yPreshower1.clear(); + m_thetaxPreshower1.clear(); + m_thetayPreshower1.clear(); + + m_xPreshower2.clear(); + m_yPreshower2.clear(); + m_thetaxPreshower2.clear(); + m_thetayPreshower2.clear(); + + m_xCalo.clear(); + m_yCalo.clear(); + m_thetaxCalo.clear(); + m_thetayCalo.clear(); + + m_truthLeptonMomentum = 0; + m_truthBarcode = 0; + m_truthPdg = 0; +} diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..1b26caadeb7290c34a199ef0e941f9203b600bba --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h @@ -0,0 +1,217 @@ +#ifndef NTUPLEDUMPER_NTUPLEDUMPERALG_H +#define NTUPLEDUMPER_NTUPLEDUMPERALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthHistogramming.h" +#include "TrkTrack/TrackCollection.h" +#include "xAODFaserTrigger/FaserTriggerData.h" +#include "xAODFaserWaveform/WaveformHitContainer.h" +#include "xAODFaserWaveform/WaveformHit.h" +#include "xAODFaserWaveform/WaveformClock.h" +#include "xAODTruth/TruthEventContainer.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" + +#include <vector> + +class TTree; +class TH1; +class FaserSCT_ID; +class VetoNuID; +class VetoID; +class TriggerID; +class PreshowerID; +class EcalID; +namespace TrackerDD +{ + class SCT_DetectorManager; +} + +class NtupleDumperAlg : public AthReentrantAlgorithm, AthHistogramming { +public: + NtupleDumperAlg(const std::string &name, ISvcLocator *pSvcLocator); + virtual ~NtupleDumperAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext &ctx) const override; + virtual StatusCode finalize() override; + const ServiceHandle <ITHistSvc> &histSvc() const; + +private: + + bool waveformHitOK(const xAOD::WaveformHit* hit) const; + void clearTree() const; + void addBranch(const std::string &name,float* var); + void addBranch(const std::string &name,unsigned int* var); + void addWaveBranches(const std::string &name, int nchannels, int first); + void FillWaveBranches(const xAOD::WaveformHitContainer &wave) const; + + ServiceHandle <ITHistSvc> m_histSvc; + + SG::ReadHandleKey<xAOD::TruthEventContainer> m_truthEventContainer { this, "EventContainer", "TruthEvents", "Truth event container name." }; + SG::ReadHandleKey<xAOD::TruthParticleContainer> m_truthParticleContainer { this, "ParticleContainer", "TruthParticles", "Truth particle container name." }; + SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollection {this, "TrackerSimDataCollection", "SCT_SDO_Map"}; + + SG::ReadHandleKey<TrackCollection> m_trackCollection { this, "TrackCollection", "CKFTrackCollection", "Input track collection name" }; + SG::ReadHandleKey<TrackCollection> m_trackSegmentCollection {this, "TrackSegmentCollection", "SegmentFit", "Input track segment collection name"}; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_vetoNuContainer { this, "VetoNuContainer", "VetoNuWaveformHits", "VetoNu hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_vetoContainer { this, "VetoContainer", "VetoWaveformHits", "Veto hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_triggerContainer { this, "TriggerContainer", "TriggerWaveformHits", "Trigger hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_preshowerContainer { this, "PreshowerContainer", "PreshowerWaveformHits", "Preshower hit container name" }; + SG::ReadHandleKey<xAOD::WaveformHitContainer> m_ecalContainer { this, "EcalContainer", "CaloWaveformHits", "Ecal hit container name" }; + SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainer { this, "ClusterContainer", "SCT_ClusterContainer", "Tracker cluster container name" }; + SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey { this, "SpacePoints", "SCT_SpacePointContainer", "space point container"}; + + SG::ReadHandleKey<xAOD::FaserTriggerData> m_FaserTriggerData { this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"}; + SG::ReadHandleKey<xAOD::WaveformClock> m_ClockWaveformContainer { this, "WaveformClockKey", "WaveformClock", "ReadHandleKey for ClockWaveforms Container"}; + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { this, "ExtrapolationTool", "FaserActsExtrapolationTool" }; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + + const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr}; + + const FaserSCT_ID* m_sctHelper; + const VetoNuID* m_vetoNuHelper; + const VetoID* m_vetoHelper; + const TriggerID* m_triggerHelper; + const PreshowerID* m_preshowerHelper; + const EcalID* m_ecalHelper; + + StringProperty m_CaloConfig { this, "CaloConfig", "Low_gain", "Configuration found at http://aagaard.web.cern.ch/aagaard/FASERruns.html (spaces replaced with '_')" }; + BooleanProperty m_doBlinding { this, "DoBlinding", true, "Blinding will not output events with Calo signal > 10 GeV e-" }; + BooleanProperty m_useFlukaWeights { this, "UseFlukaWeights", false, "Flag to weight events according to value stored in HepMC::GenEvent" }; + BooleanProperty m_useGenieWeights { this, "UseGenieWeights", false, "Flag to weight events according to Genie luminosity" }; + IntegerProperty m_flukaCollisions { this, "FlukaCollisions", 137130000, "Number of proton-proton collisions in FLUKA sample." }; + DoubleProperty m_flukaCrossSection { this, "FlukaCrossSection", 80.0, "Fluka p-p inelastic cross-section in millibarns." }; + DoubleProperty m_genieLuminosity { this, "GenieLuminosity", 150.0, "Genie luminosity in inverse fb." }; + + double m_baseEventCrossSection {1.0}; + const double kfemtoBarnsPerMilliBarn {1.0e12}; + + mutable TTree* m_tree; + + mutable TH1* m_HistRandomCharge[15]; + + mutable unsigned int m_run_number; + mutable unsigned int m_event_number; + mutable unsigned int m_event_time; + mutable unsigned int m_bcid; + + mutable unsigned int m_tbp; + mutable unsigned int m_tap; + mutable unsigned int m_inputBits; + mutable unsigned int m_inputBitsNext; + + mutable float m_wave_localtime[15]; + mutable float m_wave_peak[15]; + mutable float m_wave_width[15]; + mutable float m_wave_charge[15]; + + mutable float m_wave_raw_peak[15]; + mutable float m_wave_raw_charge[15]; + mutable float m_wave_baseline_mean[15]; + mutable float m_wave_baseline_rms[15]; + mutable unsigned int m_wave_status[15]; + + mutable float m_calo_total; + mutable float m_calo_rawtotal; + + mutable float m_Calo0_Edep; + mutable float m_Calo1_Edep; + mutable float m_Calo2_Edep; + mutable float m_Calo3_Edep; + mutable float m_Calo_Total_Edep; + mutable float m_Preshower12_Edep; + mutable float m_Preshower13_Edep; + + mutable float m_MIP_sim_Edep_calo; + mutable float m_MIP_sim_Edep_preshower; + + mutable float m_clock_phase; + + mutable unsigned int m_station0Clusters; + mutable unsigned int m_station1Clusters; + mutable unsigned int m_station2Clusters; + mutable unsigned int m_station3Clusters; + + mutable unsigned int m_nspacepoints; + mutable std::vector<double> m_spacepointX; + mutable std::vector<double> m_spacepointY; + mutable std::vector<double> m_spacepointZ; + + mutable unsigned int m_ntracksegs; + mutable std::vector<double> m_trackseg_Chi2; + mutable std::vector<double> m_trackseg_DoF; + mutable std::vector<double> m_trackseg_x; + mutable std::vector<double> m_trackseg_y; + mutable std::vector<double> m_trackseg_z; + mutable std::vector<double> m_trackseg_px; + mutable std::vector<double> m_trackseg_py; + mutable std::vector<double> m_trackseg_pz; + + mutable int m_longTracks; + mutable std::vector<double> m_Chi2; + mutable std::vector<double> m_DoF; + mutable std::vector<double> m_xup; + mutable std::vector<double> m_yup; + mutable std::vector<double> m_zup; + mutable std::vector<double> m_pxup; + mutable std::vector<double> m_pyup; + mutable std::vector<double> m_pzup; + mutable std::vector<double> m_pup; + mutable std::vector<double> m_xdown; + mutable std::vector<double> m_ydown; + mutable std::vector<double> m_zdown; + mutable std::vector<double> m_pxdown; + mutable std::vector<double> m_pydown; + mutable std::vector<double> m_pzdown; + mutable std::vector<double> m_pdown; + mutable std::vector<int> m_charge; + mutable std::vector<unsigned int> m_nLayers; + mutable std::vector<unsigned int> m_nHit0; + mutable std::vector<unsigned int> m_nHit1; + mutable std::vector<unsigned int> m_nHit2; + mutable std::vector<unsigned int> m_nHit3; + mutable std::vector<double> m_xVetoNu; + mutable std::vector<double> m_yVetoNu; + mutable std::vector<double> m_thetaxVetoNu; + mutable std::vector<double> m_thetayVetoNu; + mutable std::vector<double> m_xVetoStation1; + mutable std::vector<double> m_yVetoStation1; + mutable std::vector<double> m_thetaxVetoStation1; + mutable std::vector<double> m_thetayVetoStation1; + mutable std::vector<double> m_xVetoStation2; + mutable std::vector<double> m_yVetoStation2; + mutable std::vector<double> m_thetaxVetoStation2; + mutable std::vector<double> m_thetayVetoStation2; + mutable std::vector<double> m_xTrig; + mutable std::vector<double> m_yTrig; + mutable std::vector<double> m_thetaxTrig; + mutable std::vector<double> m_thetayTrig; + mutable std::vector<double> m_xPreshower1; + mutable std::vector<double> m_yPreshower1; + mutable std::vector<double> m_thetaxPreshower1; + mutable std::vector<double> m_thetayPreshower1; + mutable std::vector<double> m_xPreshower2; + mutable std::vector<double> m_yPreshower2; + mutable std::vector<double> m_thetaxPreshower2; + mutable std::vector<double> m_thetayPreshower2; + mutable std::vector<double> m_xCalo; + mutable std::vector<double> m_yCalo; + mutable std::vector<double> m_thetaxCalo; + mutable std::vector<double> m_thetayCalo; + + mutable double m_truthLeptonMomentum; + mutable int m_truthBarcode; + mutable int m_truthPdg; + mutable double m_crossSection; + +}; + +inline const ServiceHandle <ITHistSvc> &NtupleDumperAlg::histSvc() const { + return m_histSvc; +} + +#endif // NTUPLEDUMPER_NTUPLEDUMPERALG_H diff --git a/PhysicsAnalysis/NtupleDumper/src/component/NtupleDumper_entries.cxx b/PhysicsAnalysis/NtupleDumper/src/component/NtupleDumper_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..15dc244e170829e01af0d848e3cac55abbc83619 --- /dev/null +++ b/PhysicsAnalysis/NtupleDumper/src/component/NtupleDumper_entries.cxx @@ -0,0 +1,3 @@ +#include "../NtupleDumperAlg.h" + +DECLARE_COMPONENT(NtupleDumperAlg) diff --git a/README.md b/README.md index c2900525af586a7660cc4740ce93547fee008dc2..2d7e57abb75b58112939efb7b2726607bcfb6ec3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ git clone --recursive https://:@gitlab.cern.ch:8443/$USERNAME/calypso.git #The next three lines are used to setup the ATLAS release environment export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh -asetup --input=calypso/asetup.faser Athena,22.0.40 +asetup --input=calypso/asetup.faser Athena,22.0.49 #create build directory mkdir build @@ -29,20 +29,27 @@ 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** + +If afs is used to host and run calypso, the user should do so with an afs workspace. + +Instructions for setting up a workspace can be found here: https://resources.web.cern.ch/resources/Help/?kbid=067040 + +When compiling, CERN IT recommends using condor to submit batch jobs. The basics of running condor are found here: https://batchdocs.web.cern.ch/local/quick.html + ## Known issues: * 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 "FaserActsKalmanFilter" package is temporarily disabled. - -* 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 new file mode 100644 index 0000000000000000000000000000000000000000..5c1874e2502241f919efb21ade0e7c26de7369ca --- /dev/null +++ b/Scintillator/ScintDigiAlgs/CMakeLists.txt @@ -0,0 +1,17 @@ +################################################################################ +# Package: ScintDigiAlgs +################################################################################ + +# Declare the package name: +atlas_subdir( ScintDigiAlgs ) + +# Component(s) in the package: +atlas_add_component( ScintDigiAlgs + src/*.cxx src/*.h + src/components/*.cxx + 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 new file mode 100644 index 0000000000000000000000000000000000000000..407ab913201a42845581e5543e1455b7b89c5867 --- /dev/null +++ b/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py @@ -0,0 +1,95 @@ +# Copyright (C) 2020-2021 CERN for the benefit of the FASER collaboration + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +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) +# Parameters are per scintillator source, but not per channel. +# Updated aamplitudes (norm) to match testbeam response +# Make everything except VetoNu look like the preshower +dict_CB_param = {} +dict_CB_param["Trigger"]=dict(CB_alpha=-0.424, CB_n=6.14, CB_mean=815, CB_sigma=3.21, CB_norm = 4240) +dict_CB_param["Timing"] =dict(CB_alpha=-0.424, CB_n=6.14, CB_mean=846, CB_sigma=3.21, CB_norm = 4240) +dict_CB_param["Veto"] =dict(CB_alpha=-0.32, CB_n=9.0, CB_mean=815, CB_sigma=3.35, CB_norm = 6840) +dict_CB_param["VetoNu"] =dict(CB_alpha=-0.28, CB_n=1000, CB_mean=815, CB_sigma=5.00, CB_norm = 7040) +dict_CB_param["Preshower"]=dict(CB_alpha=-0.32, CB_n=1000, CB_mean=846, CB_sigma=4.0, CB_norm = 400) + +dict_baseline_params = { + "Trigger" : {"mean" : 15650, "rms" : 3}, + "Timing" : {"mean" : 15650, "rms" : 3}, + "Veto" : {"mean" : 15650, "rms" : 3}, + "VetoNu" : {"mean" : 15650, "rms" : 3}, + "Preshower" : {"mean" : 15650, "rms" : 3}, + } + +# One stop shopping for normal FASER data +def ScintWaveformDigitizationCfg(flags): + """ Return all algorithms and tools for Waveform digitization """ + acc = ComponentAccumulator() + + if not flags.Input.isMC: + return acc + + if "TB" in flags.GeoModel.FaserVersion: + acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto")) + acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower")) + else: + acc.merge(ScintWaveformDigiCfg(flags, "TriggerWaveformDigiAlg", "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 +# Specify data source (Veto, Trigger, Preshower) +def ScintWaveformDigiCfg(flags, name="ScintWaveformDigiAlg", source="", **kwargs): + + acc = ComponentAccumulator() + + tool = CompFactory.WaveformDigitisationTool(name=source+"WaveformDigtisationTool", **kwargs) + + kwargs.setdefault("ScintHitContainerKey", source+"Hits") + kwargs.setdefault("WaveformContainerKey", source+"Waveforms") + + digiAlg = CompFactory.ScintWaveformDigiAlg(name, **kwargs) + + if "TB" in flags.GeoModel.FaserVersion and source == "Veto": + # The testbeam counters were actually VetoNu, so use those parameters + source = "VetoNu" + + digiAlg.CB_alpha = dict_CB_param[source]["CB_alpha"] + digiAlg.CB_n = dict_CB_param[source]["CB_n"] + digiAlg.CB_mean = dict_CB_param[source]["CB_mean"] + digiAlg.CB_sigma = dict_CB_param[source]["CB_sigma"] + digiAlg.CB_norm = dict_CB_param[source]["CB_norm"] + + digiAlg.base_mean = dict_baseline_params[source]["mean"] + digiAlg.base_rms = dict_baseline_params[source]["rms"] + + kwargs.setdefault("WaveformDigitisationTool", tool) + + acc.addEventAlgo(digiAlg) + + return acc + +def ScintWaveformDigitizationOutputCfg(flags, **kwargs): + """ Return ComponentAccumulator with output for Waveform Digi""" + acc = ComponentAccumulator() + ItemList = [ + "RawWaveformContainer#*" + ] + acc.merge(OutputStreamCfg(flags, "RDO")) + ostream = acc.getEventAlgo("OutputStreamRDO") + # 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 new file mode 100644 index 0000000000000000000000000000000000000000..7eb12286567c42591314592ece065136a754d43d --- /dev/null +++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx @@ -0,0 +1,178 @@ +#include "ScintWaveformDigiAlg.h" + +#include "ScintSimEvent/ScintHitIdHelper.h" + +#include <map> + + +ScintWaveformDigiAlg::ScintWaveformDigiAlg(const std::string& name, + ISvcLocator* pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator) { + +} + +StatusCode +ScintWaveformDigiAlg::initialize() { + ATH_MSG_INFO(name() << "::initalize()" ); + + // Initalize tools + ATH_CHECK( m_digiTool.retrieve() ); + ATH_CHECK( m_mappingTool.retrieve() ); + + // Set key to read waveform from + ATH_CHECK( m_scintHitContainerKey.initialize() ); + + // Set key to write container + ATH_CHECK( m_waveformContainerKey.initialize() ); + + // 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; +} + +StatusCode +ScintWaveformDigiAlg::finalize() { + ATH_MSG_INFO(name() << "::finalize()"); + + delete m_kernel; + + return StatusCode::SUCCESS; +} + +StatusCode +ScintWaveformDigiAlg::execute(const EventContext& ctx) const { + ATH_MSG_DEBUG("Executing"); + ATH_MSG_DEBUG("Run: " << ctx.eventID().run_number() << " Event: " << ctx.eventID().event_number()); + + // Find the input HITS collection + SG::ReadHandle<ScintHitCollection> scintHitHandle(m_scintHitContainerKey, ctx); + + ATH_CHECK( scintHitHandle.isValid() ); + ATH_MSG_DEBUG("Found ReadHandle for ScintHitCollection " << m_scintHitContainerKey); + + // Find the output waveform container + SG::WriteHandle<RawWaveformContainer> waveformContainerHandle(m_waveformContainerKey, ctx); + 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); + } + } + + // 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"); + + return StatusCode::SUCCESS; +} diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..528325621b279bdc3f570c6e5ade93fe549b6c12 --- /dev/null +++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h @@ -0,0 +1,126 @@ +#ifndef SCINTDIGIALGS_SCINTWAVEFORMDIGIALG_H +#define SCINTDIGIALGS_SCINTWAVEFORMDIGIALG_H + +// Base class +#include "AthenaBaseComps/AthReentrantAlgorithm.h" + +// Data classes +#include "WaveRawEvent/RawWaveformContainer.h" +#include "ScintSimEvent/ScintHitCollection.h" + +// Tool classes +#include "WaveDigiTools/IWaveformDigitisationTool.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" + +// Handles +#include "StoreGate/ReadHandleKey.h" +#include "StoreGate/WriteHandleKey.h" + +// Gaudi +#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 { + + public: + // Constructor + ScintWaveformDigiAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~ScintWaveformDigiAlg() = default; + + /** @name Usual algorithm methods */ + //@{ + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + //@} + + + private: + + /** @name Disallow default instantiation, copy, assignment */ + //@{ + ScintWaveformDigiAlg() = delete; + ScintWaveformDigiAlg(const ScintWaveformDigiAlg&) = delete; + 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"}; + Gaudi::Property<double> m_CB_sigma {this, "CB_sigma", 0, "Sigma of the crystal ball function"}; + Gaudi::Property<double> m_CB_norm {this, "CB_norm", 0, "Norm of the crystal ball function"}; + + 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 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 + */ + ToolHandle<IWaveformDigitisationTool> m_digiTool + {this, "WaveformDigitisationTool", "WaveformDigitisationTool"}; + + /** + * @name Mapping tool + */ + ToolHandle<IWaveformCableMappingTool> m_mappingTool + {this, "WaveformCableMappingTool", "WaveformCableMappingTool"}; + + /** + * @name Input HITS using SG::ReadHandleKey + */ + //@{ + + SG::ReadHandleKey<ScintHitCollection> m_scintHitContainerKey + {this, "ScintHitContainerKey", ""}; + + //@} + + + /** + * @name Output data using SG::WriteHandleKey + */ + //@{ + SG::WriteHandleKey<RawWaveformContainer> m_waveformContainerKey + {this, "WaveformContainerKey", ""}; + //@} + +}; + + +#endif // SCINTDIGIALGS_SCINTDIGIALG_H diff --git a/Scintillator/ScintDigiAlgs/src/components/ScintDigiAlgs_entries.cxx b/Scintillator/ScintDigiAlgs/src/components/ScintDigiAlgs_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3a8deff1f06b692e1cf0928472fb12426274f059 --- /dev/null +++ b/Scintillator/ScintDigiAlgs/src/components/ScintDigiAlgs_entries.cxx @@ -0,0 +1,2 @@ +#include "../ScintWaveformDigiAlg.h" +DECLARE_COMPONENT( ScintWaveformDigiAlg ) diff --git a/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.cxx b/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.cxx index 88592d298b2eb974007a73c15ad2413beb193648..f9c937aa22c8a69153e7c32174d4c1009e9b5845 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.cxx +++ b/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.cxx @@ -3,6 +3,7 @@ */ #include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h" #include "ScintSimEventTPCnv/ScintHits/ScintHit_p1.h" #include "ScintHitCollectionCnv.h" @@ -18,11 +19,19 @@ ScintHitCollection_PERS* ScintHitCollectionCnv::createPersistent(ScintHitCollect ScintHitCollection* ScintHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "ScintHitCollectionConverter" ); ScintHitCollectionCnv_p1 converter_p1; + ScintHitCollectionCnv_p1a converter_p1a; static const pool::Guid p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779"); + static const pool::Guid p1a_guid("0DFC461F-9FF5-4447-B4F0-7CC7157191D1"); ScintHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { + if( this->compareClassGuid(p1a_guid)) + { + std::unique_ptr< ScintHitCollection_p1a > col_vect( this->poolReadObject< ScintHitCollection_p1a >() ); + trans_cont = converter_p1a.createTransient( col_vect.get(), mlog ); + } + else if( this->compareClassGuid(p1_guid)) + { std::unique_ptr< ScintHitCollection_p1 > col_vect( this->poolReadObject< ScintHitCollection_p1 >() ); trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); } else { diff --git a/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.h b/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.h index ca9c329ddad032c35766ad6a271fd7637734b1c0..4cdaf2046a595f763c424baae5f6942ab91a33fd 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.h +++ b/Scintillator/ScintEventCnv/ScintSimEventAthenaPool/src/ScintHitCollectionCnv.h @@ -8,12 +8,14 @@ #include "ScintSimEvent/ScintHitCollection.h" #include "ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1.h" #include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef ScintHitCollection_p1 ScintHitCollection_PERS; -typedef ScintHitCollectionCnv_p1 ScintHitCollectionCnv_PERS; +typedef ScintHitCollection_p1a ScintHitCollection_PERS; +typedef ScintHitCollectionCnv_p1a ScintHitCollectionCnv_PERS; class ScintHitCollectionCnv : public T_AthenaPoolCustomCnv<ScintHitCollection, ScintHitCollection_PERS > { friend class CnvFactory<ScintHitCollectionCnv>; diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/CMakeLists.txt b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/CMakeLists.txt index 89c0c08d0204d449808531439e227498cc824a1a..04ca202da817c0f95b4942bfc62b4c5159a47679 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/CMakeLists.txt +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/CMakeLists.txt @@ -22,5 +22,5 @@ atlas_add_dictionary( ScintSimEventTPCnvDict ScintSimEventTPCnv/ScintSimEventTPCnvDict.h ScintSimEventTPCnv/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv ScintSimEvent TestTools StoreGateLib SGtests Identifier ScintSimEventTPCnv ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv ScintSimEvent TestTools StoreGateLib SGtests Identifier ScintSimEventTPCnv AthenaKernel ) diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..4f8de2b4c704240402bdf5ea23a36cf3a12acefe --- /dev/null +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SCINTHITCOLLECTIONCNV_P1A_H +#define SCINTHITCOLLECTIONCNV_P1A_H + +// ScintHitCollectionCnv_p1, T/P separation of Scint Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "ScintSimEvent/ScintHitCollection.h" +#include "ScintHitCollection_p1a.h" + + +class ScintHitCollectionCnv_p1a : public T_AthenaPoolTPCnvBase<ScintHitCollection, ScintHitCollection_p1a> +{ + public: + + ScintHitCollectionCnv_p1a() {}; + + virtual ScintHitCollection* createTransient(const ScintHitCollection_p1a* persObj, MsgStream &log); + + virtual void persToTrans(const ScintHitCollection_p1a* persCont, + ScintHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const ScintHitCollection* transCont, + ScintHitCollection_p1a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h new file mode 100644 index 0000000000000000000000000000000000000000..8e714d6e571c746ae6376536ed62c5681476232e --- /dev/null +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SCINTHITCOLLECTION_P1A_H +#define SCINTHITCOLLECTION_P1A_H + +/* + +Authors: Davide Costanzo Rob Duxfield + +*/ + +#include <vector> +#include <string> + +class ScintHitCollection_p1a +{ + public: +/// Default constructor + ScintHitCollection_p1a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned long> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +ScintHitCollection_p1a::ScintHitCollection_p1a () {} + +#endif diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintSimEventTPCnvDict.h b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintSimEventTPCnvDict.h index f0042a97ec671d78b8fb783af5f516116570952a..1606077dd0efcd14371c1c7445d7a553b0b0579d 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintSimEventTPCnvDict.h +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/ScintSimEventTPCnvDict.h @@ -15,6 +15,8 @@ #include "ScintSimEventTPCnv/ScintHits/ScintHitCnv_p1.h" #include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1.h" #include "ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h" #include "ScintSimEventTPCnv/ScintHits/ScintHit_p1.h" #endif // SCINTEVENTTPCNV_SCINTSIMEVENTTPCNVDICT_H diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/selection.xml b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/selection.xml index 6b0d915eac9a1e2fedb5f8254bbbf419dec16dac..345d08165aeb11723e94f19e7195f42fcb5a88af 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/selection.xml +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/ScintSimEventTPCnv/selection.xml @@ -4,4 +4,5 @@ <class name="ScintHit_p1" /> <class name="std::vector<ScintHit_p1>" /> <class name="ScintHitCollection_p1" id="B2573A16-4B46-4E1E-98E3-F93421680779" /> + <class name="ScintHitCollection_p1a" id="0DFC461F-9FF5-4447-B4F0-7CC7157191D1" /> </lcgdict> diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1.cxx b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1.cxx index 08e4c55e910be26cd47735c49a11bcebad82f446..42b4160a2176e95919d5930140c5abcd7c0e8dfb 100644 --- a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1.cxx +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1.cxx @@ -14,7 +14,10 @@ #include "CLHEP/Geometry/Point3D.h" // Gaudi #include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + // Athena +#include "AthenaKernel/ExtendedEventContext.h" #include "StoreGate/StoreGateSvc.h" // * * * stolen from eflowRec * * * // @@ -60,7 +63,7 @@ const double ScintHitCollectionCnv_p1::m_2bHalfMaximum = pow(2.0, 15.0); const int ScintHitCollectionCnv_p1::m_2bMaximum = (unsigned short)(-1); -void ScintHitCollectionCnv_p1::transToPers(const ScintHitCollection* transCont, ScintHitCollection_p1* persCont, MsgStream &/*log*/) +void ScintHitCollectionCnv_p1::transToPers(const ScintHitCollection* transCont, ScintHitCollection_p1* persCont, MsgStream &log) { // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and // persistifies the end point of each hit plus the start point of the first hit in each string. @@ -77,6 +80,8 @@ void ScintHitCollectionCnv_p1::transToPers(const ScintHitCollection* transCont, static const double dRcut = 1.0e-7; static const double dTcut = 1.0; + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); const HepMcParticleLink * lastLink=nullptr; int lastId = -1; double stringFirstTheta = 0.0; @@ -98,11 +103,22 @@ void ScintHitCollectionCnv_p1::transToPers(const ScintHitCollection* transCont, if ( !lastLink || (siHit->particleLink() != *lastLink) ) { - // store barcode once for set of consecutive hits with same barcode + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode lastLink = &(siHit->particleLink()); persCont->m_barcode.push_back(lastLink->barcode()); - persCont->m_mcEvtIndex.push_back(lastLink->eventIndex()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); if (idx > 0) { @@ -250,6 +266,8 @@ ScintHitCollection* ScintHitCollectionCnv_p1::createTransient(const ScintHitColl void ScintHitCollectionCnv_p1::persToTrans(const ScintHitCollection_p1* persCont, ScintHitCollection* transCont, MsgStream &/*log*/) { + const EventContext& ctx = Gaudi::Hive::currentContext(); + unsigned int hitCount = 0; unsigned int angleCount = 0; unsigned int idxBC = 0; @@ -299,7 +317,11 @@ void ScintHitCollectionCnv_p1::persToTrans(const ScintHitCollection_p1* persCont HepGeom::Point3D<double> endThis( endLast + r ); - HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), HepMcParticleLink::IS_INDEX ); + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); endLast = endThis; diff --git a/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1a.cxx b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1a.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cd162d1ad3c8064966a59c3517b19b233bc29c80 --- /dev/null +++ b/Scintillator/ScintEventCnv/ScintSimEventTPCnv/src/ScintHits/ScintHitCollectionCnv_p1a.cxx @@ -0,0 +1,334 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ScintSimEvent/ScintHit.h" +#include "ScintSimEvent/ScintHitCollection.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollection_p1a.h" +#include "ScintSimEventTPCnv/ScintHits/ScintHitCollectionCnv_p1a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "AthenaKernel/ExtendedEventContext.h" +#include "StoreGate/StoreGateSvc.h" + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double ScintHitCollectionCnv_p1a::m_persEneUnit = 1.0e-5; +const double ScintHitCollectionCnv_p1a::m_persLenUnit = 1.0e-5; +const double ScintHitCollectionCnv_p1a::m_persAngUnit = 1.0e-5; +const double ScintHitCollectionCnv_p1a::m_2bHalfMaximum = pow(2.0, 15.0); +const int ScintHitCollectionCnv_p1a::m_2bMaximum = (unsigned short)(-1); + + +void ScintHitCollectionCnv_p1a::transToPers(const ScintHitCollection* transCont, ScintHitCollection_p1a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (ScintHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + ScintHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store id once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); +} + + +ScintHitCollection* ScintHitCollectionCnv_p1a::createTransient(const ScintHitCollection_p1a* persObj, MsgStream &log) { + std::unique_ptr<ScintHitCollection> trans(std::make_unique<ScintHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void ScintHitCollectionCnv_p1a::persToTrans(const ScintHitCollection_p1a* persCont, ScintHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + + if (persCont->m_nHits[i]) { + + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } +} diff --git a/Scintillator/ScintG4/PreshowerG4_SD/python/PreshowerG4_SDToolConfig.py b/Scintillator/ScintG4/PreshowerG4_SD/python/PreshowerG4_SDToolConfig.py index 96b90c45b32b2b96a801ee724f348004b59cc5a5..8dc2325ffc0a104762b605912b7232cad3f88b40 100644 --- a/Scintillator/ScintG4/PreshowerG4_SD/python/PreshowerG4_SDToolConfig.py +++ b/Scintillator/ScintG4/PreshowerG4_SD/python/PreshowerG4_SDToolConfig.py @@ -18,5 +18,7 @@ def PreshowerSensorSDCfg(ConfigFlags, name="PreshowerSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["Preshower::Plate"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, PreshowerSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.PreshowerSensorSDTool(name, **kwargs)) + return result + diff --git a/Scintillator/ScintG4/TriggerG4_SD/python/TriggerG4_SDToolConfig.py b/Scintillator/ScintG4/TriggerG4_SD/python/TriggerG4_SDToolConfig.py index dae6ba9784424a43377d5fa2d9d321d0befbdd38..2d049e14e2d104ad36b9dfffcd6b5a0a23aa1ff4 100644 --- a/Scintillator/ScintG4/TriggerG4_SD/python/TriggerG4_SDToolConfig.py +++ b/Scintillator/ScintG4/TriggerG4_SD/python/TriggerG4_SDToolConfig.py @@ -18,5 +18,7 @@ def TriggerSensorSDCfg(ConfigFlags, name="TriggerSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["Trigger::Plate"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, TriggerSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.TriggerSensorSDTool(name, **kwargs)) + return result + diff --git a/Scintillator/ScintG4/VetoG4_SD/python/VetoG4_SDToolConfig.py b/Scintillator/ScintG4/VetoG4_SD/python/VetoG4_SDToolConfig.py index ccc50ce9930063c2354d4d6f5d17688295ef9802..95000f8608cacc3b16dd0adf294370cdd80f1207 100644 --- a/Scintillator/ScintG4/VetoG4_SD/python/VetoG4_SDToolConfig.py +++ b/Scintillator/ScintG4/VetoG4_SD/python/VetoG4_SDToolConfig.py @@ -18,5 +18,7 @@ def VetoSensorSDCfg(ConfigFlags, name="VetoSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["Veto::Plate"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, VetoSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.VetoSensorSDTool(name, **kwargs)) + return result + 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/G4Extensions/Pythia8Decayer/CMakeLists.txt b/Simulation/G4Extensions/Pythia8Decayer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..57dcf64bd972fbc0cea03f89edf6a1871694c099 --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/CMakeLists.txt @@ -0,0 +1,31 @@ +################################################################################ +# Package: Pythia8Decayer +################################################################################ + +# Declare the package name: +atlas_subdir( Pythia8Decayer ) + +#if( NOT GENERATIONBASE ) + + # External dependencies: + find_package( CLHEP ) + find_package( Geant4 ) + find_package( XercesC ) + find_package( Pythia8 ) + + # Component(s) in the package: + atlas_add_library( Pythia8DecayerLib + src/*.cxx + NO_PUBLIC_HEADERS + PRIVATE_INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${PYTHIA8_INCLUDE_DIRS} + PRIVATE_LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} ${PYTHIA8_LIBRARIES} FaserMCTruth GaudiKernel AthenaBaseComps G4AtlasInterfaces G4AtlasToolsLib Pythia8_iLib ) + + atlas_add_component( Pythia8Decayer + src/components/*.cxx + INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${PYTHIA8_INCLUDE_DIRS} + LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} ${PYTHIA8_LIBRARIES} Pythia8DecayerLib AthenaBaseComps G4AtlasInterfaces ) +#endif() + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) +#atlas_install_joboptions( share/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} --extend-ignore=F401,F821 ) diff --git a/Simulation/G4Extensions/Pythia8Decayer/python/Pythia8DecayerConfigNew.py b/Simulation/G4Extensions/Pythia8Decayer/python/Pythia8DecayerConfigNew.py new file mode 100644 index 0000000000000000000000000000000000000000..6085f5cca62f25d1d6fa4e6d97fb6ab30575cccd --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/python/Pythia8DecayerConfigNew.py @@ -0,0 +1,11 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + +from AthenaConfiguration.ComponentFactory import CompFactory +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaCommon import Logging +import os + +def Pythia8DecayerPhysicsToolCfg(flags, name='Pythia8DecayerPhysicsTool', **kwargs): + result = ComponentAccumulator() + result.setPrivateTools( CompFactory.Pythia8DecayerPhysicsTool(name,**kwargs) ) + return result diff --git a/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.cxx b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a6f9ea097841a1888761efde8f32303cff44a4ba --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.cxx @@ -0,0 +1,147 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Header for my class +#include "Pythia8Decayer.h" + +#include "FaserMCTruth/FaserTrackInformation.h" + +// For passing things around +#include "CLHEP/Vector/LorentzVector.h" +#include "G4Track.hh" +#include "G4DynamicParticle.hh" +#include "G4ParticleTable.hh" +#include "G4DecayProducts.hh" +#include "G4VProcess.hh" + +Pythia8Decayer::Pythia8Decayer( const std::string s ) + : G4VExtDecayer(s) +{ + // In the constructor, make a decayer instance, so that it's initialized here and not in the event loop + std::string docstring = Pythia8_i::xmlpath(); + m_decayer = std::make_unique<Pythia8::Pythia>(docstring); + + m_decayer->readString("ProcessLevel:all = off"); + + m_decayer->readString("ProcessLevel:resonanceDecays=on"); + + // shut off Pythia8 (default) verbosty + // + m_decayer->readString("Init:showAllSettings=false"); + m_decayer->readString("Init:showChangedSettings=false"); + m_decayer->readString("Init:showAllParticleData=false"); + m_decayer->readString("Init:showChangedParticleData=false"); + // + // specify how many Py8 events to print out, at either level + // in this particular case print out a maximum of 10 events + // + m_decayer->readString("Next:numberShowProcess = 0" ); + m_decayer->readString("Next:numberShowEvent = 10"); + + m_decayer->init(); + + // shut off decays of pi0's as we want Geant4 to handle them + // if other immediate decay products should be handled by Geant4, + // their respective decay modes should be shut off as well + // + m_decayer->readString("111:onMode = off"); +} + +G4DecayProducts* Pythia8Decayer::ImportDecayProducts(const G4Track& aTrack){ + + m_decayer->event.reset(); + + G4DecayProducts* dproducts = nullptr; + + G4ParticleDefinition* pd = aTrack.GetDefinition(); + int pdgid = pd->GetPDGEncoding(); + + // check if pdgid is consistent with Pythia8 particle table + // + if ( !m_decayer->particleData.findParticle( pdgid ) ) + { + G4cout << " can NOT find pdgid = " << pdgid + << " in Pythia8::ParticleData" << G4endl; + return dproducts; + } + + if ( !m_decayer->particleData.canDecay(pdgid) ) + { + G4cout << " Particle of pdgid = " << pdgid + << " can NOT be decayed by Pythia8" << G4endl; + return dproducts; + } + + // NOTE: Energy should be in GeV + + m_decayer->event.append( pdgid, 1, 0, 0, + aTrack.GetMomentum().x() / CLHEP::GeV, + aTrack.GetMomentum().y() / CLHEP::GeV, + aTrack.GetMomentum().z() / CLHEP::GeV, + aTrack.GetDynamicParticle()->GetTotalEnergy() / CLHEP::GeV, + pd->GetPDGMass() / CLHEP::GeV ); + + // specify polarization, if any + + // special logic for primary taus(anti-taus), assumed to have polarization -1(+1), respectively + // verified from the polarization info in Genie output + double spinup; + FaserTrackInformation* info = dynamic_cast<FaserTrackInformation*>(aTrack.GetUserInformation()); + if (info != nullptr && abs(pdgid) == 15 && (info->GetClassification() == TrackClassification::Primary || info->GetClassification() == TrackClassification::RegeneratedPrimary)) + { + G4cout << "Primary tau decay identified." << G4endl; + spinup = (pdgid > 0 ? -1 : +1); + } + else + // NOTE: while in Py8 polarization is a double variable , + // in reality it's expected to be -1, 0., or 1 in case of "external" tau's, + // similar to LHA SPINUP; see Particle Decays, Hadron and Tau Decays in docs at + // https://pythia.org/manuals/pythia8305/Welcome.html + // so it's not able to handle anything like 0.99, thus we're rounding off + { + spinup = round( std::cos( aTrack.GetPolarization().angle( aTrack.GetMomentumDirection() ) ) ); + } + G4cout << "Using " << aTrack.GetParticleDefinition()->GetParticleName() << " helicity " << spinup << " for Pythia8 decay." << G4endl; + m_decayer->event.back().pol( spinup ); + + int npart_before_decay = m_decayer->event.size(); + + m_decayer->next(); + + int npart_after_decay = m_decayer->event.size(); + + // create & fill up decay products + // + dproducts = new G4DecayProducts(*(aTrack.GetDynamicParticle())); + + // create G4DynamicParticle out of each m_decayer->event entry (except the 1st one) + // and push into dproducts + + for ( int ip=npart_before_decay; ip<npart_after_decay; ++ip ) + { + + // only select final state decay products (direct or via subsequent decays); + // skip all others + // + // NOTE: in general, final state decays products will have + // positive status code between 91 and 99 + // (in case such information could be of interest in the future) + // + if ( m_decayer->event[ip].status() < 0 ) continue; + + // should we also skip neutrinos ??? + // if so, skip products with abs(m_decayer->event[ip].id()) of 12, 14, or 16 + + G4ParticleDefinition* pddec = + G4ParticleTable::GetParticleTable()->FindParticle( m_decayer->event[ip].id() ); + if ( !pddec ) continue; // maybe we should print out a warning ! + G4ThreeVector momentum = G4ThreeVector( m_decayer->event[ip].px() * CLHEP::GeV, + m_decayer->event[ip].py() * CLHEP::GeV, + m_decayer->event[ip].pz() * CLHEP::GeV ); + dproducts->PushProducts( new G4DynamicParticle( pddec, momentum) ); + } + dproducts->DumpInfo(); + return dproducts; + +} diff --git a/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.h b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.h new file mode 100644 index 0000000000000000000000000000000000000000..61b52afc41f5b22e42d39052199af5b228d2032e --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8Decayer.h @@ -0,0 +1,63 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +/// \file eventgenerator/pythia/pythia8decayer/include/Py8Decayer.hh +/// \brief Definition of the Py8Decayer class +/// +/// \author J. Yarba; FNAL +/// + +#ifndef Pythia8Decayer_H +#define Pythia8Decayer_H + +#include "G4VExtDecayer.hh" +#include "globals.hh" + +#include "Pythia8_i/Pythia8_i.h" + +class G4Track; +class G4DecayProducts; + +class Pythia8Decayer : public G4VExtDecayer +{ + + public: + + //ctor & dtor + Pythia8Decayer( const std::string s ); + + virtual G4DecayProducts* ImportDecayProducts(const G4Track&); + + private: + + // data members + std::unique_ptr<Pythia8::Pythia> m_decayer; + +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif diff --git a/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.cxx b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..750272b2c5cfa64e85c55acbb991a7b09208683d --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.cxx @@ -0,0 +1,108 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +// class header +#include "Pythia8DecayerPhysicsTool.h" +// package headers +#include "Pythia8Decayer.h" +// Geant4 headers +#include "globals.hh" +#include "G4ParticleTable.hh" +#include "G4VProcess.hh" +#include "G4ProcessManager.hh" +#include "G4Decay.hh" +#include "G4DecayTable.hh" + +// STL headers +#include <string> + +//============================================================================= +// Standard constructor, initializes variables +//============================================================================= +Pythia8DecayerPhysicsTool::Pythia8DecayerPhysicsTool( const std::string& type, + const std::string& nam, + const IInterface* parent ) + : base_class ( type, nam , parent ) +{ +} + +//============================================================================= +// Destructor +//============================================================================= + +Pythia8DecayerPhysicsTool::~Pythia8DecayerPhysicsTool() +{ +} + +//============================================================================= +// Initialize +//============================================================================= +StatusCode Pythia8DecayerPhysicsTool::initialize( ) +{ + ATH_MSG_DEBUG("Pythia8DecayerPhysicsTool initialize( )"); + this->SetPhysicsName(name()); + return StatusCode::SUCCESS; +} + +Pythia8DecayerPhysicsTool* Pythia8DecayerPhysicsTool::GetPhysicsOption() +{ + return this; +} + + +void Pythia8DecayerPhysicsTool::ConstructParticle() +{ + // nothing to do here +} +void Pythia8DecayerPhysicsTool::ConstructProcess() +{ + ATH_MSG_DEBUG("Pythia8DecayerPhysicsTool::ConstructProcess() called "); + + Pythia8Decayer* extDecayer = new Pythia8Decayer(name()); + + auto particleIterator=GetParticleIterator(); + particleIterator->reset(); + while ((*particleIterator)()) + { + G4ParticleDefinition* particle = particleIterator->value(); + G4ProcessManager* pmanager = particle->GetProcessManager(); + G4ProcessVector* processVector = pmanager->GetProcessList(); + for ( size_t i=0; i<processVector->length(); ++i ) + { + G4Decay* decay = dynamic_cast<G4Decay*>((*processVector)[i]); + if ( decay ) + { + // remove native/existing decay table for + // a)tau's + // b) B+/- + // and replace with external decayer + if ( std::abs(particle->GetPDGEncoding()) == 15 || + std::abs(particle->GetPDGEncoding()) == 521 ) + { + if ( particle->GetDecayTable() ) + { + delete particle->GetDecayTable(); + particle->SetDecayTable(nullptr); + } + decay->SetExtDecayer(extDecayer); + G4cout << "Setting ext decayer for: " + << particleIterator->value()->GetParticleName() + << G4endl; + } + // now set external decayer to all particles + // that don't yet have a decay table + if ( !particle->GetDecayTable() ) + { + decay->SetExtDecayer(extDecayer); + G4cout << "Setting ext decayer for: " + << particleIterator->value()->GetParticleName() + << G4endl; + } + } + } + } + + return; + +} diff --git a/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.h b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.h new file mode 100644 index 0000000000000000000000000000000000000000..9acd13bdaee9a2c145e317161bca9f64251c7a9b --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/src/Pythia8DecayerPhysicsTool.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +#ifndef PYTHIA8DECAYER_PYTHIA8DECAYERPHYSICSTOOL_H +#define PYTHIA8DECAYER_PYTHIA8DECAYERPHYSICSTOOL_H + +// Include files +#include "AthenaBaseComps/AthAlgTool.h" +#include "G4AtlasInterfaces/IPhysicsOptionTool.h" +#include "G4VPhysicsConstructor.hh" + +/** @class Pythia8DecayerPhysicsTool Pythia8DecayerPhysicsTool.h "Pythia8Decayer/Pythia8DecayerPhysicsTool.h" + * + * + * + * @author Edoardo Farina (modified for FASER by D. Casper) + * @date 2015-05-14 + */ +class Pythia8DecayerPhysicsTool : public G4VPhysicsConstructor, public extends<AthAlgTool, IPhysicsOptionTool> +{ +public: + /// Standard constructor + Pythia8DecayerPhysicsTool( const std::string& type , const std::string& name, + const IInterface* parent ) ; + + virtual ~Pythia8DecayerPhysicsTool( ); ///< Destructor + + /// Initialize method + virtual StatusCode initialize( ) ; + virtual void ConstructParticle(); + virtual void ConstructProcess(); + + /** Implements + */ + + virtual Pythia8DecayerPhysicsTool* GetPhysicsOption(); + +}; + + + +#endif diff --git a/Simulation/G4Extensions/Pythia8Decayer/src/components/Pythia8Decayer_entries.cxx b/Simulation/G4Extensions/Pythia8Decayer/src/components/Pythia8Decayer_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8bbd46608e2fe53980a4338c03dcd06abcf61e59 --- /dev/null +++ b/Simulation/G4Extensions/Pythia8Decayer/src/components/Pythia8Decayer_entries.cxx @@ -0,0 +1,4 @@ +#include "../Pythia8DecayerPhysicsTool.h" + +DECLARE_COMPONENT( Pythia8DecayerPhysicsTool ) + 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/src/G4FaserAlg.cxx b/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.cxx index 3ce528b032fd0ce76494e114623aa753dbc0345c..69ff7cfd61bceff6cebf6a01043012c78c0a379b 100644 --- a/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.cxx +++ b/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.cxx @@ -30,6 +30,9 @@ #include "G4VModularPhysicsList.hh" #include "G4ParallelWorldPhysics.hh" +#include "G4LogicalVolumeStore.hh" +#include "G4GDMLParser.hh" + // CLHEP includes #include "CLHEP/Random/RandomEngine.h" @@ -197,6 +200,14 @@ void G4FaserAlg::initializeOnce() if(m_userLimitsSvc.retrieve().isFailure()) { throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!"); } + + if (!m_gdmlFilename.empty()) + { + G4LogicalVolumeStore* store = G4LogicalVolumeStore::GetInstance(); + G4LogicalVolume* world = store->GetVolume("Faser::Faser"); + G4GDMLParser parser {}; + parser.Write(m_gdmlFilename.value(), world); + } if (m_activateParallelGeometries) { G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList()); diff --git a/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.h b/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.h index 420e23f7154244d03d1645aeeddcdf95e7c08ba4..1dbadf47ac6ed83bd5012ead048d077d951e624f 100644 --- a/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.h +++ b/Simulation/G4Faser/G4FaserAlg/src/G4FaserAlg.h @@ -120,6 +120,8 @@ private: /// Activate multi-threading configuration Gaudi::Property<bool> m_useMT{this,"MultiThreading", false, "Multi-threading specific settings"}; Gaudi::Property<bool> m_activateParallelGeometries{this, "ActivateParallelWorlds", false, "Toggle on/off the G4 parallel geometry system"}; + /// Dump GDML file + Gaudi::Property<std::string> m_gdmlFilename{this, "GDMLfile", "", "GDML geometry file to write"}; /// Random number service ServiceHandle<IAthRNGSvc> m_rndmGenSvc{this, "AtRndmGenSvc", "AthRNGSvc", ""}; // TODO rename property /// Random Stream Name 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/G4FaserAlg/test/runGeantinoScan.py b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py index 7e0a93719a520de7bb819fe270f8666a00c42f5c..46021eb4bc7a37eefbcdfd0b14ab72349c563364 100644 --- a/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py +++ b/Simulation/G4Faser/G4FaserAlg/test/runGeantinoScan.py @@ -19,41 +19,34 @@ if __name__ == "__main__": from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg - from G4FaserAlg.G4FaserAlgConfigNew import G4FaserMaterialStepRecorderAlgCfg from G4FaserServices.G4FaserServicesConfigNew import G4GeometryNotifierSvcCfg + from G4FaserServices.G4FaserUserActionConfigNew import UserActionMaterialStepRecorderSvcCfg # # Set up logging and new style config # log.setLevel(VERBOSE) Configurable.configurableRun3Behavior = True -# -# Input settings (Generator file) -# -# from AthenaConfiguration.TestDefaults import defaultTestFiles -# ConfigFlags.Input.Files = defaultTestFiles.EVNT -# -# Alternatively, these must ALL be explicitly set to run without an input file -# (if missing, it will try to read metadata from a non-existent file and crash) -# + from AthenaConfiguration.Enums import ProductionStep + ConfigFlags.Common.ProductionStep = ProductionStep.Simulation + ConfigFlags.Sim.ReleaseGeoModel = False ConfigFlags.Input.Files = [""] ConfigFlags.Input.isMC = True - ConfigFlags.Input.RunNumber = 12345 - ConfigFlags.Input.Collections = [""] - ConfigFlags.Input.ProjectName = "mc19" + ConfigFlags.Input.RunNumber = [12345] + ConfigFlags.Input.OverrideRunNumber = True + ConfigFlags.Input.LumiBlockNumber = [1] + Configurable.configurableRun3Behavior = 1 ConfigFlags.Common.isOnline = False ConfigFlags.Beam.Type = "collisions" ConfigFlags.Beam.Energy = 7*TeV # Informational, does not affect simulation - ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Always needed - ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion -# Workaround for bug/missing flag; unimportant otherwise + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Always needed + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion ConfigFlags.addFlag("Input.InitialTimeStamp", 0) -# Workaround to avoid problematic ISF code - ConfigFlags.GeoModel.Layout = "Development" # # Output settings # ConfigFlags.Output.HITSFileName = "MaterialStepCollection.root" ConfigFlags.GeoModel.GeoExportFile = "faserGeo.db" # Optional dump of geometry for browsing in vp1light + ConfigFlags.GeoModel.Align.Dynamic = False # # Geometry-related settings # Do not change! @@ -61,8 +54,6 @@ if __name__ == "__main__": detectors = ['Veto', 'Trigger', 'Preshower', 'FaserSCT', 'Dipole', 'Ecal'] from CalypsoConfiguration.DetectorConfigFlags import setupDetectorsFromList setupDetectorsFromList(ConfigFlags, detectors, toggle_geometry=True) - ConfigFlags.GeoModel.Align.Dynamic = False - ConfigFlags.Sim.ReleaseGeoModel = False # # All flags should be set before calling lock # @@ -79,9 +70,9 @@ if __name__ == "__main__": pg.McEventKey = "BeamTruthEvent" pg.randomSeed = 123456 pg.sampler.pid = 999 - pg.sampler.mom = PG.EThetaMPhiSampler(energy=1*TeV, theta=[0, pi/20], phi=[0, 2*pi]) - pg.sampler.pos = PG.PosSampler(x=[-5, 5], y=[-5, 5], z=-2100.0, t=0.0) - acc.addEventAlgo(pg, "AthBeginSeq") # to run *before* G4 + pg.sampler.mom = PG.EThetaMPhiSampler(energy=1*TeV, theta=[0, pi/200], phi=[0, 2*pi]) + pg.sampler.pos = PG.PosSampler(x=[-150, 150], y=[-150, 150], z=-2100.0, t=0.0) + acc.addEventAlgo(pg, "AthBeginSeq", primary = True) # to run *before* G4 # # Only one of these two should be used in a given job # (MCEventSelectorCfg for generating events with no input file, @@ -107,7 +98,8 @@ if __name__ == "__main__": # Here is the configuration of the Geant4 pieces # acc.merge(FaserGeometryCfg(ConfigFlags)) - acc.merge(G4FaserMaterialStepRecorderAlgCfg(ConfigFlags)) + acc.merge(UserActionMaterialStepRecorderSvcCfg(ConfigFlags)) + acc.merge(G4FaserAlgCfg(ConfigFlags)) acc.addService(G4GeometryNotifierSvcCfg(ConfigFlags, ActivateLVNotifier=True)) # # Verbosity @@ -125,4 +117,4 @@ if __name__ == "__main__": # # Execute and finish # - sys.exit(int(acc.run(maxEvents=20000).isFailure())) + sys.exit(int(acc.run(maxEvents=1000000).isFailure())) diff --git a/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py b/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py index 839a4fda883d0f8e39f04f4efdc7a632918a6176..1b17627a2ccf83cce04907f5784633b597497d50 100644 --- a/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py +++ b/Simulation/G4Faser/G4FaserServices/python/G4FaserServicesConfigNew.py @@ -5,6 +5,8 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator DetectorGeometrySvc, G4AtlasSvc, G4GeometryNotifierSvc, PhysicsListSvc=CompFactory.getComps("DetectorGeometrySvc","G4AtlasSvc","G4GeometryNotifierSvc","PhysicsListSvc",) from G4FaserTools.G4GeometryToolConfig import G4AtlasDetectorConstructionToolCfg +from G4StepLimitation.G4StepLimitationConfigNew import G4StepLimitationToolCfg +from Pythia8Decayer.Pythia8DecayerConfigNew import Pythia8DecayerPhysicsToolCfg def DetectorGeometrySvcCfg(ConfigFlags, name="DetectorGeometrySvc", **kwargs): result = ComponentAccumulator() @@ -34,9 +36,9 @@ def G4GeometryNotifierSvcCfg(ConfigFlags, name="G4GeometryNotifierSvc", **kwargs def PhysicsListSvcCfg(ConfigFlags, name="PhysicsListSvc", **kwargs): result = ComponentAccumulator() - G4StepLimitationTool = CompFactory.G4StepLimitationTool - PhysOptionList = [G4StepLimitationTool("G4StepLimitationTool")] + PhysOptionList = [ result.popToolsAndMerge(G4StepLimitationToolCfg(ConfigFlags)) ] #PhysOptionList += ConfigFlags.Sim.PhysicsOptions # FIXME Missing functionality + PhysOptionList += [ result.popToolsAndMerge(Pythia8DecayerPhysicsToolCfg(ConfigFlags)) ] PhysDecaysList = [] kwargs.setdefault("PhysOption", PhysOptionList) kwargs.setdefault("PhysicsDecay", PhysDecaysList) diff --git a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py index 3520b26d0df3e3bc948c8b69cedf4de6cc5aecb6..8f01d6b15fca1ff7a591132160aed2a2e31ff283 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4FaserToolsConfigNew.py @@ -2,7 +2,6 @@ from __future__ import print_function from AthenaConfiguration.ComponentFactory import CompFactory - from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaCommon import CfgMgr SensitiveDetectorMasterTool=CompFactory.SensitiveDetectorMasterTool @@ -21,103 +20,81 @@ def FastSimulationMasterToolCfg(ConfigFlags, **kwargs): result.setPrivateTools(FastSimulationMasterTool(name="FastSimulationMasterTool", **kwargs)) return result -from EmulsionG4_SD.EmulsionG4_SDToolConfig import EmulsionSensorSDCfg -from VetoG4_SD.VetoG4_SDToolConfig import VetoSensorSDCfg -from TriggerG4_SD.TriggerG4_SDToolConfig import TriggerSensorSDCfg -from PreshowerG4_SD.PreshowerG4_SDToolConfig import PreshowerSensorSDCfg -from FaserSCT_G4_SD.FaserSCT_G4_SDToolConfig import SctSensorSDCfg -from EcalG4_SD.EcalG4_SDToolConfig import EcalSensorSDCfg +def NeutrinoSensitiveDetectorListCfg(ConfigFlags): + result = ComponentAccumulator() + tools = [] + + if ConfigFlags.Detector.EnableEmulsion: + from EmulsionG4_SD.EmulsionG4_SDToolConfig import EmulsionSensorSDCfg + tools += [ result.popToolsAndMerge(EmulsionSensorSDCfg(ConfigFlags)) ] + + result.setPrivateTools(tools) + return result -def generateNeutrinoSensitiveDetectorList(ConfigFlags): +def CaloSensitiveDetectorListCfg(ConfigFlags): result = ComponentAccumulator() - SensitiveDetectorList=[] + tools = [] - if ConfigFlags.Detector.EnableEmulsion: - accEmulsion,toolEmulsion = EmulsionSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolEmulsion ] - result.merge(accEmulsion) - - return result, SensitiveDetectorList #List of tools here now! (CALL IT TOOL LIST?) + if ConfigFlags.Detector.EnableEcal: + from EcalG4_SD.EcalG4_SDToolConfig import EcalSensorSDCfg + tools += [ result.popToolsAndMerge(EcalSensorSDCfg(ConfigFlags)) ] -def generateScintSensitiveDetectorList(ConfigFlags): + result.setPrivateTools(tools) + return result +def ScintSensitiveDetectorListCfg(ConfigFlags): result = ComponentAccumulator() - SensitiveDetectorList=[] + tools = [] if ConfigFlags.Detector.EnableVeto: - accVeto,toolVeto = VetoSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolVeto ] - result.merge(accVeto) - + 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: - accTrigger,toolTrigger = TriggerSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolTrigger ] - result.merge(accTrigger) - + from TriggerG4_SD.TriggerG4_SDToolConfig import TriggerSensorSDCfg + tools += [ result.popToolsAndMerge(TriggerSensorSDCfg(ConfigFlags)) ] if ConfigFlags.Detector.EnablePreshower: - accPreshower,toolPreshower = PreshowerSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolPreshower ] - result.merge(accPreshower) - - return result, SensitiveDetectorList #List of tools here now! (CALL IT TOOL LIST?) + from PreshowerG4_SD.PreshowerG4_SDToolConfig import PreshowerSensorSDCfg + tools += [ result.popToolsAndMerge(PreshowerSensorSDCfg(ConfigFlags)) ] -def generateTrackerSensitiveDetectorList(ConfigFlags): + result.setPrivateTools(tools) + return result +def TrackerSensitiveDetectorListCfg(ConfigFlags): result = ComponentAccumulator() - SensitiveDetectorList=[] + tools = [] if ConfigFlags.Detector.EnableFaserSCT: - accSCT,toolSCT = SctSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolSCT ] - result.merge(accSCT) - - return result, SensitiveDetectorList #List of tools here now! (CALL IT TOOL LIST?) - -def generateCaloSensitiveDetectorList(ConfigFlags): + from FaserSCT_G4_SD.FaserSCT_G4_SDToolConfig import SctSensorSDCfg + tools += [ result.popToolsAndMerge(SctSensorSDCfg(ConfigFlags)) ] - result = ComponentAccumulator() - SensitiveDetectorList=[] - - if ConfigFlags.Detector.EnableEcal: - accEcal,toolEcal = EcalSensorSDCfg(ConfigFlags) - SensitiveDetectorList += [ toolEcal ] - result.merge(accEcal) - - return result, SensitiveDetectorList #List of tools here now! (CALL IT TOOL LIST?) + result.setPrivateTools(tools) + return result -def generateSensitiveDetectorList(ConfigFlags): +def SensitiveDetectorListCfg(ConfigFlags): result = ComponentAccumulator() - SensitiveDetectorList=[] - # SensitiveDetectorList += generateEnvelopeSensitiveDetectorList(ConfigFlags) # to update - - acc_NeutrinoSensitiveDetector, NeutrinoSensitiveDetectorList = generateNeutrinoSensitiveDetectorList(ConfigFlags) - SensitiveDetectorList += NeutrinoSensitiveDetectorList + tools = [] - acc_ScintSensitiveDetector, ScintSensitiveDetectorList = generateScintSensitiveDetectorList(ConfigFlags) - SensitiveDetectorList += ScintSensitiveDetectorList + tools += result.popToolsAndMerge(CaloSensitiveDetectorListCfg(ConfigFlags)) + tools += result.popToolsAndMerge(ScintSensitiveDetectorListCfg(ConfigFlags)) + tools += result.popToolsAndMerge(TrackerSensitiveDetectorListCfg(ConfigFlags)) + tools += result.popToolsAndMerge(NeutrinoSensitiveDetectorListCfg(ConfigFlags)) - acc_TrackerSensitiveDetector, TrackerSensitiveDetectorList = generateTrackerSensitiveDetectorList(ConfigFlags) - SensitiveDetectorList += TrackerSensitiveDetectorList - - acc_CaloSensitiveDetector, CaloSensitiveDetectorList = generateCaloSensitiveDetectorList(ConfigFlags) - SensitiveDetectorList += CaloSensitiveDetectorList - - result.merge(acc_NeutrinoSensitiveDetector) - result.merge(acc_ScintSensitiveDetector) - result.merge(acc_TrackerSensitiveDetector) - result.merge(acc_CaloSensitiveDetector) - - result.setPrivateTools(SensitiveDetectorList) + result.setPrivateTools(tools) return result def SensitiveDetectorMasterToolCfg(ConfigFlags, name="SensitiveDetectorMasterTool", **kwargs): result = ComponentAccumulator() - accSensitiveDetector = generateSensitiveDetectorList(ConfigFlags) - kwargs.setdefault("SensitiveDetectors", result.popToolsAndMerge(accSensitiveDetector)) #list of tools + kwargs.setdefault("SensitiveDetectors", result.popToolsAndMerge(SensitiveDetectorListCfg(ConfigFlags))) - result.setPrivateTools(SensitiveDetectorMasterTool(name, **kwargs)) #note -this is still a public tool + result.setPrivateTools(CompFactory.SensitiveDetectorMasterTool(name, **kwargs)) return result def getEmptySensitiveDetectorMasterTool(name="EmptySensitiveDetectorMasterTool", **kwargs): - return CfgMgr.SensitiveDetectorMasterTool(name, **kwargs) + result = ComponentAccumulator() + tool = result.popToolsAndMerge(CompFactory.SensitiveDetectorMasterTool(name, **kwargs)) + result.setPrivateTools(tool) + return result 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 992cfbe4fe506841adbbaa052540dc50168f1155..4e6f59490a97baee0020453bb9572fab2b090fbc 100644 --- a/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py +++ b/Simulation/G4Faser/G4FaserTools/python/G4GeometryToolConfig.py @@ -1,4 +1,5 @@ # Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +from __future__ import print_function from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory @@ -6,21 +7,25 @@ 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, SmartlessnessTool, G4AtlasDetectorConstructionTool = CompFactory.getComps("BoxEnvelope", "MaterialDescriptionTool", "SmartlessnessTool", "G4AtlasDetectorConstructionTool",) +BoxEnvelope, MaterialDescriptionTool, VoxelDensityTool, G4AtlasDetectorConstructionTool = CompFactory.getComps("BoxEnvelope", "MaterialDescriptionTool", "VoxelDensityTool", "G4AtlasDetectorConstructionTool",) from AthenaCommon.SystemOfUnits import mm @@ -56,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) @@ -106,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=[] @@ -118,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 ] @@ -137,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 @@ -163,10 +197,20 @@ def MaterialDescriptionToolCfg(ConfigFlags, name="MaterialDescriptionTool", **kw return result -def SmartlessnessToolCfg(ConfigFlags, name="SmartlessnessTool", **kwargs): +def VoxelDensityToolCfg(ConfigFlags, name="VoxelDensityTool", **kwargs): ## kwargs.setdefault("SomeProperty", aValue) + voxelDensitySettings = {} + # if ConfigFlags.Detector.GeometryITkPixel: + # voxelDensitySettings["ITkPixelDetector"] = 0.05 + # if ConfigFlags.Detector.GeometryITkStrip: + # voxelDensitySettings["ITkStrip::Barrel"] = 0.05 + # voxelDensitySettings["ITkStrip::ITkStrip_Forward"] = 0.05 + # ##The below is only needed temporarily, while we wait for + # ##improved naming to be propagated to all necessary geo tags + # voxelDensitySettings["ITkStrip::SCT_Forward"] = 0.05 + kwargs.setdefault("VolumeVoxellDensityLevel",voxelDensitySettings) result = ComponentAccumulator() - result.setPrivateTools(SmartlessnessTool(name, **kwargs)) + result.setPrivateTools(VoxelDensityTool(name, **kwargs)) return result def getFASER_RegionCreatorList(ConfigFlags): @@ -183,6 +227,9 @@ def getFASER_RegionCreatorList(ConfigFlags): if ConfigFlags.Detector.GeometryFaserCalo: regionCreatorList += [EcalPhysicsRegionToolCfg(ConfigFlags)] + + if ConfigFlags.Detector.GeometryFaserCavern: + regionCreatorList += [CavernPhysicsRegionToolCfg(ConfigFlags)] return regionCreatorList @@ -204,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) @@ -229,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 @@ -238,7 +296,7 @@ def getGeometryConfigurationTools(ConfigFlags): # package containing each tool, so G4FaserTools in this case result =ComponentAccumulator() geoConfigToolList += [result.popToolsAndMerge(MaterialDescriptionToolCfg(ConfigFlags))] - geoConfigToolList += [result.popToolsAndMerge(SmartlessnessToolCfg(ConfigFlags))] + geoConfigToolList += [result.popToolsAndMerge(VoxelDensityToolCfg(ConfigFlags))] return result, geoConfigToolList @@ -251,7 +309,9 @@ def G4AtlasDetectorConstructionToolCfg(ConfigFlags, name="G4FaserDetectorConstru kwargs.setdefault("GeometryConfigurationTools", listOfGeoConfTools) # Getting this tool by name works, but not if you use getSensitiveDetectorMasterTool() - kwargs.setdefault('SenDetMasterTool', "SensitiveDetectorMasterTool" ) + tool = result.popToolsAndMerge(SensitiveDetectorMasterToolCfg(ConfigFlags)) + result.addPublicTool(tool) + kwargs.setdefault("SenDetMasterTool", result.getPublicTool(tool.name)) toolGeo = result.popToolsAndMerge(FASEREnvelopeCfg(ConfigFlags)) kwargs.setdefault("World", toolGeo) 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 7260d59fc1e6df1b327196817f8a44c865d72a16..829b0df04de5615d1509b7dbe741c410ef6b41df 100644 --- a/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py +++ b/Simulation/ISF/ISF_Core/FaserISF_Services/python/FaserISF_ServicesConfigNew.py @@ -10,7 +10,8 @@ from AthenaConfiguration.ComponentFactory import CompFactory from BarcodeServices.BarcodeServicesConfigNew import MC15aPlusBarcodeSvcCfg from ISF_HepMC_Tools.ISF_HepMC_ToolsConfigNew import ParticleFinalStateFilterCfg, GenParticleInteractingFilterCfg -from FaserISF_HepMC_Tools.FaserISF_HepMC_ToolsConfigNew import FaserTruthStrategyCfg, FaserDipoleTruthStrategyCfg +# from FaserISF_HepMC_Tools.FaserISF_HepMC_ToolsConfigNew import FaserTruthStrategyCfg, FaserDipoleTruthStrategyCfg +from FaserISF_HepMC_Tools.FaserISF_HepMC_ToolsConfigNew import TruthStrategyGroupCfg, TrenchStrategyGroupCfg ISF__FaserTruthSvc, ISF__FaserGeoIDSvc, ISF__FaserInputConverter = CompFactory.getComps("ISF::FaserTruthSvc","ISF::FaserGeoIDSvc","ISF::FaserInputConverter") @@ -60,9 +61,13 @@ def FaserTruthServiceCfg(ConfigFlags, name="FaserISF_TruthService", **kwargs): result = MC15aPlusBarcodeSvcCfg(ConfigFlags) kwargs.setdefault('BarcodeSvc', result.getService("Barcode_MC15aPlusBarcodeSvc") ) - acc = FaserTruthStrategyCfg(ConfigFlags) - acc2= FaserDipoleTruthStrategyCfg(ConfigFlags) - kwargs.setdefault('TruthStrategies',[result.popToolsAndMerge(acc), result.popToolsAndMerge(acc2)]) + # acc = FaserTruthStrategyCfg(ConfigFlags) + # acc2= FaserDipoleTruthStrategyCfg(ConfigFlags) + # kwargs.setdefault('TruthStrategies',[result.popToolsAndMerge(acc), result.popToolsAndMerge(acc2)]) + acc = TruthStrategyGroupCfg(ConfigFlags) + # FaserNu hack + acc2 = TrenchStrategyGroupCfg(ConfigFlags) + kwargs.setdefault('TruthStrategies', [result.popToolsAndMerge(acc), result.popToolsAndMerge(acc2)]) kwargs.setdefault('SkipIfNoChildren', True) kwargs.setdefault('SkipIfNoParentBarcode', True) @@ -79,7 +84,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_Core/FaserISF_Services/src/FaserTruthSvc.cxx b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.cxx index c3e0607252a06e4d439cf298851b6d2884cef3b9..c43929542e093404fe9f53c884b59196f510e8d5 100644 --- a/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.cxx +++ b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.cxx @@ -128,6 +128,8 @@ StatusCode ISF::FaserTruthSvc::finalize() StatusCode ISF::FaserTruthSvc::initializeTruthCollection() { ATH_CHECK( m_barcodeSvc->initializeBarcodes() ); + m_incrementProcs.clear(); + m_secondaryProcs.clear(); return StatusCode::SUCCESS; } @@ -264,13 +266,20 @@ void ISF::FaserTruthSvc::recordIncidentToMCTruth( ISF::IFaserTruthIncident& ti) newPrimBC = this->maxGeneratedParticleBarcode(ti.parentParticle()->parent_event())+1; } else { + if (m_incrementProcs.count(processCode) == 0) + m_incrementProcs[processCode] = 0; + m_incrementProcs[processCode]++; newPrimBC = m_barcodeSvc->incrementBarcode( parentBC, processCode); } if ( newPrimBC == Barcode::fUndefinedBarcode) { + for (auto pair : m_incrementProcs) + { + ATH_MSG_ALWAYS("Process code: " << pair.first << " : " << pair.second); + } if (m_ignoreUndefinedBarcodes) { ATH_MSG_WARNING("Unable to generate new Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True"); } else { - ATH_MSG_FATAL("Unable to generate new Particle Barcode in region " << ti.geoID() << ". Aborting"); + ATH_MSG_FATAL("Unable to generate new Particle Barcode from " << parentBC << "( id= " << ti.parentPdgCode() << ", Ekin = " << ti.parentEkin()/Gaudi::Units::GeV << " GeV) with process code " << processCode << " in region " << ti.geoID() << ", at vertex (" << vtx->position().x() << ", " << vtx->position().y() << ", " << vtx->position().z() << "). Aborting"); abort(); } } @@ -370,12 +379,20 @@ void ISF::FaserTruthSvc::recordIncidentToMCTruth( ISF::IFaserTruthIncident& ti) } else { // generate a new barcode for the child particle + if (m_secondaryProcs.count(processCode) == 0) + m_secondaryProcs[processCode] = 0; + m_secondaryProcs[processCode]++; Barcode::ParticleBarcode secBC = m_barcodeSvc->newSecondary( parentBC, processCode); if ( secBC == Barcode::fUndefinedBarcode) { + for (auto pair : m_secondaryProcs) + { + ATH_MSG_ALWAYS("Process code: " << pair.first << " : " << pair.second); + } + if (m_ignoreUndefinedBarcodes) ATH_MSG_WARNING("Unable to generate new Secondary Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True"); else { - ATH_MSG_ERROR("Unable to generate new Secondary Particle Barcode. Aborting"); + ATH_MSG_FATAL("Unable to generate new Secondary Particle Barcode from " << parentBC << " with process code " << processCode <<" in region " << ti.geoID() << ", at vertex (" << vtx->position().x() << ", " << vtx->position().y() << ", " << vtx->position().z() << "). Aborting"); abort(); } } diff --git a/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.h b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.h index d674d80782cd3cbc5dfbef9e27939a1f4923dea8..21b4d2717eab17f96cf6e5a40cd25e45499c2b8e 100644 --- a/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.h +++ b/Simulation/ISF/ISF_Core/FaserISF_Services/src/FaserTruthSvc.h @@ -126,6 +126,10 @@ namespace ISF { bool m_quasiStableParticlesIncluded; //!< does this job simulate quasi-stable particles. + mutable std::map<int, int> m_incrementProcs; + mutable std::map<int, int> m_secondaryProcs; + + }; } 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/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py b/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py index a49c04991034dd011d9066b5b9116d317a1cd042..21a86e2026e8a13dee346d43616b677b601f1f7a 100644 --- a/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py +++ b/Simulation/ISF/ISF_HepMC/FaserISF_HepMC_Tools/python/FaserISF_HepMC_ToolsConfigNew.py @@ -153,44 +153,83 @@ def FaserParticleGenericFilterCfg(ConfigFlags, name="ISF_FaserGenericFilter", ** # http://www-geant4.kek.jp/lxr/source//processes/hadronic/management/include/G4HadronicProcessType.hh#L46 -def FaserDipoleTruthStrategyCfg(ConfigFlags, name="ISF_FaserDipoleTruthStrategy", **kwargs): - result = ComponentAccumulator() +def TruthStrategyGroupCfg(ConfigFlags, name="ISF_MCTruthStrategyGroupID", **kwargs): import ROOT, cppyy cppyy.load_library('FaserDetDescrDict') FaserRegion = ROOT.FaserDetDescr.FaserRegion - # - # Save truth in Dipole region - # - kwargs.setdefault('Regions', [FaserRegion.fFaserDipole, - FaserRegion.fFaserNeutrino]) - kwargs.setdefault('ParentMinEkin', 1000.0*MeV) - kwargs.setdefault('ChildMinEkin', 1000.0*MeV) - result.setPrivateTools(ISF__FaserTruthStrategy(name, **kwargs)) - return result - -def FaserTruthStrategyCfg(ConfigFlags, name="ISF_FaserTruthStrategy", **kwargs): result = ComponentAccumulator() + kwargs.setdefault("ParentMinEkin", 100.*MeV) + kwargs.setdefault("ChildMinEkin" , 100.*MeV) + kwargs.setdefault("VertexTypes", [3, 14, 15, 4, 5, 6, 7, 2, 12, 13, 111, 121, 131, 132, 141, 151, 152, 161, 310]) # EM *and* nuclear + kwargs.setdefault("VertexTypeRangeLow" , 201) # All kinds of decay processes + kwargs.setdefault("VertexTypeRangeHigh" , 298) # ... + kwargs.setdefault("Regions", [FaserRegion.fFaserNeutrino, + FaserRegion.fFaserScintillator, + FaserRegion.fFaserTracker, + FaserRegion.fFaserCalorimeter, + FaserRegion.fFaserCavern]) + result.setPrivateTools(CompFactory.ISF.FaserTruthStrategy(name, **kwargs)) + return result + +# FaserNu hack +def TrenchStrategyGroupCfg(ConfigFlags, name="ISF_TrenchStrategyGroupID", **kwargs): import ROOT, cppyy cppyy.load_library('FaserDetDescrDict') FaserRegion = ROOT.FaserDetDescr.FaserRegion - # - # Save truth in all regions except Dipole - # - kwargs.setdefault('Regions', [ - # FaserRegion.fFaserNeutrino, - FaserRegion.fFaserScintillator, - FaserRegion.fFaserTracker, - # FaserRegion.fFaserDipole, - # FaserRegion.fFaserCalorimeter, - FaserRegion.fFaserCavern]) - # kwargs.setdefault('ParentMinEkin', 0.1*MeV) - # kwargs.setdefault('ChildMinEkin', 0.1*MeV) - result.setPrivateTools(ISF__FaserTruthStrategy(name, **kwargs)) + + result = ComponentAccumulator() + kwargs.setdefault("ParentMinEkin", 10000.*MeV) + kwargs.setdefault("ChildMinEkin" , 10000.*MeV) + kwargs.setdefault("VertexTypes", [3, 14, 15, 4, 5, 6, 7, 2, 12, 13, 111, 121, 131, 132, 141, 151, 152, 161, 310]) # EM *and* nuclear + kwargs.setdefault("VertexTypeRangeLow" , 201) # All kinds of decay processes + kwargs.setdefault("VertexTypeRangeHigh" , 298) # ... + kwargs.setdefault("Regions", [FaserRegion.fFaserTrench]) + result.setPrivateTools(CompFactory.ISF.FaserTruthStrategy(name, **kwargs)) return result + +# def FaserDipoleTruthStrategyCfg(ConfigFlags, name="ISF_FaserDipoleTruthStrategy", **kwargs): +# result = ComponentAccumulator() + +# import ROOT, cppyy +# cppyy.load_library('FaserDetDescrDict') +# FaserRegion = ROOT.FaserDetDescr.FaserRegion +# # +# # Save truth in Dipole region +# # +# kwargs.setdefault('Regions', [FaserRegion.fFaserDipole, +# FaserRegion.fFaserNeutrino, +# FaserRegion.fFaserCavern]) +# kwargs.setdefault('ParentMinEkin', 1000.0*MeV) +# kwargs.setdefault('ChildMinEkin', 1000.0*MeV) +# result.setPrivateTools(ISF__FaserTruthStrategy(name, **kwargs)) +# return result + + +# def FaserTruthStrategyCfg(ConfigFlags, name="ISF_FaserTruthStrategy", **kwargs): +# result = ComponentAccumulator() + +# import ROOT, cppyy +# cppyy.load_library('FaserDetDescrDict') +# FaserRegion = ROOT.FaserDetDescr.FaserRegion +# # +# # Save truth in all regions except Dipole +# # +# kwargs.setdefault('Regions', [ +# # FaserRegion.fFaserNeutrino, +# FaserRegion.fFaserScintillator, +# FaserRegion.fFaserTracker]) +# # FaserRegion.fFaserDipole, +# # FaserRegion.fFaserCalorimeter, +# # FaserRegion.fFaserCavern]) +# # kwargs.setdefault('ParentMinEkin', 0.1*MeV) +# # kwargs.setdefault('ChildMinEkin', 0.1*MeV) +# result.setPrivateTools(ISF__FaserTruthStrategy(name, **kwargs)) +# return result + # def TruthStrategyGroupID_MC15Cfg(ConfigFlags, name="ISF_MCTruthStrategyGroupID_MC15", **kwargs): # result = ComponentAccumulator() # kwargs.setdefault('ParentMinPt' , 100.*MeV) diff --git a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx index 77714ac0974d54b0f6292a74a174cc86a6c7cf29..4483eb5b4cd52b31aa70cb915ba6500641297685 100644 --- a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx +++ b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + */ // TrackerAlignDBTool.cxx // AlgTool to manage the SCT AlignableTransforms in the conditions store @@ -12,6 +12,9 @@ #include "AthenaPoolUtilities/CondAttrListCollection.h" #include "AthenaPoolUtilities/AthenaAttributeList.h" +#include <string> +#include <set> +#include <exception> #include <fstream> #include <iostream> @@ -35,16 +38,16 @@ #define TRACKER_ALIGN "/Tracker/Align" TrackerAlignDBTool::TrackerAlignDBTool(const std::string& type, - const std::string& name, const IInterface* parent) + const std::string& name, const IInterface* parent) : AthAlgTool(type,name,parent), - p_toolsvc("ToolSvc",name), - m_sctid(nullptr), - m_sctman(nullptr), - m_par_scttwoside(false), - m_par_dbroot( TRACKER_ALIGN ), - m_par_dbkey( TRACKER_ALIGN ), - m_dynamicDB(false), - m_forceUserDBConfig(false) + p_toolsvc("ToolSvc",name), + m_sctid(nullptr), + m_sctman(nullptr), + m_par_scttwoside(false), + m_par_dbroot( TRACKER_ALIGN ), + m_par_dbkey( TRACKER_ALIGN ), + m_dynamicDB(false), + m_forceUserDBConfig(false) { declareInterface<ITrackerAlignDBTool>(this); declareProperty("IToolSvc", p_toolsvc); @@ -59,76 +62,76 @@ TrackerAlignDBTool::~TrackerAlignDBTool() StatusCode TrackerAlignDBTool::initialize() { - - ATH_MSG_DEBUG("initializing"); - - m_alignobjs.clear(); - m_alignchans.clear(); - int ndet {0}; - // get storegate access to conditions store - ATH_CHECK(detStore().retrieve()); + ATH_MSG_DEBUG("initializing"); - ATH_CHECK( p_toolsvc.retrieve() ); + m_alignobjs.clear(); + m_alignchans.clear(); + int ndet {0}; - // attempt to get ID helpers from detector store - // (relying on GeoModel to put them) + // get storegate access to conditions store + ATH_CHECK(detStore().retrieve()); - ATH_CHECK(detStore()->retrieve(m_sctman,"SCT")); + ATH_CHECK( p_toolsvc.retrieve() ); - if (m_sctman->m_alignfoldertype == TrackerDD::static_run1 && - !m_forceUserDBConfig) - { - m_par_dbroot = "/Tracker/Align"; - m_dynamicDB = false; - } - else if (m_sctman->m_alignfoldertype == TrackerDD::timedependent_run2 && - !m_forceUserDBConfig) - { - m_par_dbroot = "/Tracker/AlignL3"; - m_dynamicDB = true; - } - m_par_dbkey = m_par_dbroot; + // attempt to get ID helpers from detector store + // (relying on GeoModel to put them) + + ATH_CHECK(detStore()->retrieve(m_sctman,"SCT")); - ATH_CHECK(detStore()->retrieve(m_sctid)); + if (m_sctman->m_alignfoldertype == TrackerDD::static_run1 && + !m_forceUserDBConfig) + { + m_par_dbroot = "/Tracker/Align"; + m_dynamicDB = false; + } + else if (m_sctman->m_alignfoldertype == TrackerDD::timedependent_run2 && + !m_forceUserDBConfig) + { + m_par_dbroot = "/Tracker/AlignL3"; + m_dynamicDB = true; + } + m_par_dbkey = m_par_dbroot; - // setup list of alignable transforms from geometry - int chan[3]; - int TransfLevel_low = 0; // depending on alignfolder sheme; 0 for old, 2 for new - if (m_dynamicDB) TransfLevel_low = 2; + ATH_CHECK(detStore()->retrieve(m_sctid)); - for (int i=0;i<3;++i) chan[i]=100*i; + // setup list of alignable transforms from geometry + int chan[3]; + int TransfLevel_low = 0; // depending on alignfolder sheme; 0 for old, 2 for new + if (m_dynamicDB) TransfLevel_low = 2; - std::string man_name; - for (const TrackerDD::SiDetectorElement* element : *(m_sctman->getDetectorElementCollection())) + for (int i=0;i<3;++i) chan[i]=100*i; + + std::string man_name; + for (const TrackerDD::SiDetectorElement* element : *(m_sctman->getDetectorElementCollection())) + { + if (element!=0) { - if (element!=0) - { - const Identifier ident=element->identify(); - int station, layer, eta, phi, side; - if (idToDetSet(ident, station, layer, eta, phi, side)) - { - std::string level[3]; - for (int i=TransfLevel_low; i<3; ++i) - { - m_stations.insert(station); - level[i]=dirkey(station, layer, 1+i, phi); - // add this to list if not seen already - std::vector<std::string>::const_iterator ix = - find(m_alignobjs.begin(), m_alignobjs.end(), level[i]); - if (ix==m_alignobjs.end()) - { - m_alignobjs.push_back(level[i]); - m_alignchans.push_back(chan[i]++); - } - } - ++ndet; - } - else - { - ATH_MSG_ERROR("Error translating element identifier." ); - } - } + const Identifier ident=element->identify(); + int station, layer, eta, phi, side; + if (idToDetSet(ident, station, layer, eta, phi, side)) + { + std::string level[3]; + for (int i=TransfLevel_low; i<3; ++i) + { + m_stations.insert(station); + level[i]=dirkey(station, layer, 1+i, phi); + // add this to list if not seen already + std::vector<std::string>::const_iterator ix = + find(m_alignobjs.begin(), m_alignobjs.end(), level[i]); + if (ix==m_alignobjs.end()) + { + m_alignobjs.push_back(level[i]); + m_alignchans.push_back(chan[i]++); + } + } + ++ndet; + } + else + { + ATH_MSG_ERROR("Error translating element identifier." ); + } + } } ATH_CHECK(m_outputTool.retrieve()); @@ -136,12 +139,12 @@ StatusCode TrackerAlignDBTool::initialize() { ATH_MSG_DEBUG( "Database root folder " << m_par_dbroot ); ATH_MSG_DEBUG( "Geometry initialisation sees " << ndet << - " SCT modules giving " << m_alignobjs.size() << " alignment keys" ); + " SCT modules giving " << m_alignobjs.size() << " alignment keys" ); ATH_MSG_DEBUG("Keys/channels are:"); - + for (unsigned int i=0; i < m_alignobjs.size(); ++i) ATH_MSG_DEBUG( " " << m_alignobjs[i] << " [" << m_alignchans[i] << "]" ); - + } return StatusCode::SUCCESS; @@ -155,7 +158,7 @@ StatusCode TrackerAlignDBTool::finalize() StatusCode TrackerAlignDBTool::createDB() const { - + ATH_MSG_DEBUG("createDB method called"); AlignableTransform* pat = nullptr; @@ -167,8 +170,8 @@ StatusCode TrackerAlignDBTool::createDB() const if (detStore()->contains<AlignableTransformContainer>(m_par_dbroot)) { - ATH_MSG_WARNING("createDB: AlignableTransformContainer already exists" ); - return StatusCode::FAILURE; + ATH_MSG_WARNING("createDB: AlignableTransformContainer already exists" ); + return StatusCode::FAILURE; } // put them in a collection /Indet/Align @@ -187,7 +190,7 @@ StatusCode TrackerAlignDBTool::createDB() const } // record collection in SG - + ATH_CHECK( detStore()->record(patc, m_par_dbroot) ); ATH_MSG_DEBUG( "Collection has size " << patc->size() ); @@ -195,78 +198,133 @@ StatusCode TrackerAlignDBTool::createDB() const std::vector<std::string> level2; for (const TrackerDD::SiDetectorElement* element : *(m_sctman->getDetectorElementCollection()) ) { - if (element != 0) + if (element != 0) + { + const Identifier ident = element->identify(); + std::string key = dirkey(ident,3); + // do not produce AlignableTrasnforms for SCT side 1 if option set + if (!(m_sctid->side(ident)==1) || m_par_scttwoside) { - const Identifier ident = element->identify(); - std::string key = dirkey(ident,3); - // do not produce AlignableTrasnforms for SCT side 1 if option set - if (!(m_sctid->side(ident)==1) || m_par_scttwoside) - { - if ((pat=getTransPtr(key))) - { - pat->add(ident,Amg::EigenTransformToCLHEP( Amg::Transform3D::Identity() ) ); - } - else - { - ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key ); - } - // add level 2 transform if needed - do this the first time a module - // for this level 3 key is seen - std::vector<std::string>::const_iterator ix= - find(level2.begin(),level2.end(),key); - if (ix==level2.end()) - { - level2.push_back(key); - // construct identifier of level 2 transform - Identifier ident2; - ident2=m_sctid->wafer_id(m_sctid->station(ident), - m_sctid->layer(ident), - 0, 0, 0); - std::string key2 = dirkey(ident, 2); - if ((pat = getTransPtr(key2))) - { - pat->add(ident2, - Amg::EigenTransformToCLHEP( Amg::Transform3D::Identity() ) ); - } - else - { - ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key2 ); - } - } - } + if ((pat=getTransPtr(key))) + { + const auto iStation = m_sctid->station(ident); + const auto iLayer = m_sctid->layer(ident); + const auto iModuleEta = m_sctid->eta_module(ident); + const auto iModulePhi = m_sctid->phi_module(ident); + int iModule = iModulePhi; + if (iModuleEta < 0) iModule +=4; + + const auto buildKey = [](auto iStation, auto iLayer, auto iModule) { + std::stringstream ss; + ss << iStation << iLayer << iModule; + return ss.str(); + }; + + const auto key = buildKey(iStation, iLayer, iModule); + if (not (m_alignment.find(key) == m_alignment.end())) { + const std::vector<double> c = m_alignment.value().find(key)->second; + ATH_MSG_VERBOSE("Applying correction for " << key); + ATH_MSG_VERBOSE(c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " " << c[4] << " " << c[5]); + Amg::Translation3D newtranslation(c[0], c[1], c[2]); + Amg::Transform3D alignment = newtranslation * Amg::RotationMatrix3D::Identity(); + alignment *= Amg::AngleAxis3D(c[5], Amg::Vector3D(0.,0.,1.)); + alignment *= Amg::AngleAxis3D(c[4], Amg::Vector3D(0.,1.,0.)); + alignment *= Amg::AngleAxis3D(c[3], Amg::Vector3D(1.,0.,0.)); + + pat->add(ident, Amg::EigenTransformToCLHEP(alignment)); + } else { + ATH_MSG_VERBOSE("No correction given for " << key); + } + } + else + { + ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key ); + } + // add level 2 transform if needed - do this the first time a module + // for this level 3 key is seen + std::vector<std::string>::const_iterator ix= + find(level2.begin(),level2.end(),key); + if (ix==level2.end()) + { + level2.push_back(key); + // construct identifier of level 2 transform + Identifier ident2; + ident2=m_sctid->wafer_id(m_sctid->station(ident), + m_sctid->layer(ident), + 0, 0, 0); + std::string key2 = dirkey(ident, 2); + if ((pat = getTransPtr(key2))) + { + auto iStation = m_sctid->station(ident); + auto iLayer = m_sctid->layer(ident); + + const auto buildKey = [](auto iStation, auto iLayer) { + std::stringstream ss; + ss << iStation << iLayer; + return ss.str(); + }; + + const auto key = buildKey(iStation, iLayer); + if (not (m_alignment.find(key) == m_alignment.end())) { + const std::vector<double> c = m_alignment.value().find(key)->second; + ATH_MSG_VERBOSE("Applying correction for " << key); + ATH_MSG_VERBOSE(c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " " << c[4] << " " << c[5]); + Amg::Translation3D newtranslation(c[0], c[1], c[2]); + Amg::Transform3D alignment = newtranslation * Amg::RotationMatrix3D::Identity(); + alignment *= Amg::AngleAxis3D(c[5], Amg::Vector3D(0.,0.,1.)); + alignment *= Amg::AngleAxis3D(c[4], Amg::Vector3D(0.,1.,0.)); + alignment *= Amg::AngleAxis3D(c[3], Amg::Vector3D(1.,0.,0.)); + + pat->add(ident2, Amg::EigenTransformToCLHEP(alignment)); + } else { + ATH_MSG_VERBOSE("No correction given for " << key); + } + } + else + { + ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key2 ); + } + } } } + } - // create the global object with positions for the stations - Identifier ident1; - std::string key1 = dirkey(ident1, 1); - if ((pat = getTransPtr(key1))) - { - Amg::Transform3D globshift; - globshift.setIdentity(); - for (int station : m_stations) - { - ident1 = m_sctid->wafer_id(station, 0, 0, 0, 0); - pat->add(ident1, Amg::EigenTransformToCLHEP(globshift)); - } - } - else + // create the global object with positions for the stations + Identifier ident1; + std::string key1 = dirkey(ident1, 1); + if ((pat = getTransPtr(key1))) + { + // Amg::Translation3D translation(0.1,0.2,0.3); + //Amg::Transform3D globshift=translation*Amg::RotationMatrix3D::Identity(); + //std::cout<<"rotation"<<std::endl; + //std::cout<<globshift.rotation()(0,0)<<" , "<<globshift.rotation()(1,1)<<" , "<<globshift.rotation()(2,2)<<std::endl; + //std::cout<<"translation"<<std::endl; + //std::cout<<globshift.translation()(0,0)<<" , "<<globshift.translation()(1,1)<<" , "<<globshift.translation()(2,2)<<std::endl; + Amg::Transform3D globshift; + globshift.setIdentity(); + for (int station : m_stations) { - ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key1 ); - } + ident1 = m_sctid->wafer_id(station, 0, 0, 0, 0); + pat->add(ident1, Amg::EigenTransformToCLHEP(globshift)); + } + } + else + { + ATH_MSG_ERROR( "Cannot retrieve AlignableTransform for key " << key1 ); + } - // sort the created objects (in case, usually come out sorted from GeoModel) - ATH_CHECK(sortTrans()); - // list out size of all created objects - ATH_MSG_DEBUG( "Dumping size of created AlignableTransform objects"); - for (unsigned int i = 0; i < m_alignobjs.size(); ++i) - if ((pat = getTransPtr(m_alignobjs[i]))) pat->print(); + // sort the created objects (in case, usually come out sorted from GeoModel) + ATH_CHECK(sortTrans()); + // list out size of all created objects + ATH_MSG_DEBUG( "Dumping size of created AlignableTransform objects"); + for (unsigned int i = 0; i < m_alignobjs.size(); ++i) + if ((pat = getTransPtr(m_alignobjs[i]))) pat->print(); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } bool TrackerAlignDBTool::idToDetSet(const Identifier ident, int& station, - int& layer, int& eta, int& phi, int& side) const + int& layer, int& eta, int& phi, int& side) const { // transform Identifier to list of integers specifiying station,layer // eta, phi, side @@ -280,7 +338,7 @@ bool TrackerAlignDBTool::idToDetSet(const Identifier ident, int& station, } std::string TrackerAlignDBTool::dirkey(const Identifier& ident, - const int level) const + const int level) const { // given SCT identifier, and level (1, 2 or 3) return // directory key name for associated alignment data @@ -290,9 +348,9 @@ std::string TrackerAlignDBTool::dirkey(const Identifier& ident, } std::string TrackerAlignDBTool::dirkey(const int station, - const int layer, - const int level, - const int ) const + const int layer, + const int level, + const int ) const { // channel info and level (1,2 or 3) return // directory key name for associated alignment data @@ -307,17 +365,17 @@ std::string TrackerAlignDBTool::dirkey(const int station, { result << m_par_dbkey << "/" ; } - + if (level==1) { result << "Stations"; } else { if (level==2) result << "Planes"; if (level==3) { - if (station == 3 ) result << "Downstream"; - if (station == 2 ) result << "Central"; - if (station == 1 ) result << "Upstream"; - if (station == 0 ) result << "Interface"; - result << 1+layer; + if (station == 3 ) result << "Downstream"; + if (station == 2 ) result << "Central"; + if (station == 1 ) result << "Upstream"; + if (station == 0 ) result << "Interface"; + result << 1+layer; } } return result.str(); @@ -327,7 +385,7 @@ std::string TrackerAlignDBTool::dirkey(const int station, // const int layer,const int ring, const int sector, // const float rphidisp, const float rdisp, const float zdisp, // const int syst, const int level, const int skip) const { - + // ATH_MSG_DEBUG( "dispGroup called: level " << level << " syst " << syst); // int nmod=0; // // random number service @@ -438,7 +496,7 @@ std::string TrackerAlignDBTool::dirkey(const int station, // } // // update, adding to any existing shift // if (update) { - + // Amg::Transform3D shift = Amg::Translation3D(xd,yd,zd) * Amg::RotationMatrix3D::Identity(); // pat->tweak(ident2,Amg::EigenTransformToCLHEP(shift)); // ATH_MSG_VERBOSE( "Updated module " << mdet << "," << mbec @@ -495,13 +553,13 @@ std::string TrackerAlignDBTool::dirkey(const int station, // bool InDetAlignDBTool::setTrans(const Identifier& ident, const int level, // const Amg::Vector3D& translate, double alpha, double beta, double gamma) const // { - + // Amg::Translation3D newtranslation(translate); // Amg::Transform3D newtrans = newtranslation * Amg::RotationMatrix3D::Identity(); // newtrans *= Amg::AngleAxis3D(gamma, Amg::Vector3D(0.,0.,1.)); // newtrans *= Amg::AngleAxis3D(beta, Amg::Vector3D(0.,1.,0.)); // newtrans *= Amg::AngleAxis3D(alpha, Amg::Vector3D(1.,0.,0.)); - + // return setTrans(ident, level, newtrans); // } @@ -543,13 +601,13 @@ std::string TrackerAlignDBTool::dirkey(const int station, // bool InDetAlignDBTool::tweakTrans(const Identifier& ident, const int level, // const Amg::Vector3D& translate, double alpha, double beta, double gamma) const // { - + // Amg::Translation3D newtranslation(translate); // Amg::Transform3D newtrans = newtranslation * Amg::RotationMatrix3D::Identity(); // newtrans *= Amg::AngleAxis3D(gamma, Amg::Vector3D(0.,0.,1.)); // newtrans *= Amg::AngleAxis3D(beta, Amg::Vector3D(0.,1.,0.)); // newtrans *= Amg::AngleAxis3D(alpha, Amg::Vector3D(1.,0.,0.)); - + // return tweakTrans(ident, level, newtrans); // } @@ -586,7 +644,7 @@ std::string TrackerAlignDBTool::dirkey(const int station, // /** get cumulative L1, L2, L3 trafo for (L3-) module */ // Amg::Transform3D InDetAlignDBTool::getTransL123( const Identifier& ident ) const { - + // Amg::Transform3D result ; // InDetDD::SiDetectorElement* element = m_pixman->getDetectorElement( ident ) ; // if( !element ) { @@ -623,14 +681,14 @@ std::string TrackerAlignDBTool::dirkey(const int station, // } StatusCode TrackerAlignDBTool::outputObjs() const { - + ATH_MSG_DEBUG( "Output AlignableTranform objects to stream" << m_outputTool ); // get the AthenaOutputStream tool -// IAthenaOutputStreamTool* optool {nullptr}; + // IAthenaOutputStreamTool* optool {nullptr}; + + // ATH_CHECK(p_toolsvc->retrieveTool("AthenaOutputStreamTool", m_par_condstream, optool)); -// ATH_CHECK(p_toolsvc->retrieveTool("AthenaOutputStreamTool", m_par_condstream, optool)); - -// ATH_CHECK(optool->connectOutput("myAlignFile.pool.root")); + // ATH_CHECK(optool->connectOutput("myAlignFile.pool.root")); ATH_CHECK(m_outputTool->connectOutput()); // construct list of objects to be written out, either @@ -638,13 +696,13 @@ StatusCode TrackerAlignDBTool::outputObjs() const { int npairs=1; IAthenaOutputStreamTool::TypeKeyPairs typekeys(npairs); typekeys[0]= - IAthenaOutputStreamTool::TypeKeyPair("AlignableTransformContainer", - m_par_dbroot); + IAthenaOutputStreamTool::TypeKeyPair("AlignableTransformContainer", + m_par_dbroot); if (!(detStore()->contains<AlignableTransformContainer>(m_par_dbroot))) ATH_MSG_ERROR( - "Expected " << m_par_dbroot << " object not found" ); + "Expected " << m_par_dbroot << " object not found" ); // write objects to stream -// ATH_CHECK(optool->streamObjects(typekeys, "myAlignFile.pool.root")); + // ATH_CHECK(optool->streamObjects(typekeys, "myAlignFile.pool.root")); ATH_CHECK(m_outputTool->streamObjects(typekeys)); // commit output @@ -654,10 +712,10 @@ StatusCode TrackerAlignDBTool::outputObjs() const { } StatusCode TrackerAlignDBTool::fillDB(const std::string tag, - const unsigned int run1, const unsigned int event1, - const unsigned int run2, const unsigned int event2) const + const unsigned int run1, const unsigned int event1, + const unsigned int run2, const unsigned int event2) const { - + ATH_MSG_DEBUG( "fillDB: Data tag " << tag ); ATH_MSG_DEBUG( "Run/evt1 [" << run1 << "," << event1 << "]" ); ATH_MSG_DEBUG( "Run/evt2 [" << run2 << "," << event2 << "]" ); @@ -669,7 +727,7 @@ StatusCode TrackerAlignDBTool::fillDB(const std::string tag, // loop over all AlignableTransform objects created earlier and save them ATH_CHECK(regsvc->registerIOV( - "AlignableTransformContainer",m_par_dbroot, tag, run1, run2, event1, event2)); + "AlignableTransformContainer",m_par_dbroot, tag, run1, run2, event1, event2)); ATH_MSG_DEBUG( "Stored AlignableTransform object " << m_par_dbroot ); ATH_MSG_DEBUG( " Wrote one AlignableTransformContainer objects to conditions database" ); @@ -678,12 +736,12 @@ StatusCode TrackerAlignDBTool::fillDB(const std::string tag, StatusCode TrackerAlignDBTool::printDB(const int level) const { - + ATH_MSG_DEBUG("Printout TrackerAlign database contents, detail level" << level ); for (std::vector<std::string>::const_iterator iobj = m_alignobjs.begin(); - iobj != m_alignobjs.end(); - ++iobj) + iobj != m_alignobjs.end(); + ++iobj) { const AlignableTransform* pat; if ((pat = cgetTransPtr(*iobj))) @@ -691,31 +749,31 @@ StatusCode TrackerAlignDBTool::printDB(const int level) const ATH_MSG_DEBUG( "AlignableTransform object " << *iobj ); int nobj = 0; for (AlignableTransform::AlignTransMem_citr cit = pat->begin(); - cit!=pat->end(); - ++cit) + cit!=pat->end(); + ++cit) { - const Identifier& ident = cit->identify(); - const Amg::Transform3D& trans = Amg::CLHEPTransformToEigen( cit->transform() ); - Amg::Vector3D shift = trans.translation(); - //Amg::RotationMatrix3D rot=trans.rotation(); - int station, layer, eta, phi, side; - if (idToDetSet(ident, station, layer, eta, phi, side)) - { - if (level > 1) - { - double alpha, beta, gamma; - extractAlphaBetaGamma(trans, alpha, beta, gamma); - ATH_MSG_DEBUG( "Tracker [" << station << "," << layer << - "," << eta << "," << phi << "," << side << "] Trans:(" << - shift.x() << "," << shift.y() << "," << shift.z() << ") Rot:{" - << alpha << "," << beta << "," << gamma << "}"); - } - ++nobj; - } - else - { - ATH_MSG_ERROR("Unknown identifier in AlignableTransform" ); - } + const Identifier& ident = cit->identify(); + const Amg::Transform3D& trans = Amg::CLHEPTransformToEigen( cit->transform() ); + Amg::Vector3D shift = trans.translation(); + //Amg::RotationMatrix3D rot=trans.rotation(); + int station, layer, eta, phi, side; + if (idToDetSet(ident, station, layer, eta, phi, side)) + { + if (level > 1) + { + double alpha, beta, gamma; + extractAlphaBetaGamma(trans, alpha, beta, gamma); + ATH_MSG_DEBUG( "Tracker [" << station << "," << layer << + "," << eta << "," << phi << "," << side << "] Trans:(" << + shift.x() << "," << shift.y() << "," << shift.z() << ") Rot:{" + << alpha << "," << beta << "," << gamma << "}"); + } + ++nobj; + } + else + { + ATH_MSG_ERROR("Unknown identifier in AlignableTransform" ); + } } ATH_MSG_DEBUG( "Object contains " << nobj << " transforms" ); } @@ -731,28 +789,28 @@ StatusCode TrackerAlignDBTool::printDB(const int level) const AlignableTransform* TrackerAlignDBTool::getTransPtr(const std::string key) const { - // look in collection to retrieve pointer to AlignableTransform object of - // given key and return it, return 0 if not collection or key value not found - AlignableTransformContainer* patc; - AlignableTransform* pat {nullptr}; + // look in collection to retrieve pointer to AlignableTransform object of + // given key and return it, return 0 if not collection or key value not found + AlignableTransformContainer* patc; + AlignableTransform* pat {nullptr}; - if(detStore()->retrieve(patc,m_par_dbroot ).isFailure()) - { + if(detStore()->retrieve(patc,m_par_dbroot ).isFailure()) + { ATH_MSG_ERROR("Unable to retrieve alignment container from DetStore."); return nullptr; - } + } - for (DataVector<AlignableTransform>::iterator dva=patc->begin(); - dva!=patc->end();++dva) - { - if ((*dva)->tag()==key) + for (DataVector<AlignableTransform>::iterator dva=patc->begin(); + dva!=patc->end();++dva) { - pat=*dva; - break; + if ((*dva)->tag()==key) + { + pat=*dva; + break; + } } + return pat; } - return pat; -} const AlignableTransform* TrackerAlignDBTool::cgetTransPtr(const std::string key) const { @@ -764,18 +822,18 @@ const AlignableTransform* TrackerAlignDBTool::cgetTransPtr(const std::string key if(detStore()->retrieve(patc, m_par_dbroot ).isFailure()) { - ATH_MSG_ERROR("Unable to retrieve alignment container from DetStore."); - return nullptr; + ATH_MSG_ERROR("Unable to retrieve alignment container from DetStore."); + return nullptr; } for (DataVector<AlignableTransform>::const_iterator dva=patc->begin(); - dva!=patc->end(); - ++dva) + dva!=patc->end(); + ++dva) { if ((*dva)->tag() == key) { - pat=*dva; - break; + pat=*dva; + break; } } return pat; @@ -784,7 +842,7 @@ const AlignableTransform* TrackerAlignDBTool::cgetTransPtr(const std::string key StatusCode TrackerAlignDBTool::sortTrans() const { // loop through all the AlignableTransform objects and sort them - + ATH_MSG_DEBUG( "Sorting all AlignableTransforms in TDS" ); AlignableTransform* pat; // use cget and a const cast to allow containers that have been read in @@ -796,7 +854,7 @@ StatusCode TrackerAlignDBTool::sortTrans() const } void TrackerAlignDBTool::extractAlphaBetaGamma(const Amg::Transform3D & trans, - double& alpha, double& beta, double &gamma) const + double& alpha, double& beta, double &gamma) const { double siny = trans(0,2); beta = asin(siny); @@ -832,14 +890,14 @@ void TrackerAlignDBTool::extractAlphaBetaGamma(const Amg::Transform3D & trans, // idToDetSet(ident,det,bec,layer,ring,sector,side); // const unsigned int DBident=det*10000+2*bec*1000+layer*100+ring*10+sector; // // so far not a very fancy DB identifier, but seems elaborate enough for this simple structure - + // if (StatusCode::SUCCESS==detStore()->retrieve(atrlistcol1,key)) { // // loop over objects in collection // //atrlistcol1->dump(); // atrlistcol2 = const_cast<CondAttrListCollection*>(atrlistcol1); // if (atrlistcol2!=0){ // for (CondAttrListCollection::const_iterator citr=atrlistcol2->begin(); citr!=atrlistcol2->end();++citr) { - + // const coral::AttributeList& atrlist=citr->second; // coral::AttributeList& atrlist2 = const_cast<coral::AttributeList&>(atrlist); @@ -865,7 +923,7 @@ void TrackerAlignDBTool::extractAlphaBetaGamma(const Amg::Transform3D & trans, // oldtrans *= Amg::AngleAxis3D(atrlist2["Rz"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,0.,1.)); // oldtrans *= Amg::AngleAxis3D(atrlist2["Ry"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,1.,0.)); // oldtrans *= Amg::AngleAxis3D(atrlist2["Rx"].data<float>()*CLHEP::mrad, Amg::Vector3D(1.,0.,0.)); - + // // get the new transform // Amg::Transform3D newtrans = trans*oldtrans; @@ -880,7 +938,7 @@ void TrackerAlignDBTool::extractAlphaBetaGamma(const Amg::Transform3D & trans, // atrlist2["Rx"].data<float>() = alpha/CLHEP::mrad ; // atrlist2["Ry"].data<float>() = beta/CLHEP::mrad ; // atrlist2["Rz"].data<float>() = gamma/CLHEP::mrad ; - + // result = true; // msg(MSG::DEBUG) << "Tweak New global DB -- channel: " << citr->first // << " ,det: " << atrlist2["det"].data<int>() @@ -894,7 +952,7 @@ void TrackerAlignDBTool::extractAlphaBetaGamma(const Amg::Transform3D & trans, // << " ,Rx: " << atrlist2["Rx"].data<float>() // << " ,Ry: " << atrlist2["Ry"].data<float>() // << " ,Rz: " << atrlist2["Rz"].data<float>() << endmsg; - + // } // } // } diff --git a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h index 2c82c20a10baffab0b01d6c00af036b6adabaa11..6ee1a190427d31b683aa946fe54726e8b04079ba 100644 --- a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h +++ b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.h @@ -186,6 +186,8 @@ class TrackerAlignDBTool: virtual public ITrackerAlignDBTool, public AthAlgTool bool m_dynamicDB; bool m_forceUserDBConfig; std::set<int> m_stations; + Gaudi::Property<std::map<std::string, std::vector<double>>> m_alignment{ this, "AlignmentConstants", {}, "Alignment constants."}; + mutable ToolHandle<IAthenaOutputStreamTool> m_outputTool { this, "OutputTool", "AthenaOutputStreamTool/CondStream1"} ; diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/CMakeLists.txt b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/CMakeLists.txt index c2a3d1b2056e307e861b27ea0bef0411f754db7b..af29f45685a723d97b25c290c39ae2d52fe69e91 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/CMakeLists.txt +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/CMakeLists.txt @@ -10,6 +10,7 @@ find_package( Boost COMPONENTS filesystem thread system ) # Component(s) in the package: atlas_add_component( FaserSCT_ConditionsAlgorithms + src/*.h src/*.cxx src/components/*.cxx INCLUDE_DIRS ${Boost_INCLUDE_DIRS} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d1e117ef59175dfa68ebba6bab1123a5516c9c6e --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.cxx @@ -0,0 +1,178 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#include "FaserSCT_ConfigurationCondAlg.h" + +#include "Identifier/Identifier.h" +#include "Identifier/IdentifierHash.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" + +#include <memory> + + +FaserSCT_ConfigurationCondAlg::FaserSCT_ConfigurationCondAlg(const std::string& name, ISvcLocator* pSvcLocator) : + ::AthReentrantAlgorithm(name, pSvcLocator) {} + +StatusCode FaserSCT_ConfigurationCondAlg::initialize() { + ATH_MSG_DEBUG("initialize " << name()); + + // CondSvc + ATH_CHECK(m_condSvc.retrieve()); + + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + // Read Cond Handle + ATH_CHECK(m_readKey.initialize()); + + // Write Cond Handle + ATH_CHECK(m_writeKey.initialize()); + if (m_condSvc->regHandle(this, m_writeKey).isFailure()) { + ATH_MSG_FATAL("unable to register WriteCondHandle " << m_writeKey.fullKey() << " with CondSvc"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode FaserSCT_ConfigurationCondAlg::execute(const EventContext& ctx) const { + ATH_MSG_DEBUG("execute " << name()); + + // Write Cond Handle + SG::WriteCondHandle<FaserSCT_ConfigurationCondData> writeHandle{m_writeKey, ctx}; + // Do we have a valid Write Cond Handle for current time? + if (writeHandle.isValid()) { + ATH_MSG_DEBUG("CondHandle " << writeHandle.fullKey() << " is already valid. " + << "In theory this should not be called, but may happen" + << " if multiple concurrent events are being processed out of order."); + return StatusCode::SUCCESS; + } + + // Construct the output Cond Object and fill it in + std::unique_ptr<FaserSCT_ConfigurationCondData> writeCdo{std::make_unique<FaserSCT_ConfigurationCondData>()}; + // clear structures before filling + writeCdo->clear(); + + if (writeCdo == nullptr) { + ATH_MSG_FATAL("Pointer of derived conditions object is null"); + return StatusCode::FAILURE; + } + + // Get read 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 StatusCode::FAILURE; + } + ATH_MSG_INFO("Size of " << m_readKey.key() << " is " << readCdo->size()); + + // Get the validity range + EventIDRange rangeW; + if (not readHandle.range(rangeW)) { + ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key()); + return StatusCode::FAILURE; + } + ATH_MSG_DEBUG("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdo->size()= " << readCdo->size()); + ATH_MSG_DEBUG("Range of input is " << rangeW); + + writeHandle.addDependency(readHandle); + + std::string sensorParam{"sensor"}; + std::string nstripParam{"nstrips"}; + std::string noisyParam{"noisyList"}; + //std::string stripParam{"strip"}; + //std::string occupancyParam{"occupancy"}; + CondAttrListCollection::const_iterator itr{readCdo->begin()}; + CondAttrListCollection::const_iterator end{readCdo->end()}; + // CondAttrListCollection doesn't support C++11 type loops, no generic 'begin' + for (; itr != end; ++itr) { + // A CondAttrListCollection is a map of ChanNum and AttributeList + CondAttrListCollection::ChanNum channelNumber{itr->first}; + const CondAttrListCollection::AttributeList &payload{itr->second}; + + if (not (payload.exists(sensorParam) and not payload[sensorParam].isNull() and + payload.exists(nstripParam) and not payload[nstripParam].isNull() and + payload.exists(noisyParam) )) { + ATH_MSG_FATAL(sensorParam << " and/or " << noisyParam << " does not exist."); + continue; + } + + auto sensorVal {payload[sensorParam].data<int>()}; + auto nstripVal {payload[nstripParam].data<int>()}; + auto channel {payload[sensorParam].data<int>()}; + + if (channel != int(channelNumber)) { + ATH_MSG_FATAL("Sensor " << payload[sensorParam] << " != channel " << channelNumber << "!"); + return StatusCode::FAILURE; + } + + if (payload[noisyParam].isNull()) continue; // No noisy strips + + std::string noisyListVal {payload[noisyParam].data<std::string>()}; + + // Parse string of noisy strips + std::stringstream ss(noisyListVal); + std::string item; + int nfound = 0; + ATH_MSG_VERBOSE("Parsing noisy strips string: " << noisyListVal); + + while (ss >> item) { + + if(item.size() == 0) continue; + + //ATH_MSG_VERBOSE("["<<item<<"]"); + + // Split by colon + auto i = item.find(':'); + int stripVal(std::stoi(item.substr(0, i))); + float occupancy(std::stof(item.substr((i+1), (i+7)))); + + ATH_MSG_VERBOSE("Found sensor " << sensorVal << " strip " << stripVal << " occupancy " << occupancy); + nfound++; + + Identifier waferId = m_idHelper->wafer_id(sensorVal); + Identifier stripId = m_idHelper->strip_id(waferId, stripVal); + if (stripId.is_valid() and occupancy > m_occupancyThreshold) { + writeCdo->setBadStripId(stripId, sensorVal, stripVal); + ATH_MSG_INFO("Bad Strip: " << m_idHelper->station(stripId) << "/" << m_idHelper->layer(stripId) << "/" + << m_idHelper->phi_module(stripId) << "/" << m_idHelper->phi_module(stripId) << "/" + << m_idHelper->side(stripId) << "/" << m_idHelper->strip(stripId) << " (" << sensorVal<< ") : " + << occupancy); + } else { + ATH_MSG_VERBOSE(m_idHelper->station(stripId) << "/" << m_idHelper->layer(stripId) << "/" + << m_idHelper->phi_module(stripId) << "/" << m_idHelper->phi_module(stripId) << "/" + << m_idHelper->side(stripId) << "/" << m_idHelper->strip(stripId) << " (" << sensorVal<< ") : " + << occupancy); + } + } // End of parsing line + + // Check that we found the strips we should have + if (nfound != nstripVal) { + ATH_MSG_FATAL("Sensor " << sensorVal << " found " << nfound << " but expected " << nstripVal); + return StatusCode::FAILURE; + } + + } // End of loop over sensors + + // Summarize what we found + ATH_MSG_INFO("From " << readCdo->size() << " sensors in DB"); + ATH_MSG_INFO("found " << writeCdo->getBadStripIds()->size() << " bad strips"); + ATH_MSG_INFO("found " << writeCdo->getBadModuleIds()->size() << " bad modules"); + + if (writeHandle.record(std::move(writeCdo)).isFailure()) { + ATH_MSG_FATAL("Could not record SCT_ConfigurationCondData " << writeHandle.key() + << " with EventRange " << writeHandle.getRange() + << " into Conditions Store"); + return StatusCode::FAILURE; + } + ATH_MSG_INFO("recorded new CDO " << writeHandle.key() << " with range " << writeHandle.getRange() << " into Conditions Store"); + + return StatusCode::SUCCESS; +} + +StatusCode FaserSCT_ConfigurationCondAlg::finalize() { + ATH_MSG_DEBUG("finalize " << name()); + return StatusCode::SUCCESS; +} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.h b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..44f81c4282b0a50d1859f31396a8d4dd8a8f335e --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/FaserSCT_ConfigurationCondAlg.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef FASERSCT_CONFIGURATIONCONDALG_H +#define FASERSCT_CONFIGURATIONCONDALG_H + +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaPoolUtilities/CondAttrListCollection.h" + +#include "StoreGate/ReadCondHandleKey.h" +#include "StoreGate/WriteCondHandleKey.h" + +#include "GaudiKernel/ICondSvc.h" +#include "GaudiKernel/ServiceHandle.h" + +// TODO use instead SCT_ConfigurationCondData? +// #include "SCT_ConditionsData/SCT_ConfigurationCondData.h" +#include "FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h" + + +class FaserSCT_ID; + +class FaserSCT_ConfigurationCondAlg : public AthReentrantAlgorithm { + public: + FaserSCT_ConfigurationCondAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~FaserSCT_ConfigurationCondAlg() = default; + virtual StatusCode initialize() override; + virtual StatusCode execute(const EventContext& ctx) const override; + virtual StatusCode finalize() override; + virtual bool isClonable() const override { return true; }; + + private: + SG::ReadCondHandleKey<CondAttrListCollection> m_readKey {this, "ReadKey", "/SCT/DAQ/NoisyStrips", "Key of input noisy strips folder"}; + SG::WriteCondHandleKey<FaserSCT_ConfigurationCondData> m_writeKey{this, "WriteKey", "FaserSCT_ConfigurationCondData", "Key of output (derived) conditions data"}; + ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"}; + const FaserSCT_ID* m_idHelper{nullptr}; + Gaudi::Property<double> m_occupancyThreshold {this, "OccupancyThreshold", 0.01, "Mask strips with an occupancy larger than the OccupancyCut"}; +}; + + + +#endif //FASERSCT_CONFIGURATIONCONDALG_H diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/components/FaserSCT_ConditionsAlgorithms_entries.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/components/FaserSCT_ConditionsAlgorithms_entries.cxx index f8b127e85d0a477d87019556c48cc0873a19eee8..465ffd956838ce71cb17495156804176be756ebc 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/components/FaserSCT_ConditionsAlgorithms_entries.cxx +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsAlgorithms/src/components/FaserSCT_ConditionsAlgorithms_entries.cxx @@ -34,6 +34,7 @@ // #include "../SCT_StripVetoTestAlg.h" // #include "../SCT_TdaqEnabledCondAlg.h" // #include "../SCT_TdaqEnabledTestAlg.h" +#include "../FaserSCT_ConfigurationCondAlg.h" DECLARE_COMPONENT( FaserSCT_AlignCondAlg ) // DECLARE_COMPONENT( SCT_ByteStreamErrorsTestAlg ) @@ -71,3 +72,4 @@ DECLARE_COMPONENT( FaserSCT_SiliconTempCondAlg ) // DECLARE_COMPONENT( SCT_StripVetoTestAlg ) // DECLARE_COMPONENT( SCT_TdaqEnabledCondAlg ) // DECLARE_COMPONENT( SCT_TdaqEnabledTestAlg ) +DECLARE_COMPONENT( FaserSCT_ConfigurationCondAlg ) diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsData/CMakeLists.txt b/Tracker/TrackerConditions/FaserSCT_ConditionsData/CMakeLists.txt index f13ae3272499c4b66d5dab008bff2a1b92081f88..16fcf75c2d6c9caff8ea4c3a18e143f6d7010436 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsData/CMakeLists.txt +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsData/CMakeLists.txt @@ -8,6 +8,7 @@ atlas_subdir( FaserSCT_ConditionsData ) # Component(s) in the package: atlas_add_library( FaserSCT_ConditionsData + FaserSCT_ConditionsData/*.h src/*.cxx PUBLIC_HEADERS FaserSCT_ConditionsData LINK_LIBRARIES AthenaPoolUtilities Identifier ) diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsData/FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h b/Tracker/TrackerConditions/FaserSCT_ConditionsData/FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h new file mode 100644 index 0000000000000000000000000000000000000000..0ff7a294584d2cf7d318cfce8ab39a044dd7da5c --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsData/FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h @@ -0,0 +1,98 @@ +#ifndef FASERSCT_CONFIGURATIONCONDDATA_H +#define FASERSCT_CONFIGURATIONCONDDATA_H + +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#include <array> +#include <bitset> +#include <map> +#include <set> + +// Include Athena stuff +#include "Identifier/Identifier.h" +#include "Identifier/IdentifierHash.h" + +/** + * @class FaserSCT_ConfigurationCondData + * @brief Class for data object used in SCT_ConfigurationCondAlg and SCT_ConfigurationConditionsTool. + **/ +class FaserSCT_ConfigurationCondData { +public: + + /// Constructor + FaserSCT_ConfigurationCondData(); + + /// Destructor + virtual ~FaserSCT_ConfigurationCondData() = default; + + /// Set a bad strip identifier + void setBadStripId(const Identifier& badStripId, const IdentifierHash& hash, const int strip); + /// Get all bad strip identifiers + const std::set<Identifier>* getBadStripIds() const; + /// Clear all bad strip identifiers + void clearBadStripIds(); + /// Check if a strip identifier is bad one + bool isBadStrip(const IdentifierHash& hash, const int strip) const; + + /// Set a bad wafer identifier + void setBadWaferId(const Identifier& badWaferId); + /// Get all bad wafer identifiers + const std::set<Identifier>* getBadWaferIds() const; + /// Clear all bad wafer identifiers + void clearBadWaferIds(); + /// Check if a wafer identifier is bad one + bool isBadWaferId(const Identifier& waferId) const; + + /// Set a bad module identifier + void setBadModuleId(const Identifier& badModuleId); + /// Get all bad module identifiers + const std::set<Identifier>* getBadModuleIds() const; + /// Clear all bad module identifiers + void clearBadModuleIds(); + /// Check if a module identifier is bad one + bool isBadModuleId(const Identifier& moduleId) const; + + /// Set bad links for a module + void setBadLinks(const IdentifierHash& hash, const bool isBadLink0, const bool isBadLink1); + /// Get all bad links + const std::map<IdentifierHash, std::pair<bool, bool>>* getBadLinks() const; + /// Clear all bad links + void clearBadLinks(); + /// Check if a module has bad links + std::pair<bool, bool> areBadLinks(const IdentifierHash& hash) const; + + /// Set bad chips for a module + void setBadChips(const Identifier& moduleId, const unsigned int chipStatus); + /// Get bad chips for a module + unsigned int getBadChips(const Identifier& moduleId) const; + /// Get all bad chips + const std::map<Identifier, unsigned int>* getBadChips() const; + /// Clear all bad chips + void clearBadChips(); + + /// Clear all bad information + void clear(); + +private: + enum {N_MODULES=4088, N_STRIPS=768, N_SIDES=2}; + + std::set<Identifier> m_badStripIds; + std::array<std::bitset<N_STRIPS>, N_MODULES*N_SIDES> m_badStripArray; + std::set<Identifier> m_badWaferIds; + std::set<Identifier> m_badModuleIds; + std::map<IdentifierHash, std::pair<bool, bool>> m_badLinks; + std::array<std::pair<bool, bool>, N_MODULES> m_badLinksArray; + std::map<Identifier, unsigned int> m_badChips; +}; + +// Class definition for StoreGate +#include "AthenaKernel/CLASS_DEF.h" +CLASS_DEF( FaserSCT_ConfigurationCondData , 81691222 , 1 ) + +// Condition container definition for CondInputLoader +#include "AthenaKernel/CondCont.h" +CONDCONT_DEF( FaserSCT_ConfigurationCondData, 230890898 ); + +#endif // FASERSCT_CONFIGURATIONCONDDATA_H diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/BField_DataConditions.py b/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/BField_DataConditions.py new file mode 100755 index 0000000000000000000000000000000000000000..94846ee80dedb41dbc2354a6662873203aad9cb6 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsData/data/BField_DataConditions.py @@ -0,0 +1,85 @@ +#!/bin/env python + +# Use this to add a field map to the CONDBR3 database for real data +# Copied the result from the OFLP200 DB +# Note that the testbeam turns off the field by setting scale = 0 +description = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>' + +descriptionDCS = '<timeStamp>time</timeStamp><addrHeader><address_header service_type="71" clid="1238547719" /></addrHeader><typeName>CondAttrListCollection</typeName><cache>600</cache>' + +descriptionAlign = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header service_type="256" clid="1170039409" /></addrHeader><typeName>AlignableTransformContainer</typeName>' + +import sys +from PyCool import cool, coral +from CoolConvUtilities.AtlCoolLib import indirectOpen + +dbSvc = cool.DatabaseSvcFactory.databaseService() +connectString = 'sqlite://;schema=ALLP200.db;dbname=CONDBR3' + +print('generating field database') +#dbSvc.dropDatabase( connectString ) +try: + # Open existing instead? + print('Try indirectOpen') + db = indirectOpen( connectString, readOnly=False ) +except Exception as e: + print(e) + print('Problem opening DB, create instead') + db = dbSvc.createDatabase( connectString ) + +glob = db.createFolderSet("/GLOBAL") +glob_bfield = db.createFolderSet("/GLOBAL/BField") + +glob_bfield.createTagRelation("GLOBAL-01", "GLOBAL-BField-01") +glob.createTagRelation("OFLCOND-FASER-01", "GLOBAL-01") + +glob_bfield.createTagRelation("GLOBAL-02", "GLOBAL-BField-02") +glob.createTagRelation("OFLCOND-FASER-02", "GLOBAL-02") + +glob_bfield.createTagRelation("GLOBAL-TB00", "GLOBAL-BField-TB00") +glob.createTagRelation("OFLCOND-FASER-TB00", "GLOBAL-TB00") + +mapSpec = cool.RecordSpecification() +mapSpec.extend( 'FieldType', cool.StorageType.String4k ) +mapSpec.extend( 'MapFileName', cool.StorageType.String4k ) + +mapRecord = cool.Record(mapSpec) +mapRecord['FieldType'] = "GlobalMap" +mapRecord['MapFileName'] = "file:MagneticFieldMaps/FaserFieldTable.root" + +mapFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, mapSpec) +mapFolder = db.createFolder('/GLOBAL/BField/Maps', mapFolderSpec, descriptionDCS, True ) + +mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1, "GLOBAL-BField-Maps-01", True ) +mapFolder.createTagRelation("GLOBAL-BField-01", "GLOBAL-BField-Maps-01") + +mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1, "GLOBAL-BField-Maps-02", True ) +mapFolder.createTagRelation("GLOBAL-BField-02", "GLOBAL-BField-Maps-02") + +mapFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, mapRecord, 1, "GLOBAL-BField-Maps-TB00", True ) +mapFolder.createTagRelation("GLOBAL-BField-TB00", "GLOBAL-BField-Maps-TB00") + +scaleSpec = cool.RecordSpecification() +scaleSpec.extend( 'value', cool.StorageType.Float ) + +scaleRecord = cool.Record(scaleSpec) +scaleRecord['value'] = 1.0 + +scaleFolderSpec = cool.FolderSpecification(cool.FolderVersioning.MULTI_VERSION, scaleSpec) +scaleFolder = db.createFolder('/GLOBAL/BField/Scales', scaleFolderSpec, descriptionDCS, True ) + +# Channel names don't seem to be handled properly by Athena +scaleFolder.createChannel( 1, "Dipole_Scale" ) +scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1, "GLOBAL-BField-Scale-01", True ) +scaleFolder.createTagRelation("GLOBAL-BField-01", "GLOBAL-BField-Scale-01") + + +scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1, "GLOBAL-BField-Scale-02", True ) +scaleFolder.createTagRelation("GLOBAL-BField-02", "GLOBAL-BField-Scale-02") + + +scaleRecord['value'] = 0.0 +scaleFolder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, scaleRecord, 1, "GLOBAL-BField-Scale-TB00", True ) +scaleFolder.createTagRelation("GLOBAL-BField-TB00", "GLOBAL-BField-Scale-TB00") + +db.closeDatabase() diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsData/src/FaserSCT_ConfigurationCondData.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsData/src/FaserSCT_ConfigurationCondData.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c630fc082a6ff16a7f696696cdc3d58abd689578 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsData/src/FaserSCT_ConfigurationCondData.cxx @@ -0,0 +1,165 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h" + +#include <algorithm> +#include <iterator> + +//---------------------------------------------------------------------- +// Constructor +FaserSCT_ConfigurationCondData::FaserSCT_ConfigurationCondData(): + m_badStripIds{}, + m_badStripArray{}, + m_badWaferIds{}, + m_badModuleIds{}, + m_badChips{} +{ + clearBadLinks(); +} + +//---------------------------------------------------------------------- +// Set a bad strip identifier +void FaserSCT_ConfigurationCondData::setBadStripId(const Identifier& badStripId, const IdentifierHash& hash, const int strip) { + m_badStripIds.insert(badStripId); + m_badStripArray[hash].set(strip); +} + +//---------------------------------------------------------------------- +// Get all bad strip identifiers +const std::set<Identifier>* FaserSCT_ConfigurationCondData::getBadStripIds() const { + return &m_badStripIds; +} + +//---------------------------------------------------------------------- +// Clear all bad strip identifiers +void FaserSCT_ConfigurationCondData::clearBadStripIds() { + m_badStripIds.clear(); + m_badStripArray.fill(std::bitset<N_STRIPS>()); +} + +//---------------------------------------------------------------------- +// Check if a strip identifier is bad one +bool FaserSCT_ConfigurationCondData::isBadStrip(const IdentifierHash& hash, const int strip) const { + return m_badStripArray[hash][strip]; +} + +//---------------------------------------------------------------------- +// Set a bad wafer identifier +void FaserSCT_ConfigurationCondData::setBadWaferId(const Identifier& badWaferId) { + m_badWaferIds.insert(badWaferId); +} + +//---------------------------------------------------------------------- +// Get all bad wafer identifiers +const std::set<Identifier>* FaserSCT_ConfigurationCondData::getBadWaferIds() const { + return &m_badWaferIds; +} + +//---------------------------------------------------------------------- +// Clear all bad wafer identifiers +void FaserSCT_ConfigurationCondData::clearBadWaferIds() { + m_badWaferIds.clear(); +} + +//---------------------------------------------------------------------- +// Check if a wafer identifier is bad one +bool FaserSCT_ConfigurationCondData::isBadWaferId(const Identifier& waferId) const { + return (m_badWaferIds.find(waferId)!=m_badWaferIds.end()); +} + +//---------------------------------------------------------------------- +// Set a bad module identifier +void FaserSCT_ConfigurationCondData::setBadModuleId(const Identifier& badModuleId) { + m_badModuleIds.insert(badModuleId); +} + +//---------------------------------------------------------------------- +// Get all bad module identifiers +const std::set<Identifier>* FaserSCT_ConfigurationCondData::getBadModuleIds() const { + return &m_badModuleIds; +} + +//---------------------------------------------------------------------- +// Clear all bad module identifiers +void FaserSCT_ConfigurationCondData::clearBadModuleIds() { + m_badModuleIds.clear(); +} + +//---------------------------------------------------------------------- +// Check if a module identifier is bad one +bool FaserSCT_ConfigurationCondData::isBadModuleId(const Identifier& moduleId) const { + return (m_badModuleIds.find(moduleId)!=m_badModuleIds.end()); +} + +//---------------------------------------------------------------------- +// Set bad links for a module +void FaserSCT_ConfigurationCondData::setBadLinks(const IdentifierHash& hash, const bool isBadLink0, const bool isBadLink1) { + unsigned int iHash{hash}; + iHash = (iHash/2)*2; // Make iHash even + if (m_badLinks.count(iHash)==0) { + m_badLinks.insert(std::pair<IdentifierHash, std::pair<bool, bool>>(iHash, std::pair<bool, bool>(isBadLink0, isBadLink1))); + } else { + m_badLinks[iHash].first &= isBadLink0; + m_badLinks[iHash].second &= isBadLink1; + } + m_badLinksArray[iHash/2].first &= isBadLink0; + m_badLinksArray[iHash/2].second &= isBadLink1; +} + +//---------------------------------------------------------------------- +// Get all bad links +const std::map<IdentifierHash, std::pair<bool, bool>>* FaserSCT_ConfigurationCondData::getBadLinks() const { + return &m_badLinks; +} + +//---------------------------------------------------------------------- +// Clear all bad links +void FaserSCT_ConfigurationCondData::clearBadLinks() { + m_badLinks.clear(); + m_badLinksArray.fill(std::make_pair(true, true)); +} + +//---------------------------------------------------------------------- +// Check if a module has bad links +std::pair<bool, bool> FaserSCT_ConfigurationCondData::areBadLinks(const IdentifierHash& hash) const { + // Bad convetion is used. true is for good link and false is for bad link... + return m_badLinksArray[hash/2]; +} + +//---------------------------------------------------------------------- +// Set bad chips for a module +void FaserSCT_ConfigurationCondData::setBadChips(const Identifier& moduleId, const unsigned int chipStatus) { + if (chipStatus!=0) m_badChips[moduleId] = chipStatus; +} + +//---------------------------------------------------------------------- +// bad chips for a module +unsigned int FaserSCT_ConfigurationCondData::getBadChips(const Identifier& moduleId) const { + std::map<Identifier, unsigned int>::const_iterator it{m_badChips.find(moduleId)}; + return (it!=m_badChips.end()) ? (*it).second : 0; +} + +//---------------------------------------------------------------------- +// Get all bad chips +const std::map<Identifier, unsigned int>* FaserSCT_ConfigurationCondData::getBadChips() const { + return &m_badChips; +} + +//---------------------------------------------------------------------- +// Clear all bad chips +void FaserSCT_ConfigurationCondData::clearBadChips() { + m_badChips.clear(); +} + +//---------------------------------------------------------------------- +// Clear all bad information +void FaserSCT_ConfigurationCondData::clear() { + clearBadStripIds(); + clearBadWaferIds(); + clearBadModuleIds(); + clearBadLinks(); + clearBadChips(); +} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt index b19cee24e9260527698b0040339c7560a97feb49..a89fc207ed29dfc53e48e3182d7dad88d3a0bfb9 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/CMakeLists.txt @@ -13,12 +13,15 @@ find_package( GMock ) # Component(s) in the package: atlas_add_component ( FaserSCT_ConditionsTools + FaserSCT_ConditionsTools/*.h src/components/*.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel FaserSCT_ConditionsToolsLib Identifier GeoModelUtilities GeoModelFaserUtilities GaudiKernel AthenaBaseComps StoreGateLib SGtests xAODEventInfo FaserSCT_ConditionsData InDetByteStreamErrors TrackerIdentifier TrackerReadoutGeometry FaserSiPropertiesToolLib InDetConditionsSummaryService ) 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_CableMappingTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_CableMappingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e3472b215006d06607c0316ecfdaf09976e0b092 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_CableMappingTool.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations +*/ + +/** @file ISCT_CableMappingTool.h Interface file for SCT_CableMappingTool. + */ + +// Multiple inclusion protection +#ifndef ISCT_CABLE_MAPPING_TOOL +#define ISCT_CABLE_MAPPING_TOOL + +//STL includes +#include <vector> + +//Gaudi Includes +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" + +class ISCT_CableMappingTool: virtual public IAlgTool { + + public: + + //----------Public Member Functions----------// + // Structors + virtual ~ISCT_CableMappingTool() = default; //!< Destructor + + /// Creates the InterfaceID and interfaceID() method + DeclareInterfaceID(ISCT_CableMappingTool, 1, 0); + + // Methods to return cable-mapping data + virtual std::map<int, std::pair<int,int> > getCableMapping(const EventContext& ctx) const = 0; + virtual std::map<int, std::pair<int,int> > getCableMapping(void) const = 0; + +}; + +//---------------------------------------------------------------------- +#endif // ISCT_CABLE_MAPPING_TOOL diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConditionsSummaryTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConditionsSummaryTool.h new file mode 100644 index 0000000000000000000000000000000000000000..8fdc8ebc3ce9214db846e19651041909b6439dbf --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConditionsSummaryTool.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ISCT_CONDITIONSSUMMARYTOOL_H +#define ISCT_CONDITIONSSUMMARYTOOL_H + +#include "GaudiKernel/IInterface.h" +#include "Identifier/IdContext.h" + +#include "InDetConditionsSummaryService/InDetHierarchy.h" + +class Identifier; +class IdentifierHash; + +/** + * @class ISCT_ConditionsSummaryTool + * Interface class for service providing summary of status of a detector element +**/ + +class ISCT_ConditionsSummaryTool: virtual public IInterface, virtual public IAlgTool { +public: + virtual ~ISCT_ConditionsSummaryTool() = default; + /// Creates the InterfaceID and interfaceID() method + DeclareInterfaceID(ISCT_ConditionsSummaryTool, 1, 0); + + virtual bool isGood(const Identifier& elementId, const InDetConditions::Hierarchy h) const =0; + virtual bool isGood(const Identifier& elementId, const EventContext& ctx, const InDetConditions::Hierarchy h) const =0; + virtual bool isGood(const IdentifierHash& elementHash) const =0; + virtual bool isGood(const IdentifierHash& elementHash, const EventContext& ctx) const =0; +}; + +#endif //ISCT_CONDITIONSSUMMARYTOOL_H diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConfigurationConditionsTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConfigurationConditionsTool.h index 597047503e59fdbf179b02eb95ddc4cc4b777358..c4d4ca0eeaead8ad6cbbe72e5d7a8979d938a528 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConfigurationConditionsTool.h +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/FaserSCT_ConditionsTools/ISCT_ConfigurationConditionsTool.h @@ -15,7 +15,7 @@ #include <map> #include "InDetConditionsSummaryService/InDetHierarchy.h" -#include "FaserSCT_ConditionsTools/ISCT_ConditionsTool.h" +#include "ISCT_ConditionsTool.h" class Identifier; class IdentifierHash; diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_CableMappingConfig.py b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_CableMappingConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..2dadb536ac49c9f4c9250e6da0d16aa012f7a6e9 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_CableMappingConfig.py @@ -0,0 +1,27 @@ +"""Define methods to configure FaserSCT_CableMapping + +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from IOVDbSvc.IOVDbSvcConfig import addFolders +FaserSCT_CableMappingTool=CompFactory.FaserSCT_CableMappingTool + +def FaserSCT_CableMappingToolCfg(flags, name="CableMappingTool", **kwargs): + """Return a configured FaserSCT_CableMappingTool""" + return FaserSCT_CableMappingTool(name, **kwargs) + +def FaserSCT_CableMappingCfg(flags, **kwargs): + """Return configured ComponentAccumulator and tool for FaserSCT_CableMapping + + CableMappingTool may be provided in kwargs + """ + acc = ComponentAccumulator() + # tool = kwargs.get("CableMappingTool", FaserSCT_CableMappingToolCfg(flags)) + # folder arguments + dbInstance = kwargs.get("dbInstance", "TDAQ_OFL") + dbFolder = kwargs.get("dbFolder", "/SCT/DAQ/CableMapping") + acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection")) + # acc.addPublicTool(tool) + return acc + diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_ConditionsSummaryToolConfig.py b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_ConditionsSummaryToolConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..8f07c6531bc9023cf6959cff9e9ccc44fb9990af --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_ConditionsSummaryToolConfig.py @@ -0,0 +1,34 @@ +# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from IOVDbSvc.IOVDbSvcConfig import addFolders +from SCT_GeoModel.SCT_GeoModelConfig import SCT_ReadoutGeometryCfg + +FaserSCT_ConfigurationCondAlg = CompFactory.FaserSCT_ConfigurationCondAlg +FaserSCT_ConfigurationConditionsTool = CompFactory.FaserSCT_ConfigurationConditionsTool + +def FaserSCT_ConfigurationCondAlgCfg(flags, name="FaserSCT_ConfigurationCondAlg", **kwargs): + acc = ComponentAccumulator() + dbInstance = kwargs.get("dbInstance", "INDET_OFL") + dbFolder = kwargs.get("dbFolder", "/SCT/DAQ/NoisyStrips") + #dbFolder = kwargs.get("dbFolder", "/INDET/NoisyStrips") + acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection")) + acc.addCondAlgo(FaserSCT_ConfigurationCondAlg(name, **kwargs)) + return acc + + +def FaserSCT_ConfigurationConditionsToolCfg(flags, name="FaserSCT_ConfigurationCondAlg", **kwargs): + acc = ComponentAccumulator() + acc.merge(FaserSCT_ConfigurationCondAlgCfg(flags, name="FaserSCT_ConfigurationCondAlg", **kwargs)) + acc.setPrivateTools(FaserSCT_ConfigurationConditionsTool(name, **kwargs)) + return acc + + +def FaserSCT_ConditionsSummaryToolCfg(flags, name="FaserSCT_ConditionsSummaryTool", **kwargs): + acc = ComponentAccumulator() + ConditionsTools = [] + SCT_ConfigurationConditionsTool = acc.popToolsAndMerge(FaserSCT_ConfigurationConditionsToolCfg(flags)) + ConditionsTools += [ SCT_ConfigurationConditionsTool ] + kwargs.setdefault("ConditionsTools", ConditionsTools) + acc.setPrivateTools(CompFactory.FaserSCT_ConditionsSummaryTool(name=name, **kwargs)) + return acc diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_DCSConditionsConfig.py b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_DCSConditionsConfig.py index cc1ddf6c99661d1fdbace11d74e7c3785e90be9e..42b71a58c0ba31f95f196a509134218e01e7e28c 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_DCSConditionsConfig.py +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_DCSConditionsConfig.py @@ -29,7 +29,7 @@ def FaserSCT_DCSConditionsCfg(flags, name="TrackerSCT_DCSConditions", **kwargs): tempFolder = kwargs.get("tempFolder", "/SCT/DCS/MODTEMP") stateFolder = kwargs.get("stateFolder", "/SCT/DCS/CHANSTAT") if tool.ReadAllDBFolders == tool.ReturnHVTemp: - acc.merge(addFolders(flags, stateFolder, dbInstance, className="CondAttrListCollection")) + acc.merge(addFolders(flags, stateFolder, dbInstance, className="CondAttrListCollection",db="OFLP200")) # algo statArgs = { "name": name + "StatCondAlg", @@ -40,7 +40,7 @@ def FaserSCT_DCSConditionsCfg(flags, name="TrackerSCT_DCSConditions", **kwargs): statAlg = FaserSCT_DCSConditionsStatCondAlg(**statArgs) acc.addCondAlgo(statAlg) if tool.ReturnHVTemp: - acc.merge(addFolders(flags, [hvFolder, tempFolder], dbInstance, className="CondAttrListCollection")) + acc.merge(addFolders(flags, [hvFolder, tempFolder], dbInstance, className="CondAttrListCollection",db="OFLP200")) hvAlg = FaserSCT_DCSConditionsHVCondAlg(name=name + "HVCondAlg", ReadKey=hvFolder) acc.addCondAlgo(hvAlg) tempAlg = FaserSCT_DCSConditionsTempCondAlg(name=name + "TempCondAlg", ReadKey=tempFolder) diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_NoisyStripsConfig.py b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_NoisyStripsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..2ac8a632f87fdc8faf7046001188806dfd1a6dd0 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/python/FaserSCT_NoisyStripsConfig.py @@ -0,0 +1,23 @@ +"""Define methods to configure FaserSCT_NoisyStrips + +Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +""" +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.ComponentFactory import CompFactory +from IOVDbSvc.IOVDbSvcConfig import addFolders +FaserSCT_NoisyStripsTool=CompFactory.FaserSCT_NoisyStripTool + +def FaserSCT_NoisyStripsToolCfg(flags, name="NoisyStripsTool", **kwargs): + """Return a configured FaserSCT_NoisyStripsTool""" + return FaserSCT_NoisyStripsTool(name, **kwargs) + +def FaserSCT_NoisyStripsCfg(flags, **kwargs): + """Return configured ComponentAccumulator and tool for FaserSCT_NoisyStrips + NoisyStripsTool may be provided in kwargs + """ + acc = ComponentAccumulator() + dbInstance = kwargs.get("dbInstance", "INDET_OFL") + dbFolder = kwargs.get("dbFolder", "/SCT/DAQ/NoisyStrips") + acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection")) + # acc.addPublicTool(tool) + return acc diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..be731ccc6509c890e1150857c57df39f637855d2 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.cxx @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +/** @file FaserSCT_CableMappingTool.cxx Implementation file for FaserSCT_CableMappingTool. + @author Dave Casper (06/01/22) +*/ + +#include "FaserSCT_CableMappingTool.h" + +// Include Athena stuff + +//---------------------------------------------------------------------- +FaserSCT_CableMappingTool::FaserSCT_CableMappingTool (const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +//---------------------------------------------------------------------- +StatusCode +FaserSCT_CableMappingTool::initialize() { + // Read Cond Handle Key + + ATH_CHECK(m_readKey.initialize()); + + return StatusCode::SUCCESS; +} // FaserSCT_CableMappingTool::initialize() + +//---------------------------------------------------------------------- +StatusCode +FaserSCT_CableMappingTool::finalize() { + // Print where you are + return StatusCode::SUCCESS; +} // FaserSCT_CableMappingTool::finalize() + +//---------------------------------------------------------------------- +std::map<int, std::pair<int, int> > +FaserSCT_CableMappingTool::getCableMapping(const EventContext& ctx) const { + // Print where you are + ATH_MSG_DEBUG("in getCableMapping()"); + std::map<int, std::pair<int, int> > 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 mapping info + std::string stationParam{"station"}; + std::string planeParam{"plane"}; + 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(stationParam) and not payload[stationParam].isNull() and + payload.exists(planeParam) and not payload[planeParam].isNull()) + { + int stationVal{payload[stationParam].data<int>()}; + int planeVal {payload[planeParam].data<int>()}; + if (stationVal < 0 || planeVal < 0) continue; // Don't include invalid entries + mappingData.emplace(std::make_pair(channelNumber, std::make_pair(stationVal, planeVal))); + } else { + ATH_MSG_WARNING(stationParam << " and/or " << planeParam << " does not exist for ChanNum " << channelNumber); + } + } + + return mappingData; +} //FaserSCT_ReadCalibChipDataTool::getNPtGainData() + +std::map<int, std::pair<int, int> > +FaserSCT_CableMappingTool::getCableMapping(void) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return getCableMapping(ctx); +} + diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b2cf0076af23e99195e4283ac563aad846487c4e --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_CableMappingTool.h @@ -0,0 +1,62 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations +*/ + +/** @file FaserSCT_CableMappingTool.h Header file for FaserSCT_CableMappingTool. + @author Dave Casper, 06/01/22 +*/ + +// Multiple inclusion protection +#ifndef FASERSCT_CABLE_MAPPING_TOOL +#define FASERSCT_CABLE_MAPPING_TOOL + +// Include interface class +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserSCT_ConditionsTools/ISCT_CableMappingTool.h" + +// Include Athena stuff +#include "AthenaPoolUtilities/CondAttrListCollection.h" +#include "StoreGate/ReadCondHandleKey.h" + +#include "GaudiKernel/ICondSvc.h" +#include "Gaudi/Property.h" + +// #include "FaserSCT_ConditionsData/FaserSCT_ConditionsParameters.h" +// #include "FaserSCT_ConditionsData/FaserSCT_GainCalibData.h" +// #include "FaserSCT_ConditionsData/FaserSCT_NoiseCalibData.h" + +// Include Gaudi classes +#include "GaudiKernel/EventContext.h" + +/** This class contains a Tool that reads SCT cable mapping data and makes it available to + other algorithms. The current implementation reads the data from a COOL database. +*/ + +class FaserSCT_CableMappingTool: public extends<AthAlgTool, ISCT_CableMappingTool> { + + public: + //----------Public Member Functions----------// + // Structors + FaserSCT_CableMappingTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor + virtual ~FaserSCT_CableMappingTool() = default; //!< Destructor + + // Standard Gaudi functions + virtual StatusCode initialize() override; //!< Gaudi initialiser + virtual StatusCode finalize() override; //!< Gaudi finaliser + + // Methods to return calibration data + virtual std::map<int, std::pair<int, int> > getCableMapping(const EventContext& ctx) const override; + virtual std::map<int, std::pair<int, int> > getCableMapping(void) const override; + + private: + // Read Cond Handle + SG::ReadCondHandleKey<CondAttrListCollection> m_readKey{this, "ReadKey", "/SCT/DAQ/CableMapping", "Key of input cabling folder"}; + + ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"}; + +}; + +//---------------------------------------------------------------------- +#endif // FASERSCT_CABLE_MAPPING_TOOL diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..afa408534cb14480c4664d5f3055af1b94e1126a --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.cxx @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "FaserSCT_ConditionsSummaryTool.h" +#include "FaserSCT_ConditionsTools/ISCT_ConditionsTool.h" + + +FaserSCT_ConditionsSummaryTool::FaserSCT_ConditionsSummaryTool(const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent), m_toolHandles{this} { + declareProperty("ConditionsTools", m_toolHandles); +} + +StatusCode FaserSCT_ConditionsSummaryTool::initialize() { + ATH_CHECK(m_toolHandles.retrieve()); + m_noReports = m_toolHandles.empty(); + return StatusCode::SUCCESS; +} + +bool FaserSCT_ConditionsSummaryTool::isGood(const Identifier& elementId, const EventContext& ctx, const InDetConditions::Hierarchy h) const { + if (not m_noReports) { + for (const ToolHandle<ISCT_ConditionsTool>& tool: m_toolHandles) { + if (tool->canReportAbout(h) and (not tool->isGood(elementId, ctx, h))) return false; + } + } + return true; +} + +bool FaserSCT_ConditionsSummaryTool::isGood(const Identifier& elementId, const InDetConditions::Hierarchy h) const { + return isGood(elementId, Gaudi::Hive::currentContext(), h); +} + +bool FaserSCT_ConditionsSummaryTool::isGood(const IdentifierHash& elementHash, const EventContext& ctx) const { + if (not m_noReports) { + for (const ToolHandle<ISCT_ConditionsTool>& tool: m_toolHandles) { + if ((tool->canReportAbout(InDetConditions::SCT_SIDE) or + tool->canReportAbout(InDetConditions::SCT_MODULE)) and + (not tool->isGood(elementHash, ctx))) { + return false; + } + } + } + return true; +} + +bool FaserSCT_ConditionsSummaryTool::isGood(const IdentifierHash& elementHash) const { + return isGood(elementHash, Gaudi::Hive::currentContext()); +} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.h new file mode 100644 index 0000000000000000000000000000000000000000..681ac2be455a5ab243f61165c99022a169f8ee3e --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConditionsSummaryTool.h @@ -0,0 +1,38 @@ +#ifndef FASERSCT_CONDITIONSSUMMARYTOOL_H +#define FASERSCT_CONDITIONSSUMMARYTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "InDetConditionsSummaryService/InDetHierarchy.h" +#include "FaserSCT_ConditionsTools/ISCT_ConditionsSummaryTool.h" + +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/EventContext.h" + +#include <string> +#include <vector> + +class ISCT_ConditionsTool; + +/** + * @class FaserSCT_ConditionsSummaryTool + * Interface class for tool providing summary of status of an SCT detector element +**/ +class FaserSCT_ConditionsSummaryTool: public extends<AthAlgTool, ISCT_ConditionsSummaryTool> { +public: + FaserSCT_ConditionsSummaryTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Tool constructor + virtual ~FaserSCT_ConditionsSummaryTool() = default; + virtual StatusCode initialize() override; + + virtual bool isGood(const Identifier& elementId, const InDetConditions::Hierarchy h) const override; + virtual bool isGood(const Identifier& elementId, const EventContext& ctx, const InDetConditions::Hierarchy h) const override; + virtual bool isGood(const IdentifierHash& elementHash) const override; + virtual bool isGood(const IdentifierHash& elementHash, const EventContext& ctx) const override; + +private: + StringArrayProperty m_reportingTools; //!< list of tools to be used + ToolHandleArray<ISCT_ConditionsTool> m_toolHandles; + bool m_noReports{true}; +}; + + +#endif // FASERSCT_CONDITIONSSUMMARYTOOL_H diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.cxx b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1c6b2a8aea93f47f1ac295470ac118baab5744e2 --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.cxx @@ -0,0 +1,333 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#include "FaserSCT_ConfigurationConditionsTool.h" + +// Athena includes +#include "TrackerIdentifier/FaserSCT_ID.h" +// #include "InDetReadoutGeometry/SiDetectorElement.h" +#include "StoreGate/ReadCondHandle.h" + +// Constructor +FaserSCT_ConfigurationConditionsTool::FaserSCT_ConfigurationConditionsTool(const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +// Initialize +StatusCode FaserSCT_ConfigurationConditionsTool::initialize() { + ATH_MSG_DEBUG("Initializing configuration"); + + ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); + + // Read Cond Handle Key + ATH_CHECK(m_condKey.initialize()); + // ATH_CHECK(m_SCTDetEleCollKey.initialize()); + + return StatusCode::SUCCESS; +} + +// What level of element can this service report about +bool FaserSCT_ConfigurationConditionsTool::canReportAbout(InDetConditions::Hierarchy h) const { + return (h == InDetConditions::SCT_STRIP or + h == InDetConditions::SCT_CHIP or + h == InDetConditions::SCT_SIDE or + h == InDetConditions::SCT_MODULE or + h == InDetConditions::DEFAULT); +} + +// Is an element with this Identifier and hierarchy good? +bool FaserSCT_ConfigurationConditionsTool::isGood(const Identifier& elementId, const EventContext& ctx, InDetConditions::Hierarchy h) const { + if (not canReportAbout(h)) return true; + + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In isGood, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return false; + } + + bool result{true}; + if (h == InDetConditions::SCT_STRIP) { + result = (not condData->isBadStrip(m_idHelper->wafer_hash(m_idHelper->wafer_id(elementId)), + m_idHelper->strip(elementId))); + + ATH_MSG_VERBOSE("isGood: Strip " << m_idHelper->strip(elementId) << "/" << m_idHelper->wafer_hash(m_idHelper->wafer_id(elementId)) << " is " << result); + + // If strip itself is not bad, check if it's in a bad module + if (result and m_checkStripsInsideModules) { + result = (not isStripInBadModule(elementId, condData)); + ATH_MSG_VERBOSE("Good strip set bad by module check"); + } + } else if (h == InDetConditions::SCT_MODULE) { + result = (not condData->isBadModuleId(elementId)); + } else if (h == InDetConditions::SCT_SIDE or h == InDetConditions::DEFAULT) { + result = (not condData->isBadWaferId(elementId)); + } else if (h == InDetConditions::SCT_CHIP) { + result = isGoodChip(elementId, ctx); + } + return result; +} + +bool FaserSCT_ConfigurationConditionsTool::isGood(const Identifier& elementId, InDetConditions::Hierarchy h) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + + return isGood(elementId, ctx, h); +} + +// Is a wafer with this IdentifierHash good? +bool FaserSCT_ConfigurationConditionsTool::isGood(const IdentifierHash& hashId, const EventContext& ctx) const { + const Identifier elementId{m_idHelper->wafer_id(hashId)}; + return isGood(elementId, ctx, InDetConditions::SCT_SIDE); +} + +bool FaserSCT_ConfigurationConditionsTool::isGood(const IdentifierHash& hashId) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return isGood(hashId, ctx); +} + +// Is a chip with this Identifier good? +bool FaserSCT_ConfigurationConditionsTool::isGoodChip(const Identifier& stripId, const EventContext& ctx) const { + // This check assumes present SCT. + // Get module number + const Identifier moduleId{m_idHelper->module_id(stripId)}; + if (not moduleId.is_valid()) { + ATH_MSG_WARNING("moduleId obtained from stripId " << stripId << " is invalid."); + return false; + } + + // badChips word for the module + const unsigned int v_badChips{badChips(moduleId, ctx)}; + // badChips holds 12 bits. + // bit 0 (LSB) is chip 0 for side 0. + // bit 5 is chip 5 for side 0. + // bit 6 is chip 6 for side 1. + // bit 11 is chip 11 for side 1. + + // If there is no bad chip, this check is done. + if (v_badChips==0) return true; + + const int side{m_idHelper->side(stripId)}; + // Check the six chips on the side + // 0x3F = 0000 0011 1111 + // 0xFC0 = 1111 1100 0000 + // If there is no bad chip on the side, this check is done. + if ((side==0 and (v_badChips & 0x3F)==0) or (side==1 and (v_badChips & 0xFC0)==0)) return true; + + int chip{getChip(stripId, ctx)}; + if (chip<0 or chip>=12) { + ATH_MSG_WARNING("chip number is invalid: " << chip); + return false; + } + + // Check if the chip is bad + const bool badChip{static_cast<bool>(v_badChips & (1<<chip))}; + + return (not badChip); +} + +// Check if a strip is within a bad module +bool FaserSCT_ConfigurationConditionsTool::isStripInBadModule(const Identifier& stripId, const FaserSCT_ConfigurationCondData* condData) const { + if (condData==nullptr) { + ATH_MSG_ERROR("In isStripInBadModule, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return true; + } + + const Identifier moduleId(m_idHelper->module_id(m_idHelper->wafer_id(stripId))); + return condData->isBadModuleId(moduleId); +} + +// Check if a wafer is within a bad module +bool FaserSCT_ConfigurationConditionsTool::isWaferInBadModule(const Identifier& waferId, const EventContext& ctx) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In isWaferInBadModule, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return true; + } + + const Identifier moduleId{m_idHelper->module_id(waferId)}; + return condData->isBadModuleId(moduleId); +} + +// Find the chip number containing a particular strip Identifier +int FaserSCT_ConfigurationConditionsTool::getChip(const Identifier& stripId, const EventContext& ctx) const { + // Find side and strip number + const int side{m_idHelper->side(stripId)}; + int strip{m_idHelper->strip(stripId)}; + + // Check for swapped readout direction + const IdentifierHash waferHash{m_idHelper->wafer_hash(m_idHelper->wafer_id(stripId))}; + const TrackerDD::SiDetectorElement* pElement{getDetectorElement(waferHash, ctx)}; + if (pElement==nullptr) { + ATH_MSG_FATAL("Element pointer is nullptr in 'badStrips' method"); + return invalidChipNumber; + } + strip = (pElement->swapPhiReadoutDirection()) ? lastStrip - strip: strip; + + // Find chip number + return (side==0 ? strip/stripsPerChip : strip/stripsPerChip + 6); +} + +int FaserSCT_ConfigurationConditionsTool::getChip(const Identifier& stripId) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return getChip(stripId, ctx); +} + +const std::set<Identifier>* FaserSCT_ConfigurationConditionsTool::badModules(const EventContext& ctx) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badModules, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return nullptr; + } + + return condData->getBadModuleIds(); +} + +const std::set<Identifier>* FaserSCT_ConfigurationConditionsTool::badModules() const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badModules(ctx); +} + +void FaserSCT_ConfigurationConditionsTool::badStrips(const Identifier& moduleId, std::set<Identifier>& strips, const EventContext& ctx, bool ignoreBadModules, bool ignoreBadChips) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badStrips, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return; + } + + // Bad strips for a given module + if (ignoreBadModules) { + // Ignore strips in bad modules + if (condData->isBadModuleId(moduleId)) return; + } + + for (const Identifier& badStripId: *(condData->getBadStripIds())) { + if (ignoreBadChips) { + // Ignore strips in bad chips + const int chip{getChip(badStripId)}; + if (chip!=invalidChipNumber) { + unsigned int chipStatusWord{condData->getBadChips(moduleId)}; + if ((chipStatusWord & (1 << chip)) != 0) continue; + } + } + if (m_idHelper->module_id(m_idHelper->wafer_id(badStripId)) == moduleId) strips.insert(badStripId); + } +} + +void FaserSCT_ConfigurationConditionsTool::badStrips(const Identifier& moduleId, std::set<Identifier>& strips, bool ignoreBadModules, bool ignoreBadChips) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badStrips(moduleId, strips, ctx, ignoreBadModules, ignoreBadChips); +} + +std::pair<bool, bool> FaserSCT_ConfigurationConditionsTool::badLinks(const IdentifierHash& hash, const EventContext& ctx) const { + // Bad links for a given module + // Bad convetion is used. true is for good link and false is for bad link... + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badLinks, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return std::pair<bool, bool>{false, false}; + } + + return condData->areBadLinks(hash); +} + +std::pair<bool, bool> FaserSCT_ConfigurationConditionsTool::badLinks(const IdentifierHash& hash) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badLinks(hash, ctx); +} + +const std::map<IdentifierHash, std::pair<bool, bool>>* FaserSCT_ConfigurationConditionsTool::badLinks(const EventContext& ctx) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badLinks, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return nullptr; + } + + return condData->getBadLinks(); +} + +const std::map<IdentifierHash, std::pair<bool, bool>>* FaserSCT_ConfigurationConditionsTool::badLinks() const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badLinks(ctx); +} + +const std::map<Identifier, unsigned int>* FaserSCT_ConfigurationConditionsTool::badChips(const EventContext& ctx) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badChips, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return nullptr; + } + + return condData->getBadChips(); +} + +const std::map<Identifier, unsigned int>* FaserSCT_ConfigurationConditionsTool::badChips() const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badChips(ctx); +} + +unsigned int FaserSCT_ConfigurationConditionsTool::badChips(const Identifier& moduleId, const EventContext& ctx) const { + // Bad chips for a given module + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badChips, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return 0xFFF; // 12 bad chips + } + + return condData->getBadChips(moduleId); +} + +unsigned int FaserSCT_ConfigurationConditionsTool::badChips(const Identifier& moduleId) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + return badChips(moduleId, ctx); +} +void +FaserSCT_ConfigurationConditionsTool::badStrips(std::set<Identifier>& strips, const EventContext& ctx, bool ignoreBadModules, bool ignoreBadChips) const { + const FaserSCT_ConfigurationCondData* condData{getCondData(ctx)}; + if (condData==nullptr) { + ATH_MSG_ERROR("In badStrips, FaserSCT_ConfigurationCondData pointer cannot be retrieved"); + return; + } + + if (!ignoreBadModules and !ignoreBadChips) { + std::copy(condData->getBadStripIds()->begin(), condData->getBadStripIds()->end(), std::inserter(strips,strips.begin())); + return; + } + for (const Identifier& badStripId: *(condData->getBadStripIds())) { + const Identifier moduleId{m_idHelper->module_id(m_idHelper->wafer_id(badStripId))}; + // Ignore strips in bad modules + if (ignoreBadModules) { + if (condData->isBadModuleId(moduleId)) continue; + } + // Ignore strips in bad chips + if (ignoreBadChips) { + const int chip{getChip(badStripId)}; + if (chip!=invalidChipNumber) { + unsigned int chipStatusWord{condData->getBadChips(moduleId)}; + if ((chipStatusWord & (1 << chip)) != 0) continue; + } + } + strips.insert(badStripId); + } +} + +void +FaserSCT_ConfigurationConditionsTool::badStrips(std::set<Identifier>& strips, bool ignoreBadModules, bool ignoreBadChips) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + badStrips(strips, ctx, ignoreBadModules, ignoreBadChips); +} + +const FaserSCT_ConfigurationCondData* +FaserSCT_ConfigurationConditionsTool::getCondData(const EventContext& ctx) const { + SG::ReadCondHandle<FaserSCT_ConfigurationCondData> condData{m_condKey, ctx}; + if (!condData.isValid()) { + ATH_MSG_ERROR("can't retrieve condData"); + } + return condData.retrieve(); +} + +const TrackerDD::SiDetectorElement* FaserSCT_ConfigurationConditionsTool::getDetectorElement(const IdentifierHash& waferHash, const EventContext& ctx) const { + SG::ReadCondHandle<TrackerDD::SiDetectorElementCollection> condData{m_SCTDetEleCollKey, ctx}; + if (not condData.isValid()) return nullptr; + return condData->getDetectorElement(waferHash); +} diff --git a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.h b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.h new file mode 100644 index 0000000000000000000000000000000000000000..49fdb5c99735b25fc66bd218f3ba7bf784f2deab --- /dev/null +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/FaserSCT_ConfigurationConditionsTool.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file FaserSCT_ConfigurationConditionsTool.h + * header file for tool which reads SCT configuration from database + * @author shaun.roe@cern.ch, gwilliam@mail.cern.ch +**/ + + +#ifndef FASERSCT_CONFIGURATIONCONDITIONSTOOL_H +#define FASERSCT_CONFIGURATIONCONDITIONSTOOL_H + +// Athena includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "FaserSCT_ConditionsTools/ISCT_ConfigurationConditionsTool.h" + +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "FaserSCT_ConditionsData/FaserSCT_ConfigurationCondData.h" +#include "StoreGate/ReadCondHandleKey.h" + +// Gaudi includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/ContextSpecificPtr.h" +#include "TrackerReadoutGeometry/SiDetectorElementCollection.h" + +// STL includes +#include <string> + +// Forward declarations +class FaserSCT_ID; + +/** + * @class FaserSCT_ConfigurationConditionsTool + * Tool which reads FaserSCT_Configuration from the database + * Deals with bad modules, bad links, strips out of the readout and bad strips +**/ + +class FaserSCT_ConfigurationConditionsTool: public extends<AthAlgTool, ISCT_ConfigurationConditionsTool> { + public: + + //@name Tool methods + //@{ + FaserSCT_ConfigurationConditionsTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~FaserSCT_ConfigurationConditionsTool() = default; + virtual StatusCode initialize() override; + //@} + + /**Can the tool report about the given component? (chip, module...)*/ + virtual bool canReportAbout(InDetConditions::Hierarchy h) const override; + + /**Is the detector element good?*/ + virtual bool isGood(const Identifier& elementId, InDetConditions::Hierarchy h=InDetConditions::DEFAULT) const override; + virtual bool isGood(const Identifier& elementId, const EventContext& ctx, InDetConditions::Hierarchy h=InDetConditions::DEFAULT) const override; + + /**Is it good?, using wafer hash*/ + virtual bool isGood(const IdentifierHash& hashId) const override; + virtual bool isGood(const IdentifierHash& hashId, const EventContext& ctx) const override; + + /**List of bad modules*/ + virtual const std::set<Identifier>* badModules(const EventContext& ctx) const override; + virtual const std::set<Identifier>* badModules() const override; + /**List of bad strips*/ + virtual void badStrips(std::set<Identifier>& strips, const EventContext& ctx, bool ignoreBadModules=false, bool ignoreBadChips=false) const override; + virtual void badStrips(std::set<Identifier>& strips, bool ignoreBadModules=false, bool ignoreBadChips=false) const override; + /**List of bad strips for a given module*/ + virtual void badStrips(const Identifier& moduleId, std::set<Identifier>& strips, const EventContext& ctx, bool ignoreBadModules=false, bool ignoreBadChips=false) const override; + virtual void badStrips(const Identifier& moduleId, std::set<Identifier>& strips, bool ignoreBadModules=false, bool ignoreBadChips=false) const override; + /**List of bad links*/ + virtual std::pair<bool, bool> badLinks(const IdentifierHash& hash, const EventContext& ctx) const override; + virtual std::pair<bool, bool> badLinks(const IdentifierHash& hash) const override; + /**Bad links for a given module*/ + virtual const std::map<IdentifierHash, std::pair<bool, bool>>* badLinks(const EventContext& ctx) const override; + virtual const std::map<IdentifierHash, std::pair<bool, bool>>* badLinks() const override; + /**List of bad chips*/ + virtual const std::map<Identifier, unsigned int>* badChips(const EventContext& ctx) const override; + virtual const std::map<Identifier, unsigned int>* badChips() const override; + /**Bad chips for a given module*/ + virtual unsigned int badChips(const Identifier& moduleId, const EventContext& ctx) const override; + virtual unsigned int badChips(const Identifier& moduleId) const override; + /** Get the chip number containing a particular strip*/ + virtual int getChip(const Identifier& stripId, const EventContext& ctx) const override; + virtual int getChip(const Identifier& stripId) const override; + + private: + SG::ReadCondHandleKey<FaserSCT_ConfigurationCondData> m_condKey{this, "CondKeyConfig", "FaserSCT_ConfigurationCondData", "SCT DAQ configuration"}; + SG::ReadCondHandleKey<TrackerDD::SiDetectorElementCollection> m_SCTDetEleCollKey{this, "SCTDetEleCollKey", "SCT_DetectorElementCollection", "Key of SiDetectorElementCollection for SCT"}; + + const FaserSCT_ID* m_idHelper{nullptr}; + BooleanProperty m_checkStripsInsideModules{this, "checkStripsInsideModule", false, " Do we want to check if a strip is bad because it is inside a bad module"}; + + /** Is a strip within a bad module*/ + bool isStripInBadModule(const Identifier& stripId, const FaserSCT_ConfigurationCondData*) const; + /** Is a wafer in a bad module*/ + bool isWaferInBadModule(const Identifier& waferId, const EventContext& ctx) const; + + /**Is a chip with this Identifier good?*/ + bool isGoodChip(const Identifier& stripId, const EventContext& ctx) const; + + /** enum for constants*/ + enum {stripsPerChip=128, lastStrip=767, invalidChipNumber=-1}; + + const FaserSCT_ConfigurationCondData* getCondData(const EventContext& ctx) const; + const TrackerDD::SiDetectorElement* getDetectorElement(const IdentifierHash& waferHash, const EventContext& ctx) const; +}; + +#endif //FASERSCT_CONFIGURATIONCONDITIONSTOOL_H 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 5cf6ed934a7efda6c107717ff2eb41a70237fa8d..ae50a450b23170de19a520750fac0c9893f29ec6 100644 --- a/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx +++ b/Tracker/TrackerConditions/FaserSCT_ConditionsTools/src/components/FaserSCT_ConditionsTools_entries.cxx @@ -19,6 +19,9 @@ #include "../FaserSCT_SiliconConditionsTool.h" // #include "../SCT_StripVetoTool.h" // #include "../SCT_TdaqEnabledTool.h" +#include "../FaserSCT_CableMappingTool.h" +#include "../FaserSCT_ConditionsSummaryTool.h" +#include "../FaserSCT_ConfigurationConditionsTool.h" // DECLARE_COMPONENT( SCT_ByteStreamErrorsTool ) // DECLARE_COMPONENT( SCT_ChargeTrappingTool ) @@ -41,3 +44,6 @@ DECLARE_COMPONENT( FaserSCT_ReadCalibChipDataTool ) DECLARE_COMPONENT( FaserSCT_SiliconConditionsTool ) // DECLARE_COMPONENT( SCT_StripVetoTool ) // DECLARE_COMPONENT( SCT_TdaqEnabledTool ) +DECLARE_COMPONENT( FaserSCT_CableMappingTool ) +DECLARE_COMPONENT( FaserSCT_ConditionsSummaryTool ) +DECLARE_COMPONENT( FaserSCT_ConfigurationConditionsTool ) diff --git a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py index 26dff64f141ad9f22ff4ac430ef2fbdf98065f7e..038c8c38bb3c6d0daed962726f310867873a4c02 100644 --- a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py +++ b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py @@ -2,7 +2,7 @@ from AthenaConfiguration.ComponentFactory import CompFactory from AthenaConfiguration.Enums import ProductionStep -from IOVDbSvc.IOVDbSvcConfig import addFoldersSplitOnline +from IOVDbSvc.IOVDbSvcConfig import addFolders, addFoldersSplitOnline def FaserSCT_GeometryCfg( flags ): from FaserGeoModel.GeoModelConfig import GeoModelCfg @@ -33,10 +33,11 @@ def FaserSCT_GeometryCfg( flags ): # acc.merge(addFoldersSplitOnline(flags,"INDET","/Indet/Onl/AlignL3","/Indet/AlignL3",className="AlignableTransformContainer")) print("FaserSCT dynamic align flag is not supported!") else: + print("Override Alignment dbname to OFLP200, fix this when alignment available in CONDBR3") if flags.Common.Project != "AthSimulation" and (flags.Common.ProductionStep != ProductionStep.Simulation or flags.Overlay.DataOverlay): - acc.merge(addFoldersSplitOnline(flags,"SCT","/Tracker/Onl/Align","/Tracker/Align",className="AlignableTransformContainer")) + acc.merge(addFolders(flags,"/Tracker/Align", "SCT_OFL", className="AlignableTransformContainer", db="OFLP200")) else: - acc.merge(addFoldersSplitOnline(flags,"SCT","/Tracker/Onl/Align","/Tracker/Align")) + acc.merge(addFolders(flags, "/Tracker/Align", "SCT_OFL", db="OFLP200")) if flags.Common.Project != "AthSimulation": # Protection for AthSimulation builds if flags.Common.ProductionStep != ProductionStep.Simulation or flags.Overlay.DataOverlay: FaserSCT_AlignCondAlg = CompFactory.FaserSCT_AlignCondAlg diff --git a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/TrackerReadoutGeometry/SiDetectorElement.h b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/TrackerReadoutGeometry/SiDetectorElement.h index 652add49be92b54bcf1b273d8d1da11f1ad4fd52..3286b43b3f8b66d91ee8fe864cd3218a8301802c 100644 --- a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/TrackerReadoutGeometry/SiDetectorElement.h +++ b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/TrackerReadoutGeometry/SiDetectorElement.h @@ -221,6 +221,8 @@ namespace TrackerDD { // Position /// Local (simulation/hit frame) to global transform virtual const GeoTrf::Transform3D& transformHit() const; + /// Local (simulation/hit frame) to module transform + virtual const GeoTrf::Transform3D& transformModule() const; /// Local (reconstruction frame) to global transform virtual const Amg::Transform3D& transform() const override final; /** @@ -340,40 +342,37 @@ namespace TrackerDD { @name Module Frame Methods to help work with the module frame. - This is mainly of of use in the SCT where the module frame can - in general be different from the element frame. It is actully - defined as the frame of one of the sides (currently the axial - side), but using these methods one does not need to make any - assumptions about what the actual frame is. In the following - methods the local element frame is the local reconstruction - frame of this element. + This is mainly of of use in the SCT where the module frame is + different from the element frame. We have removed the ATLAS convention + in which the module frame was one of the wafers. */ //@{ + /// Module to global frame transform. /// Includes misalignment. The module frame is defined to be the - /// local reconstruction frame of the axial layer in the SCT. For - /// the pixel it is the same as the element. + /// frame in which the wafers are centered, rotated by +/- stereo angle, and equally offset in depth. + /// For the pixel it is the same as the element. //const HepGeom::Transform3D & moduleTransform() const; + const HepGeom::Transform3D& moduleTransformCLHEP() const; const Amg::Transform3D& moduleTransform() const; /// Default module to global frame transform, ie with no misalignment. /// The module frame is defined to be the - /// local reconstruction frame of the axial layer in the SCT. For - /// the pixel it is the same as the element. + /// frame in which each wafer is centered, rotated by +/- stereo angle, and offset in depth. + /// For the pixel it is the same as the element. Amg::Transform3D defModuleTransform() const; + /// Default to global transform + /// ie with no misalignment. + const HepGeom::Transform3D defModuleTransformCLHEP() const; /// Take a transform of the local element frame and return its equivalent in the module frame. //HepGeom::Transform3D localToModuleFrame(const HepGeom::Transform3D & localTransform) const; Amg::Transform3D localToModuleFrame(const Amg::Transform3D& localTransform) const; - /// Transformation from local element to module frame. This can be - /// used to take a local position in the element frame and transform - /// it to a position in the module frame. If one is already in the - /// module frame it will return the Identity transform. - //HepGeom::Transform3D localToModuleTransform() const; + /// Transformation from local element to module frame. Amg::Transform3D localToModuleTransform() const; /// Check if the element and module frame are the same. @@ -695,6 +694,8 @@ namespace TrackerDD { mutable Amg::Transform3D m_transform ATLAS_THREAD_SAFE; // Guarded by m_mutex mutable HepGeom::Transform3D m_transformCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex + mutable Amg::Transform3D m_moduleTransform ATLAS_THREAD_SAFE; // Guarded by m_mutex + mutable HepGeom::Transform3D m_moduleTransformCLHEP ATLAS_THREAD_SAFE; // Guarded by m_mutex mutable Amg::Vector3D m_normal ATLAS_THREAD_SAFE; // Guarded by m_mutex mutable Amg::Vector3D m_etaAxis ATLAS_THREAD_SAFE; // Guarded by m_mutex diff --git a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SiDetectorElement.cxx b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SiDetectorElement.cxx index c9a29684d559305ac76ad06b2b632701df8cdc3c..07a1fadae9b0560bd722ed281f0a01b83d514477 100644 --- a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SiDetectorElement.cxx +++ b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SiDetectorElement.cxx @@ -122,6 +122,9 @@ namespace TrackerDD { SiDetectorElement::updateCache() const { const GeoTrf::Transform3D& geoTransform = transformHit(); + const GeoTrf::Transform3D& geoModuleTransform = transformModule(); + // ATH_MSG_ALWAYS("Wafer transform: " << geoTransform.translation() << "//" << geoTransform.rotation() ); + // ATH_MSG_ALWAYS("Module transform: " << geoModuleTransform.translation() << "//" << geoModuleTransform.rotation() ); double radialShift = 0.; @@ -215,6 +218,9 @@ namespace TrackerDD { m_transformCLHEP = Amg::EigenTransformToCLHEP(geoTransform) * recoToHitTransformImpl(); m_transform = Amg::CLHEPTransformToEigen(m_transformCLHEP); + m_moduleTransformCLHEP = Amg::EigenTransformToCLHEP(geoModuleTransform) * recoToHitTransformImpl(); + m_moduleTransform = Amg::CLHEPTransformToEigen(m_moduleTransformCLHEP); + // Check that local frame is right-handed. (ie transform has no reflection) // This can be done by checking that the determinant is >0. if (m_firstTime) { // Only need to check this once. @@ -286,6 +292,28 @@ namespace TrackerDD { return getMaterialGeom()->getAbsoluteTransform(); } + const GeoTrf::Transform3D& + SiDetectorElement::transformModule() const + { + PVConstLink parent = getMaterialGeom()->getParent()->getParent(); + const GeoVFullPhysVol* fullParent = dynamic_cast<const GeoVFullPhysVol*>(&(*parent)); + if (fullParent == nullptr) + { + ATH_MSG_FATAL("Unable to reach parent module volume"); + if (m_geoAlignStore) { + const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getAbsPosition(getMaterialGeom()); + if (ptrXf) return *ptrXf; + } + return getMaterialGeom()->getAbsoluteTransform(); + } + // ATH_MSG_ALWAYS("Found full parent named: " << fullParent->getLogVol()->getName() << " with id " << fullParent->getId()); + if (m_geoAlignStore) { + const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getAbsPosition(fullParent); + if (ptrXf) return *ptrXf; + } + return fullParent->getAbsoluteTransform(); + } + const Amg::Transform3D& SiDetectorElement::transform() const { @@ -377,40 +405,81 @@ namespace TrackerDD { const Amg::Transform3D& SiDetectorElement::moduleTransform() const { - return (isModuleFrame()) ? transform() : m_otherSide->transform(); + if (!m_cacheValid) { + std::lock_guard<std::mutex> lock(m_mutex); + if (!m_cacheValid) updateCache(); + } + + return m_moduleTransform; + } + + const HepGeom::Transform3D& + SiDetectorElement::moduleTransformCLHEP() const + { + //stuff to get the CLHEP version of the local to global transform. + if (!m_cacheValid) { + std::lock_guard<std::mutex> lock(m_mutex); + if (!m_cacheValid) updateCache(); + } + + return m_moduleTransformCLHEP; } Amg::Transform3D SiDetectorElement::defModuleTransform() const { - return (isModuleFrame()) ? defTransform() : m_otherSide->defTransform(); + HepGeom::Transform3D tmpTransform = defModuleTransformCLHEP(); + return Amg::CLHEPTransformToEigen(tmpTransform); } + const HepGeom::Transform3D + SiDetectorElement::defModuleTransformCLHEP() const + { + PVConstLink parent = getMaterialGeom()->getParent()->getParent(); + const GeoVFullPhysVol* fullParent = dynamic_cast<const GeoVFullPhysVol*>(&(*parent)); + if (fullParent == nullptr) + { + ATH_MSG_FATAL("Unable to reach parent module volume"); + if (m_geoAlignStore) { + const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getDefAbsPosition(getMaterialGeom()); + if (ptrXf) return Amg::EigenTransformToCLHEP(*ptrXf) * recoToHitTransform(); + } + return Amg::EigenTransformToCLHEP(getMaterialGeom()->getDefAbsoluteTransform()) * recoToHitTransform(); + } + // ATH_MSG_ALWAYS("Found full parent named: " << fullParent->getLogVol()->getName() << " with id " << fullParent->getId()); + if (m_geoAlignStore) { + const GeoTrf::Transform3D* ptrXf = m_geoAlignStore->getDefAbsPosition(fullParent); + if (ptrXf) return Amg::EigenTransformToCLHEP(*ptrXf) * recoToHitTransform(); + } + return Amg::EigenTransformToCLHEP(fullParent->getDefAbsoluteTransform()) * recoToHitTransform(); + } + + // Take a transform in the local reconstruction and return it in the module frame // For a given transform l in frame A. The equivalent transform in frame B is // B.inverse() * A * l * A.inverse() * B // Here A is the local to global transform of the element and B is the local to global // transform of the module. - // If we are already in the module frame then there is nothing to do, we just return the - // transform that is input. Otherwise we use the above formula. Amg::Transform3D SiDetectorElement::localToModuleFrame(const Amg::Transform3D& localTransform) const { - if (isModuleFrame()) { - return localTransform; - } else { - return m_otherSide->transform().inverse() * transform() * localTransform * transform().inverse() * m_otherSide->transform(); - } + return moduleTransform().inverse() * transform() * localTransform * transform().inverse() * moduleTransform(); + // if (isModuleFrame()) { + // return localTransform; + // } else { + // return m_otherSide->transform().inverse() * transform() * localTransform * transform().inverse() * m_otherSide->transform(); + // } } Amg::Transform3D SiDetectorElement::localToModuleTransform() const { - if (isModuleFrame()) { - return Amg::Transform3D(); // Identity - } else { - return m_otherSide->transform().inverse() * transform(); - } + return transform().inverse() * moduleTransform(); + // if (isModuleFrame()) { + // return Amg::Transform3D(); // Identity + // } else { + // return m_otherSide->transform().inverse() * transform(); + // } } bool diff --git a/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py b/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py index a4bd9fb2c54f97e9983106eb6743c00bb772e585..f952b5766a0acf1085974f3af9332a8ac3de0462 100644 --- a/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py +++ b/Tracker/TrackerDigitization/FaserSCT_Digitization/python/FaserSCT_DigitizationConfigNew.py @@ -239,10 +239,12 @@ 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", ItemList)) + 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/CMakeLists.txt b/Tracker/TrackerEventCnv/TrackerByteStream/CMakeLists.txt index 2ae44b44d80880acc3f92a74b9e32de0e2e1ee55..37ed93239bfb5f8ce750be0ce355ac72ee3e5f59 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/CMakeLists.txt +++ b/Tracker/TrackerEventCnv/TrackerByteStream/CMakeLists.txt @@ -8,7 +8,7 @@ atlas_subdir( TrackerByteStream ) atlas_add_component( TrackerByteStream src/*.cxx src/*.h src/components/*.cxx - LINK_LIBRARIES AthenaKernel GaudiKernel StoreGateLib FaserByteStreamCnvSvcBaseLib FaserEventStorageLib TrackerRawData TrackerReadoutGeometry TrackerIdentifier EventFormats + LINK_LIBRARIES AthenaKernel GaudiKernel StoreGateLib FaserByteStreamCnvSvcBaseLib FaserEventStorageLib TrackerRawData TrackerReadoutGeometry TrackerIdentifier EventFormats FaserSCT_ConditionsToolsLib PRIVATE_LINK_LIBRARIES AthenaBaseComps ) diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/python/TrackerByteStreamConfig.py b/Tracker/TrackerEventCnv/TrackerByteStream/python/TrackerByteStreamConfig.py index 06e029772acd553a6791869ab62dcedbad321bff..f1945e30e6c607f7d107d1ca3c27a4be427d3524 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/python/TrackerByteStreamConfig.py +++ b/Tracker/TrackerEventCnv/TrackerByteStream/python/TrackerByteStreamConfig.py @@ -2,8 +2,11 @@ #from AthenaConfiguration.ComponentFactory import CompFactory from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from FaserSCT_ConditionsTools.FaserSCT_CableMappingConfig import FaserSCT_CableMappingCfg +# from FaserSCT_ConditionsTools.FaserSCT_DCSConditionsConfig import FaserSCT_DCSConditionsCfg def TrackerByteStreamCfg(configFlags, **kwargs): - acc = ComponentAccumulator() + acc = FaserSCT_CableMappingCfg(configFlags, **kwargs) + # tool = acc.popToolsAndMerge(acc) return acc \ No newline at end of file diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx index 8a82d3cdd8aac0fd64f28d389402308bdf8525d7..4d7b497ce61ad48c1ab20e8b32c87a6eaa6d7851 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.cxx @@ -26,6 +26,7 @@ TrackerByteStreamCnv::TrackerByteStreamCnv(ISvcLocator* svcloc) : Converter(storageType(), classID(), svcloc) , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "TrackerByteStreamCnv") , m_tool("TrackerDataDecoderTool") + , m_mappingTool("FaserSCT_CableMappingTool") , m_rdpSvc("FaserROBDataProviderSvc", "TrackerByteStreamCnv") , m_detStoreSvc("StoreGateSvc/DetectorStore", "TrackerByteStreamCnv") { @@ -46,6 +47,7 @@ StatusCode TrackerByteStreamCnv::initialize() CHECK(Converter::initialize()); CHECK(m_rdpSvc.retrieve()); CHECK(m_tool.retrieve()); + CHECK(m_mappingTool.retrieve()); ATH_CHECK(m_detStoreSvc.retrieve()); ATH_CHECK(m_detStoreSvc->retrieve(m_sctID, "FaserSCT_ID")); @@ -94,9 +96,12 @@ StatusCode TrackerByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObject*& p FaserSCT_RDO_Container* cont = new FaserSCT_RDO_Container(max); ATH_MSG_DEBUG("New FaserSCT_RDO_Container created of size="<<cont->size()); + auto mapping = m_mappingTool->getCableMapping(); + ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries"); + // Convert raw data into this container - CHECK( m_tool->convert(re, cont, key) ); + CHECK( m_tool->convert(re, cont, key, mapping) ); pObj = SG::asStorable(cont); diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h index 212257deffe468d416c04d1b23ed2dd60496fdc5..161bcd9740c6cb0d3c4f04e1bc03dfce7e613493 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerByteStreamCnv.h @@ -14,6 +14,7 @@ #include "AthenaBaseComps/AthMessaging.h" #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h" +#include "FaserSCT_ConditionsTools/ISCT_CableMappingTool.h" class TrackerDataDecoderTool; class IFaserROBDataProviderSvc; @@ -39,9 +40,10 @@ public: static const CLID& classID(); private: - ToolHandle<TrackerDataDecoderTool> m_tool; ServiceHandle<IFaserROBDataProviderSvc> m_rdpSvc; ServiceHandle<StoreGateSvc> m_detStoreSvc; + ToolHandle<TrackerDataDecoderTool> m_tool; + ToolHandle<ISCT_CableMappingTool> m_mappingTool; const FaserSCT_ID* m_sctID{nullptr}; }; diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx index e3c2b07fddfdc0305326f11a27def61644e1b6d0..f8ec8ce1de921bb86ae9ef704a0dce1084a33947 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.cxx @@ -45,8 +45,8 @@ TrackerDataDecoderTool::initialize() ATH_CHECK(detStore()->retrieve(m_sctID, "FaserSCT_ID")); - auto first_wafer = m_sctID->wafer_begin(); - m_trb0Station = m_sctID->station(*first_wafer); + // auto first_wafer = m_sctID->wafer_begin(); + // m_trb0Station = m_sctID->station(*first_wafer); m_sctContext = m_sctID->wafer_context(); m_phiReversed.resize(m_sctID->wafer_hash_max(), false); @@ -80,7 +80,9 @@ TrackerDataDecoderTool::finalize() StatusCode TrackerDataDecoderTool::convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* container, - std::string key) + std::string key, + const std::map<int, std::pair<int, int> >& cableMapping) + { ATH_MSG_DEBUG("TrackerDataDecoderTool::convert()"); @@ -116,10 +118,17 @@ TrackerDataDecoderTool::convert(const DAQFormats::EventFull* re, if ((frag->source_id()&0xFFFF0000) != DAQFormats::SourceIDs::TrackerSourceID) continue; ATH_MSG_DEBUG("Fragment:\n" << *frag); uint32_t trb = frag->source_id() & 0x0000FFFF; + if (cableMapping.count(trb) == 0) + { + ATH_MSG_ERROR("Invalid trb number " << trb << " not in mapping DB"); + return StatusCode::FAILURE; + } // FIXME: 1 by default; needs to be 0 for IFT - int station = m_trb0Station + trb / TrackerDataFragment::PLANES_PER_STATION; - int plane = trb % TrackerDataFragment::PLANES_PER_STATION; - + // int station = m_trb0Station + trb / TrackerDataFragment::PLANES_PER_STATION; + // int plane = trb % TrackerDataFragment::PLANES_PER_STATION; + int station = cableMapping.at(trb).first; + int plane = cableMapping.at(trb).second; + // Exceptions are a no-no in Athena/Calypso, so catch any thrown by faser-common try { diff --git a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h index 1d9507c2b6d8ca77467e2685d26ff9d459f83b9f..fbe14e215a19ecf9f009197270161c5f68ae9e87 100644 --- a/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h +++ b/Tracker/TrackerEventCnv/TrackerByteStream/src/TrackerDataDecoderTool.h @@ -31,7 +31,8 @@ class TrackerDataDecoderTool : public AthAlgTool { virtual StatusCode initialize(); virtual StatusCode finalize(); - StatusCode convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* cont, std::string key); + StatusCode convert(const DAQFormats::EventFull* re, FaserSCT_RDO_Container* cont, std::string key, + const std::map<int, std::pair<int, int> >& cableMapping); private: const FaserSCT_ID* m_sctID{nullptr}; @@ -41,8 +42,8 @@ private: "ModuleMap", {7, 2, 5, 0, 3, 6, 1, 4}, "Mapping from online to offline module numbers" }; - - Gaudi::Property<uint32_t> m_trb0Station { this, "Trb0StationNumber", 1, "Station number for TRB #0" }; + + // Gaudi::Property<uint32_t> m_trb0Station { this, "Trb0StationNumber", 1, "Station number for TRB #0" }; }; #endif /* TRACKERBYTESTREAM_TRACKERDATADECODERTOOL_H */ diff --git a/Tracker/TrackerEventCnv/TrackerEventAthenaPool/src/FaserSCT_SpacePointContainerCnv.cxx b/Tracker/TrackerEventCnv/TrackerEventAthenaPool/src/FaserSCT_SpacePointContainerCnv.cxx index 5a63749a53243fc196ac93ccab92c040359e7d4b..b1402a22ab345a28ac4c9559062a26fd16cded88 100644 --- a/Tracker/TrackerEventCnv/TrackerEventAthenaPool/src/FaserSCT_SpacePointContainerCnv.cxx +++ b/Tracker/TrackerEventCnv/TrackerEventAthenaPool/src/FaserSCT_SpacePointContainerCnv.cxx @@ -48,7 +48,7 @@ StatusCode FaserSCT_SpacePointContainerCnv::initialize() { FaserSCT_SpacePointContainer_PERS* FaserSCT_SpacePointContainerCnv::createPersistent (FaserSCT_SpacePointContainer* transObj) { - ATH_MSG_INFO("FaserSCT_SpacePointContainerCnv::createPersistent()"); + ATH_MSG_DEBUG("FaserSCT_SpacePointContainerCnv::createPersistent()"); FaserSCT_SpacePointContainerCnv_PERS converter; @@ -60,7 +60,7 @@ FaserSCT_SpacePointContainerCnv::createPersistent (FaserSCT_SpacePointContainer* FaserSCT_SpacePointContainer* FaserSCT_SpacePointContainerCnv::createTransient() { - ATH_MSG_INFO("FaserSCT_SpacePointContainerCnv::createTransient()"); + ATH_MSG_DEBUG("FaserSCT_SpacePointContainerCnv::createTransient()"); static const pool::Guid p0_guid("DB0397F9-A163-496F-BC17-C7E507A1FA50"); FaserSCT_SpacePointContainer* transObj(nullptr); diff --git a/Tracker/TrackerEventCnv/TrackerEventCnvTools/TrackerEventCnvTools/TrackerEventCnvTool.h b/Tracker/TrackerEventCnv/TrackerEventCnvTools/TrackerEventCnvTools/TrackerEventCnvTool.h index 29ef80259242bde365ddf83b6ec8bcff3ada41ac..f56577388e62f131d349f5e40a12383cf87e8b71 100644 --- a/Tracker/TrackerEventCnv/TrackerEventCnvTools/TrackerEventCnvTools/TrackerEventCnvTool.h +++ b/Tracker/TrackerEventCnv/TrackerEventCnvTools/TrackerEventCnvTools/TrackerEventCnvTool.h @@ -89,7 +89,7 @@ class TrackerEventCnvTool : public extends<AthAlgTool, Trk::ITrkEventCnvTool> // added to check TRT existence (SLHC geo check) const IdDictManager* m_idDictMgr; - SG::ReadHandleKey<FaserSCT_ClusterContainer> m_sctClusContName {this, "SCT_ClusterContainer", "SCT_Clusters", "SCT Cluster container name"}; //!< location of container of sct clusters + SG::ReadHandleKey<FaserSCT_ClusterContainer> m_sctClusContName {this, "SCT_ClusterContainer", "SCT_ClusterContainer", "SCT Cluster container name"}; //!< location of container of sct clusters SG::ReadCondHandleKey<TrackerDD::SiDetectorElementCollection> m_SCTDetEleCollKey{this, "SCTDetEleCollKey", "SCT_DetectorElementCollection", "Key of SiDetectorElementCollection for SCT"}; }; diff --git a/Tracker/TrackerEventCnv/TrackerEventCnvTools/src/TrackerEventCnvTool.cxx b/Tracker/TrackerEventCnv/TrackerEventCnvTools/src/TrackerEventCnvTool.cxx index 92d62c99790494ae1c0a2b0cb3b62753fe0386fe..1eb3b38a4270226687a0eb12b700d8be54dde0a4 100644 --- a/Tracker/TrackerEventCnv/TrackerEventCnvTools/src/TrackerEventCnvTool.cxx +++ b/Tracker/TrackerEventCnv/TrackerEventCnvTools/src/TrackerEventCnvTool.cxx @@ -27,7 +27,7 @@ Tracker::TrackerEventCnvTool::TrackerEventCnvTool(const std::string& t, const IInterface* p ) : base_class(t,n,p), - m_setPrepRawDataLink(false), + m_setPrepRawDataLink(true), m_IDHelper(nullptr), m_SCTHelper(nullptr), m_idDictMgr(nullptr) diff --git a/Tracker/TrackerEventCnv/TrackerEventTPCnv/src/FaserSCT_SpacePointCnv_p0.cxx b/Tracker/TrackerEventCnv/TrackerEventTPCnv/src/FaserSCT_SpacePointCnv_p0.cxx index b6cbc9da2508bd734634af3702165b262885ceff..6dc7c62a91fb18c44e701175173d3df82b4c02b0 100644 --- a/Tracker/TrackerEventCnv/TrackerEventTPCnv/src/FaserSCT_SpacePointCnv_p0.cxx +++ b/Tracker/TrackerEventCnv/TrackerEventTPCnv/src/FaserSCT_SpacePointCnv_p0.cxx @@ -15,7 +15,7 @@ StatusCode FaserSCT_SpacePointCnv_p0::initialize(MsgStream& log ) { // ISvcLocator* svcLocator = Gaudi::svcLocator(); // Get the messaging service, print where you are - log << MSG::INFO << "FaserSCT_SpacePointCnv::initialize()" << endmsg; + log << MSG::DEBUG << "FaserSCT_SpacePointCnv::initialize()" << endmsg; if(m_sctClusContName.initialize()!=StatusCode::SUCCESS) log << MSG::WARNING<< "FaserSCT_SpacePointCnv failed to initialize the sct cluster container" << endmsg; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.cxx b/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.cxx index a4725975ac05e81da114e34f703a482c8df7fbf5..2149bdb33ed2ef55ea57a0c1bf55b025dd69dc16 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.cxx +++ b/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.cxx @@ -2,8 +2,7 @@ Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration */ -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h" #include "FaserSiHitCollectionCnv.h" @@ -17,15 +16,24 @@ FaserSiHitCollection_PERS* FaserSiHitCollectionCnv::createPersistent(FaserSiHitC FaserSiHitCollection* FaserSiHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "FaserSiHitCollectionConverter" ); - FaserSiHitCollectionCnv_p1 converter_p1; + FaserSiHitCollectionCnv_p3 converter_p3; + FaserSiHitCollectionCnv_p3a converter_p3a; - static const pool::Guid p1_guid("FF9508DE-3E25-425D-9556-16D319DCE0E1"); + static const pool::Guid p3_guid("FF9508DE-3E25-425D-9556-16D319DCE0E1"); + static const pool::Guid p3a_guid("72FD9F51-AB1B-4DF7-B430-6CCAE0A994DB"); FaserSiHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { - std::unique_ptr< FaserSiHitCollection_p1 > col_vect( this->poolReadObject< FaserSiHitCollection_p1 >() ); - trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); - } else { + if( this->compareClassGuid(p3a_guid)) + { + std::unique_ptr< FaserSiHitCollection_p3a > col_vect( this->poolReadObject< FaserSiHitCollection_p3a >() ); + trans_cont = converter_p3a.createTransient( col_vect.get(), mlog ); + } + else if( this->compareClassGuid(p3_guid)) + { + std::unique_ptr< FaserSiHitCollection_p3 > col_vect( this->poolReadObject< FaserSiHitCollection_p3 >() ); + trans_cont = converter_p3.createTransient( col_vect.get(), mlog ); + } + else { throw std::runtime_error("Unsupported persistent version of Data container"); } return trans_cont; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.h b/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.h index 1467731fec80812428550f9c75cc3393dcf07047..47892fe8a5cd1738428aa90858c95e83d46fe232 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventAthenaPool/src/FaserSiHitCollectionCnv.h @@ -6,14 +6,16 @@ #define FASERSIHITCOLLECTIONCNV #include "TrackerSimEvent/FaserSiHitCollection.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef FaserSiHitCollection_p1 FaserSiHitCollection_PERS; -typedef FaserSiHitCollectionCnv_p1 FaserSiHitCollectionCnv_PERS; +typedef FaserSiHitCollection_p3a FaserSiHitCollection_PERS; +typedef FaserSiHitCollectionCnv_p3a FaserSiHitCollectionCnv_PERS; class FaserSiHitCollectionCnv : public T_AthenaPoolCustomCnv<FaserSiHitCollection, FaserSiHitCollection_PERS > { friend class CnvFactory<FaserSiHitCollectionCnv>; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/CMakeLists.txt b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/CMakeLists.txt index f18b094587235a28640989f322dd66b1a65d284b..7e51dca0f68d6ec72f510b641c9ab535094db6ba 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/CMakeLists.txt +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/CMakeLists.txt @@ -22,5 +22,5 @@ atlas_add_dictionary( TrackerSimEventTPCnvDict TrackerSimEventTPCnv/TrackerSimEventTPCnvDict.h TrackerSimEventTPCnv/selection.xml INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv TrackerSimEvent TestTools StoreGateLib SGtests Identifier TrackerSimEventTPCnv ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaPoolCnvSvcLib GaudiKernel GeneratorObjectsTPCnv TrackerSimEvent TestTools StoreGateLib SGtests Identifier TrackerSimEventTPCnv AthenaKernel ) diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p1.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p2.h similarity index 60% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p1.h rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p2.h index 3a4bec3cdaca91575a51d5589310e9b89306c395..791df726101c1e4178b3d9ceb1248174a91b7fd0 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p1.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p2.h @@ -2,30 +2,30 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -#ifndef FASERSIHITCNV_P1_H -#define FASERSIHITCNV_P1_H +#ifndef FASERSIHITCNV_P2_H +#define FASERSIHITCNV_P2_H /* Transient/Persistent converter for FaserSiHit class */ #include "TrackerSimEvent/FaserSiHit.h" -#include "FaserSiHit_p1.h" +#include "FaserSiHit_p2.h" #include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" class MsgStream; -class FaserSiHitCnv_p1 : public T_AthenaPoolTPCnvBase<FaserSiHit, FaserSiHit_p1> +class FaserSiHitCnv_p2 : public T_AthenaPoolTPCnvBase<FaserSiHit, FaserSiHit_p2> { public: - FaserSiHitCnv_p1() {} + FaserSiHitCnv_p2() {} - virtual void persToTrans(const FaserSiHit_p1* persObj, FaserSiHit* + virtual void persToTrans(const FaserSiHit_p2* persObj, FaserSiHit* transObj, MsgStream &log); - virtual void transToPers(const FaserSiHit* transObj, FaserSiHit_p1* + virtual void transToPers(const FaserSiHit* transObj, FaserSiHit_p2* persObj, MsgStream &log); }; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h similarity index 61% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h index 488221edc81c645ae56e453a2cafb18195f1242d..3f2eb8610682ccf021f0c57904dd9487d35e559e 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h @@ -2,31 +2,31 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -#ifndef FASERSIHITCOLLECTIONCNV_P1_H -#define FASERSIHITCOLLECTIONCNV_P1_H +#ifndef FASERSIHITCOLLECTIONCNV_P3_H +#define FASERSIHITCOLLECTIONCNV_P3_H -// FaserSiHitCollectionCnv_p1, T/P separation of FaserSi Hits +// FaserSiHitCollectionCnv_p3, T/P separation of FaserSi Hits // author D.Costanzo <davide.costanzo@cern.ch> // author O.Arnaez <olivier.arnaez@cern.ch> #include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" #include "TrackerSimEvent/FaserSiHitCollection.h" -#include "FaserSiHitCollection_p1.h" +#include "FaserSiHitCollection_p3.h" -class FaserSiHitCollectionCnv_p1 : public T_AthenaPoolTPCnvBase<FaserSiHitCollection, FaserSiHitCollection_p1> +class FaserSiHitCollectionCnv_p3 : public T_AthenaPoolTPCnvBase<FaserSiHitCollection, FaserSiHitCollection_p3> { public: - FaserSiHitCollectionCnv_p1() {}; + FaserSiHitCollectionCnv_p3() {}; - virtual FaserSiHitCollection* createTransient(const FaserSiHitCollection_p1* persObj, MsgStream &log); + virtual FaserSiHitCollection* createTransient(const FaserSiHitCollection_p3* persObj, MsgStream &log); - virtual void persToTrans(const FaserSiHitCollection_p1* persCont, + virtual void persToTrans(const FaserSiHitCollection_p3* persCont, FaserSiHitCollection* transCont, MsgStream &log) ; virtual void transToPers(const FaserSiHitCollection* transCont, - FaserSiHitCollection_p1* persCont, + FaserSiHitCollection_p3* persCont, MsgStream &log) ; private: diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h new file mode 100644 index 0000000000000000000000000000000000000000..8f453cf57ab52efb41fbe739d6543d75ba77c72a --- /dev/null +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef FASERSIHITCOLLECTIONCNV_P3A_H +#define FASERSIHITCOLLECTIONCNV_P3A_H + +// FaserSiHitCollectionCnv_p3, T/P separation of FaserSi Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "FaserSiHitCollection_p3a.h" + + +class FaserSiHitCollectionCnv_p3a : public T_AthenaPoolTPCnvBase<FaserSiHitCollection, FaserSiHitCollection_p3a> +{ + public: + + FaserSiHitCollectionCnv_p3a() {}; + + virtual FaserSiHitCollection* createTransient(const FaserSiHitCollection_p3a* persObj, MsgStream &log); + + virtual void persToTrans(const FaserSiHitCollection_p3a* persCont, + FaserSiHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const FaserSiHitCollection* transCont, + FaserSiHitCollection_p3a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h similarity index 88% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h index fa4018a016b99d2bc7baf9e46a8711fa6278e787..b07b2e3810eaed573449bd4c389befee571bea7f 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h @@ -2,8 +2,8 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -#ifndef FASERSIHITCOLLECTION_P1_H -#define FASERSIHITCOLLECTION_P1_H +#ifndef FASERSIHITCOLLECTION_P3_H +#define FASERSIHITCOLLECTION_P3_H /* @@ -14,11 +14,11 @@ Authors: Davide Costanzo Rob Duxfield #include <vector> #include <string> -class FaserSiHitCollection_p1 +class FaserSiHitCollection_p3 { public: /// Default constructor - FaserSiHitCollection_p1 (); + FaserSiHitCollection_p3 (); //private: std::vector<float> m_hit1_meanTime; // 1 element per string @@ -52,6 +52,6 @@ class FaserSiHitCollection_p1 // inlines inline -FaserSiHitCollection_p1::FaserSiHitCollection_p1 () {} +FaserSiHitCollection_p3::FaserSiHitCollection_p3 () {} #endif diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h new file mode 100644 index 0000000000000000000000000000000000000000..137ebd68b84c0ea6e6643132023d90c49b23df0f --- /dev/null +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef FASERSIHITCOLLECTION_P3A_H +#define FASERSIHITCOLLECTION_P3A_H + +/* + +Authors: Davide Costanzo Rob Duxfield + +*/ + +#include <vector> +#include <string> + +class FaserSiHitCollection_p3a +{ + public: +/// Default constructor + FaserSiHitCollection_p3a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned long> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +FaserSiHitCollection_p3a::FaserSiHitCollection_p3a () {} + +#endif diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p2.h similarity index 83% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p2.h index 159caf56dd047bd4d7d7fa505b3076dd96b07534..fa8e50a85a8fceafa20e4dbed50f60c052510d0e 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p2.h @@ -2,12 +2,12 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -#ifndef FASERSIHIT_P1_H -#define FASERSIHIT_P1_H +#ifndef FASERSIHIT_P2_H +#define FASERSIHIT_P2_H #include "GeneratorObjectsTPCnv/HepMcParticleLink_p2.h" -class FaserSiHit_p1 { +class FaserSiHit_p2 { public: float m_stX, m_stY, m_stZ; float m_enX, m_enY, m_enZ; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnvDict.h b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnvDict.h index 6146be90a917d1eaf49b9a7c9996f5cc4eb66262..a898e3095bee7e4b25d2090b0e7365cbdcc4d00e 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnvDict.h +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnvDict.h @@ -7,14 +7,16 @@ //----------------------------------------------------------------------------- // -// file: TrackerSimEventTPCnvDict_p1.h +// file: TrackerSimEventTPCnvDict.h // //----------------------------------------------------------------------------- -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p2.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p2.h" #endif // TRACKERSIMEVENTTPCNV_TRACKERSIMEVENTTPCNVDICT_H diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/selection.xml b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/selection.xml index 72a04265e6367e090af8a543dd0a550d4e948af5..6b34f88fcb38eb134efb2a283ac6635860a76928 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/selection.xml +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/TrackerSimEventTPCnv/selection.xml @@ -1,6 +1,7 @@ <lcgdict> <!-- FaserSiHits --> - <class name="FaserSiHit_p1" /> - <class name="std::vector<FaserSiHit_p1>" /> - <class name="FaserSiHitCollection_p1" id="FF9508DE-3E25-425D-9556-16D319DCE0E1" /> + <class name="FaserSiHit_p2" /> + <class name="std::vector<FaserSiHit_p2>" /> + <class name="FaserSiHitCollection_p3" id="FF9508DE-3E25-425D-9556-16D319DCE0E1" /> + <class name="FaserSiHitCollection_p3a" id="72FD9F51-AB1B-4DF7-B430-6CCAE0A994DB" /> </lcgdict> diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p1.cxx b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p2.cxx similarity index 85% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p1.cxx rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p2.cxx index a6e9c320e1118143f505e4f3ad3f7234a3afd498..5dde908345fee67f41b4f7f5c4b71407d25c926e 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p1.cxx +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCnv_p2.cxx @@ -6,12 +6,12 @@ #include "Identifier/Identifier.h" #include "GeneratorObjectsTPCnv/HepMcParticleLinkCnv_p2.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p1.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHit_p2.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCnv_p2.h" void -FaserSiHitCnv_p1::persToTrans(const FaserSiHit_p1* persObj, FaserSiHit* transObj, MsgStream &log) +FaserSiHitCnv_p2::persToTrans(const FaserSiHit_p2* persObj, FaserSiHit* transObj, MsgStream &log) { HepMcParticleLinkCnv_p2 HepMcPLCnv; HepMcParticleLink link; @@ -32,7 +32,7 @@ FaserSiHitCnv_p1::persToTrans(const FaserSiHit_p1* persObj, FaserSiHit* transObj void -FaserSiHitCnv_p1::transToPers(const FaserSiHit* transObj, FaserSiHit_p1* persObj, MsgStream &log) +FaserSiHitCnv_p2::transToPers(const FaserSiHit* transObj, FaserSiHit_p2* persObj, MsgStream &log) { // if (log.level() <= MSG::DEBUG) log << MSG::DEBUG << "FaserSiHitCnv_p1::transToPers called " << endmsg; HepMcParticleLinkCnv_p2 HepMcPLCnv; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p1.cxx b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3.cxx similarity index 82% rename from Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p1.cxx rename to Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3.cxx index c31eed267329943e8a0627881057281bcb7248df..ee4b293a83af7fbb970f12a48d63ce67285e476d 100644 --- a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p1.cxx +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3.cxx @@ -4,8 +4,8 @@ #include "TrackerSimEvent/FaserSiHit.h" #include "TrackerSimEvent/FaserSiHitCollection.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p1.h" -#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p1.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3.h" #include "GeneratorObjects/HepMcParticleLink.h" #include <cmath> @@ -14,8 +14,12 @@ #include "CLHEP/Geometry/Point3D.h" // Gaudi #include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + // Athena #include "StoreGate/StoreGateSvc.h" +#include "AthenaKernel/ExtendedEventContext.h" + // * * * stolen from eflowRec * * * // inline double phicorr(double a) @@ -53,14 +57,14 @@ inline double cycle(double a, double b) } -const double FaserSiHitCollectionCnv_p1::m_persEneUnit = 1.0e-5; -const double FaserSiHitCollectionCnv_p1::m_persLenUnit = 1.0e-5; -const double FaserSiHitCollectionCnv_p1::m_persAngUnit = 1.0e-5; -const double FaserSiHitCollectionCnv_p1::m_2bHalfMaximum = pow(2.0, 15.0); -const int FaserSiHitCollectionCnv_p1::m_2bMaximum = (unsigned short)(-1); +const double FaserSiHitCollectionCnv_p3::m_persEneUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3::m_persLenUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3::m_persAngUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3::m_2bHalfMaximum = pow(2.0, 15.0); +const int FaserSiHitCollectionCnv_p3::m_2bMaximum = (unsigned short)(-1); -void FaserSiHitCollectionCnv_p1::transToPers(const FaserSiHitCollection* transCont, FaserSiHitCollection_p1* persCont, MsgStream &/*log*/) +void FaserSiHitCollectionCnv_p3::transToPers(const FaserSiHitCollection* transCont, FaserSiHitCollection_p3* persCont, MsgStream &log) { // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and // persistifies the end point of each hit plus the start point of the first hit in each string. @@ -77,6 +81,8 @@ void FaserSiHitCollectionCnv_p1::transToPers(const FaserSiHitCollection* transCo static const double dRcut = 1.0e-7; static const double dTcut = 1.0; + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); const HepMcParticleLink * lastLink=nullptr; int lastId = -1; double stringFirstTheta = 0.0; @@ -98,11 +104,22 @@ void FaserSiHitCollectionCnv_p1::transToPers(const FaserSiHitCollection* transCo if ( !lastLink || (siHit->particleLink() != *lastLink) ) { - // store barcode once for set of consecutive hits with same barcode + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode lastLink = &(siHit->particleLink()); persCont->m_barcode.push_back(lastLink->barcode()); - persCont->m_mcEvtIndex.push_back(lastLink->eventIndex()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); if (idx > 0) { @@ -241,15 +258,17 @@ void FaserSiHitCollectionCnv_p1::transToPers(const FaserSiHitCollection* transCo } -FaserSiHitCollection* FaserSiHitCollectionCnv_p1::createTransient(const FaserSiHitCollection_p1* persObj, MsgStream &log) { +FaserSiHitCollection* FaserSiHitCollectionCnv_p3::createTransient(const FaserSiHitCollection_p3* persObj, MsgStream &log) { std::unique_ptr<FaserSiHitCollection> trans(std::make_unique<FaserSiHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); persToTrans(persObj, trans.get(), log); return(trans.release()); } -void FaserSiHitCollectionCnv_p1::persToTrans(const FaserSiHitCollection_p1* persCont, FaserSiHitCollection* transCont, MsgStream &/*log*/) +void FaserSiHitCollectionCnv_p3::persToTrans(const FaserSiHitCollection_p3* persCont, FaserSiHitCollection* transCont, MsgStream &/*log*/) { + const EventContext& ctx = Gaudi::Hive::currentContext(); + unsigned int hitCount = 0; unsigned int angleCount = 0; unsigned int idxBC = 0; @@ -299,7 +318,11 @@ void FaserSiHitCollectionCnv_p1::persToTrans(const FaserSiHitCollection_p1* pers HepGeom::Point3D<double> endThis( endLast + r ); - HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), HepMcParticleLink::IS_INDEX ); + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); endLast = endThis; diff --git a/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3a.cxx b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3a.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0aebca47dc6ae6eb0d6662d4a2b4abe1a52dc1ae --- /dev/null +++ b/Tracker/TrackerEventCnv/TrackerSimEventTPCnv/src/TrackerHits/FaserSiHitCollectionCnv_p3a.cxx @@ -0,0 +1,351 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TrackerSimEvent/FaserSiHit.h" +#include "TrackerSimEvent/FaserSiHitCollection.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollection_p3a.h" +#include "TrackerSimEventTPCnv/TrackerHits/FaserSiHitCollectionCnv_p3a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "StoreGate/StoreGateSvc.h" +#include "AthenaKernel/ExtendedEventContext.h" + + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double FaserSiHitCollectionCnv_p3a::m_persEneUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3a::m_persLenUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3a::m_persAngUnit = 1.0e-5; +const double FaserSiHitCollectionCnv_p3a::m_2bHalfMaximum = pow(2.0, 15.0); +const int FaserSiHitCollectionCnv_p3a::m_2bMaximum = (unsigned short)(-1); + + +void FaserSiHitCollectionCnv_p3a::transToPers(const FaserSiHitCollection* transCont, FaserSiHitCollection_p3a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (FaserSiHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + FaserSiHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + // log << MSG::ALWAYS << "TP: Event collection from link: " << lastLink->getEventCollection() << " ; char value: " << lastLink->getEventCollectionAsChar() << " barcode: " << lastLink->barcode() << endmsg; + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store id once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); + + // log << MSG::ALWAYS << "nBC: " << persCont->m_nBC << endmsg; + // log << MSG::ALWAYS << "nId: " << persCont->m_nId << endmsg; + // log << MSG::ALWAYS << "nHits:" << persCont->m_nHits << endmsg; + +} + + +FaserSiHitCollection* FaserSiHitCollectionCnv_p3a::createTransient(const FaserSiHitCollection_p3a* persObj, MsgStream &log) { + // for (size_t i = 0; i < persObj->m_evtColl.size(); i++) + // { + // if (persObj->m_evtColl[i] != 'a') + // log << MSG::ALWAYS << "Corrupted in createTransient: " << persObj->m_evtColl[i] << endmsg; + // } + std::unique_ptr<FaserSiHitCollection> trans(std::make_unique<FaserSiHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void FaserSiHitCollectionCnv_p3a::persToTrans(const FaserSiHitCollection_p3a* persCont, FaserSiHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + // log << MSG::ALWAYS << "nHits.size(): " << persCont->m_nHits.size() << " nBC.size(): " << persCont->m_nBC.size() << endmsg; + // log << MSG::ALWAYS << " nBC: " << persCont->m_nBC << endmsg; + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + if (persCont->m_nHits[i]) { + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + // log << MSG::ALWAYS << "i: " << i << " persCont->m_nHits[i]: " << persCont->m_nHits[i] << " start: " << start << " endHit: " << endHit << endmsg; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + // log << MSG::ALWAYS << "PT: Event collection from persCont: " << persCont->m_evtColl[idxBC] << " ; idxBC: " << idxBC << " evtColl.size(): " << persCont->m_evtColl.size() << " evtIndex.size(): " << persCont->m_mcEvtIndex.size() << endmsg; + + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } + // log << MSG::ALWAYS << "hitCount: " << hitCount << endmsg; +} diff --git a/Tracker/TrackerG4/FaserSCT_G4_SD/python/FaserSCT_G4_SDToolConfig.py b/Tracker/TrackerG4/FaserSCT_G4_SD/python/FaserSCT_G4_SDToolConfig.py index eb4fb53749d2a8e01bfd52992421322e91115cbd..1e4fa355daf2e1a9c381b80aa5a2ad8002dbc881 100644 --- a/Tracker/TrackerG4/FaserSCT_G4_SD/python/FaserSCT_G4_SDToolConfig.py +++ b/Tracker/TrackerG4/FaserSCT_G4_SD/python/FaserSCT_G4_SDToolConfig.py @@ -18,5 +18,7 @@ def SctSensorSDCfg(ConfigFlags, name="SctSensorSD", **kwargs): kwargs.setdefault("LogicalVolumeNames", ["SCT::BRLSensor"]) kwargs.setdefault("OutputCollectionNames", [bare_collection_name]) - # result.merge(acc) - return result, FaserSctSensorSDTool(name, **kwargs) + result = ComponentAccumulator() + result.setPrivateTools(CompFactory.FaserSctSensorSDTool(name, **kwargs)) + return result + 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/CMakeLists.txt b/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt index 29e80551e078ae78985801f204169932da2dcb94..5a85e55131b3ef638671c33f5ec3f742bf48203d 100644 --- a/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/CMakeLists.txt @@ -17,5 +17,5 @@ atlas_add_component( NoisyStripFinder atlas_install_python_modules( python/*.py ) -#atlas_install_scripts( test/*.py ) +atlas_install_scripts( share/*.py share/*.sh ) diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/README.md b/Tracker/TrackerRecAlgs/NoisyStripFinder/README.md new file mode 100644 index 0000000000000000000000000000000000000000..407b1d255379dd7d6ecf2b3c9ae5f9e016a1192b --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/README.md @@ -0,0 +1,72 @@ +Noisy strips are now part of the conditions database and are used in default reco + +To update the database, the following steps should be used. + +1) Determine the runs to update. +A handy utility to find all runs of a given type is findFaserRunsByType.py: + +`findFaserRunsByType.py -t Physics -o physics_runs.txt 7730-8370` + +2) Submit jobs to create the noisy strip DB for each run +From a release directory, best to create a subdirectory for this and then: + +`submitNoisyStripJobs.py --release .. physics_runs.txt` + +Can also just specify run numbers (or a range) instead of a text file of runs + +If you want to do this interactively, this script submits jobs to run the following: +`NoisyStripFinderJob.py` +`makeNoisyStripDB.py` + +3) Check that all of the jobs finished successfully (or can check individual runs) + +`checkNoisyStripJobs.py physics_runs.txt` + +This can also write out a file of runs to submit again + +4) Check that the actual noisy strips found make sense +This reads the individual DB files in each subdirectory, can also specify specific runs + +`checkNoisyStripDB.py physics_runs.txt` + +5) Merge the individual runs into a single DB +Note this script writes the individual runs with open-ended IOVs. +This means the last run merged will be used for all later data until the DB is updated again. +So if you are merging multiple times (with the --append option), it is important to do ths in chronological order. + +`mergeNoisyStripDB.py physics_runs.txt` + +Note, this can be slow. Use --verbose to watch the progress. + +6) Test the database +The resulting database by default has the name noisy_strips.db. +This can be copied to the data/sqlite200 subdirectory of the working directory and reco jobs will use this. +Check here for details: +https://gitlab.cern.ch/faser/calypso/-/blob/master/Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml + +7) Merge with production DB +This updated noisy strips folder /SCT/DAQ/NoisyStrips now needs to be merged into the production DB. +First copy the current DB from CVMFS to some local directory. + +`cp /cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/sqlite200/ALLP200.db .` + +Next, use AtlCoolCopy to merge the updates into this file: + +`AtlCoolCopy "sqlite://;schema=noisy_strips.db;dbname=CONDBR3" "sqlite://;schema=ALLP200.db;dbname=CONDBR3" ` + +This can also be slow. + +Finally, the ALLP200.db file should be installed on cvmfs once everything is verified to be correct. + +Older instructions from Tobias when he was developing this package are here: + +Mask noisy strips: + +1) Run the NoisyStripFinderDbg.py on raw data files + +2) Run makeNoisyStripDB.py on the NoisyStripFinderHist.root produced by the NoisyStripFinderDbg.py script + +3) Edit the path for the COOLOFL_INDET database in Database/ConnectionManagement/FaserAuthentication/data/dblookup.xml to point to the noisy_strips.db produced by the makeNoisyStripDB.py script + +4) Set the checkBadChannels flag to True for the FaserSCT_ClusterizationCfg, e.g. like this + acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, checkBadChannels=True, DataObjectName="SCT_EDGEMODE_RDOs", ClusterToolTimingPattern="01X")) 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/share/NoisyStripFinderHist_Analysis.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py old mode 100644 new mode 100755 index 349316b31446434c1ad41f58ba2c269e4ce0a93a..f882e8f303929f4cf34858b852698308aa2ae993 --- a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderHist_Analysis.py @@ -71,7 +71,7 @@ for dictkey in HistDict: sensorhash.text = dictkey bini = 1 while bini <= 768: - if HistDict[dictkey].GetBinContent(bini) >= 0.1 : + if HistDict[dictkey].GetBinContent(bini) >= 0.01: strip = ET.SubElement(sensorhash, "Strip") strip.text = str(bini - 1) # strip number is offset by histogram bin number by 1 because of underflow bin occupancy = ET.SubElement(strip, "Occupancy") diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py new file mode 100755 index 0000000000000000000000000000000000000000..b6dc5c514d05c558310bf1108e505deca1e8098c --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/NoisyStripFinderJob.py @@ -0,0 +1,80 @@ +#!/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 +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("file", nargs="+", help="full path to input file") +parser.add_argument("--nevents", "-n", default=-1, type=int, help="Number of events to process") +parser.add_argument("--outfile", "-o", default="NoisyStripFinderHist.root", help="Specify output file") + +parser.add_argument("--verbose", "-v", action="store_true", help="Debug output") +args = parser.parse_args() + +if args.verbose: + log.setLevel(DEBUG) +else: + log.setLevel(INFO) + +Configurable.configurableRun3Behavior = True + +# +filelist = [] +for filename in args.file: + if filename[:22] == "/eos/experiment/faser/": + filelist.append(f"root://eospublic.cern.ch/{filename}") + else: + filelist.append(filename) + +ConfigFlags.Input.Files = args.file +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +#ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.IOVDb.DatabaseInstance = "CONDBR3" +ConfigFlags.Input.ProjectName = "data22" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" +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, OccupancyCut=-1)) +acc.merge(NoisyStripFinderCfg(ConfigFlags, OutputHistRootName=args.outfile)) + +# 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 + +# Don't print out every event +from AthenaConfiguration.ComponentFactory import CompFactory +eventLoop = CompFactory.AthenaEventLoopMgr() +eventLoop.EventPrintoutInterval = 1000 +acc.addService(eventLoop) + +if args.verbose: + acc.foreach_component("*").OutputLevel = VERBOSE + acc.printConfig() +else: + acc.foreach_component("*").OutputLevel = INFO + +sc = acc.run(maxEvents=args.nevents) +print(f"Job finished with {sc.isSuccess()} => {not sc.isSuccess()}") +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripDB.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripDB.py new file mode 100755 index 0000000000000000000000000000000000000000..486304cd78da213562c6e98c96efa5aefb8b5793 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripDB.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +# +# Sept 2022, E. Torrence +# +# Script to merge individual run DBs into a master DB +# +# Usage: +# ./mergeNoisyDBRuns.py -h +# +import sys +import argparse +import subprocess + +from pathlib import Path + +from PyCool import cool +from CoolConvUtilities.AtlCoolLib import indirectOpen + +def parse_arguments(): + + description="Script to merge DBs from individual runs into one DB\n" + parser = argparse.ArgumentParser(description, + formatter_class=argparse.RawTextHelpFormatter) + + + parser.add_argument("runs", nargs='+', help="Specify FASER runs or range") + parser.add_argument("--threshold", default="0.01", help="Threshold to calls trip noisy (0.01)") + parser.add_argument("-v", "--verbose", action="store_true", help="Debugging output") + return parser.parse_args() + +# Take a string and turn it into a list of integers +# Can specify single values, ranges, or comma separated lists of both +def parseRunList(runlist): + + run_list = [] + + # Check if this is a file with run numbers + if len(runlist) == 1: + path = Path(runlist[0]) + if path.exists() and path.is_file(): + print(f"Reading runs from {path}") + # Try reading each line as a run number + with path.open() as f: + for line in f.readlines(): + line = line.strip() + if len(line) == 0: continue + if line[0] in ['#', '!']: continue + if not line.isnumeric(): + print(f"Error parsing {line}") + continue + run_list.append(int(line)) + # Done reading file + return(run_list) + elif '-' in runlist[0]: + pass + elif ',' in runlist[0]: + pass + elif not runlist[0].isnumeric(): + print(f"File {path} doesn't exist!") + return run_list + + for string in runlist: + tokens = string.split(',') + + for segment in tokens: + + if len(segment) == 0: continue + + if '-' in segment: # Range of runs + start, end = segment.split('-') + if not start.isnumeric(): + print(f"Found invalid run {start}") + continue + if not end.isnumeric(): + print(f"Found invalid run {end}") + continue + start = int(start) + end = int(end) + run_list.extend(list(range(int(start), int(end)+1))) + + else: + if not segment.isnumeric(): + print(f"Found invalid run {segment}") + continue + run_list.append(int(segment)) + + return(run_list) + +class NoisyRunAnalyzer: + + def __init__(self, verbose=False, threshold=0.01): + self.verbose = verbose + + self.run_dict = {} + self.noise_threshold = threshold + + def addRun(self, runnum): + + if self.verbose: print(f"\nRun {runnum}") + + runstr = f'{runnum:06d}' + infile = Path(f'{runstr}/noisy_{runstr}.db') + if not infile.is_file(): + print(f"{runstr}/noisy_{runstr}.db doesn't exist!") + return + + db_string = f'sqlite://;schema={runstr}/noisy_{runstr}.db;dbname=CONDBR3' + try: + self.db = indirectOpen(db_string, readOnly=True, oracle=False, debug=False) + except Exception as e: + print(e) + return + + # Now read all channels + folder_string = "/SCT/DAQ/NoisyStrips" + try: + self.folder = self.db.getFolder(folder_string) + except Exception as e: + print(e) + return + + if self.folder is None: + print(f"Can't access folder {folder_string} in {db_string}") + return + + channels = cool.ChannelSelection.all() + iov_lo = (runnum<<32) + iov_hi = ((runnum+1)<<32) - 1 + tag = '' + + try: + itr = self.folder.browseObjects(iov_lo, iov_hi, channels, tag) + except Exception as e: + print(e) + return + + rd = self.run_dict.get(runnum, None) + if rd is None: + self.run_dict[runnum] = {} + + # Now iterate through objects (should only be one IOV, but multiple channels) + while itr.goToNext(): + obj = itr.currentRef() + if self.verbose: print(obj.payload()) + + sensor = obj.payload()['sensor'] + nstrips = obj.payload()['nstrips'] + + # Skip if this sensor has no noisy strips + if nstrips == 0: continue + + sensor_dict = self.run_dict[runnum].get(sensor, None) + if sensor_dict is None: + self.run_dict[runnum][sensor] = {} + + # Now need to parse the noisy strip string + noisyList = obj.payload()['noisyList'] + + for item in noisyList.strip().split(): + + strip = int(item.split(':')[0]) + occupancy = float(item.split(':')[1]) + + if occupancy < self.noise_threshold: continue + + strip_dict = self.run_dict[runnum][sensor].get(strip, None) + if strip_dict is None: + self.run_dict[runnum][sensor][strip] = {} + + self.run_dict[runnum][sensor][strip] = occupancy + + # Done looping over strips + + # Done looping over objects + if self.verbose: print(self.run_dict) + + # Done, close the database + self.db.closeDatabase() + + def printRunSummary(self): + + for run in self.run_dict: + + #print(f"Run {run}: {len(self.run_dict[run])} sensors with noisy strips") + + noisy_by_layer = [0] * 12 + noisy_strips_by_layer = [0] * 12 + + for sensor in self.run_dict[run]: + layer = sensor // 16 + noisy_by_layer[layer] += 1 + noisy_strips_by_layer[layer] += len(self.run_dict[run][sensor]) + + #print(f"Sensors by layer: ", end='') + #[ print(f' {n:3d}', end='') for n in noisy_by_layer] + #print() + + print(f"Run {run} strips > {100*self.noise_threshold:3.1f}% by layer: ", end='') + [ print(f' {n:3d}', end='') for n in noisy_strips_by_layer] + print() + + +# Command-line execution +if __name__ == "__main__": + + # Parse the command-line arguments + args = parse_arguments() + + run_list = parseRunList(args.runs) + run_list.sort() + + nra = NoisyRunAnalyzer(verbose=args.verbose, threshold=float(args.threshold)) + + for runnum in run_list: + nra.addRun(runnum) + + nra.printRunSummary() + diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripHist.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripHist.py new file mode 100755 index 0000000000000000000000000000000000000000..0ace2cb64ed224633bc5cf16ac81046384a5b3c2 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripHist.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# +# Simple utility to run as a post script +# after the noisyStripFinder +# +# Usage: checkNoisyStripHist.py <histfile> [return code] +# +import sys +if len(sys.argv) <= 1: + sys.exit(1) +filename = sys.argv[1] +# +# Check previous return code if it is provided +if len(sys.argv) >= 3: + rc = int(sys.argv[2]) + if rc: sys.exit(rc) +# +# Check histogram entries +# This causes a segfault. Lets try without ROOT +#from ROOT import TFile +if False: + import ROOT + try: + f = ROOT.TFile.Open(filename, 'r') + except Exception as e: + print(e) + sys.exit(1) + else: + n = f.Get("numEvents").GetVal() + print(f"Found {filename} with {n} entries") + sys.exit(n==0) + +from pathlib import Path +f = Path(filename) +if not f.is_file(): sys.exit(1) + +size = f.stat().st_size + +if size < 1000: # Almost certainly empty + print(f"Found {f} with size {size}!") + sys.exit(1) + +sys.exit(0) diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripJobs.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripJobs.py new file mode 100755 index 0000000000000000000000000000000000000000..937c7e21d5a39812279ffdfb481025e78738dc20 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/checkNoisyStripJobs.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +# +# Sept 2022, E. Torrence +# +# Script to check NoisyStrips jobs for problems +# +# Usage: +# ./checkNoisyJobs.py -h +# +import sys +import argparse +from pathlib import Path + +import ROOT + +def parse_arguments(): + + description="Script to check noisy strip finding jobs\n" + parser = argparse.ArgumentParser(description, + formatter_class=argparse.RawTextHelpFormatter) + + + parser.add_argument("runs", nargs='+', help="Specify FASER runs or range") + + parser.add_argument("-v", "--verbose", action="store_true", help="Debugging output") + parser.add_argument("--write_missing", action="store_true", help="Write out missing runs to file") + + return parser.parse_args() + +# Take a string and turn it into a list of integers +# Can specify single values, ranges, or comma separated lists of both +def parseRunList(runlist): + + run_list = [] + + # Check if this is a file with run numbers + if len(runlist) == 1: + path = Path(runlist[0]) + if path.exists() and path.is_file(): + print(f"Reading runs from {path}") + # Try reading each line as a run number + with path.open() as f: + for line in f.readlines(): + line = line.strip() + if len(line) == 0: continue + if line[0] in ['#', '!']: continue + if not line.isnumeric(): + print(f"Error parsing {line}") + continue + run_list.append(int(line)) + # Done reading file + return(run_list) + elif '-' in runlist[0]: + pass + elif ',' in runlist[0]: + pass + elif not runlist[0].isnumeric(): + print(f"File {path} doesn't exist!") + return run_list + + for string in runlist: + tokens = string.split(',') + + for segment in tokens: + + if len(segment) == 0: continue + + if '-' in segment: # Range of runs + start, end = segment.split('-') + if not start.isnumeric(): + print(f"Found invalid run {start}") + continue + if not end.isnumeric(): + print(f"Found invalid run {end}") + continue + start = int(start) + end = int(end) + run_list.extend(list(range(int(start), int(end)+1))) + + else: + if not segment.isnumeric(): + print(f"Found invalid run {segment}") + continue + run_list.append(int(segment)) + + return(run_list) + +class JobChecker: + + def __init__(self, run=None): + self.select_run(run) + + self.verbose = True + self.check_all = False + + self.check_function_list = [] + self.check_function_list.append(self.check_directory) + self.check_function_list.append(self.check_histograms) + self.check_function_list.append(self.check_dbfile) + + def select_run(self, run): + self.run_number = run + if run is None: return + self.run_string = f'{run:06d}' + + def check_run(self, run=None): + # Return true on error + + if run is not None: + self.select_run(run) + + if run is None: + print("No run specified!") + return True + + for func in self.check_function_list: + if func(): return True + + return False + + def check_directory(self): + + directory_path = Path(self.run_string) + if not directory_path.exists(): + print(f"* Directory {self.run_string} not found!") + elif self.verbose: + print(f" => Directory {self.run_string} found") + return( not directory_path.exists() ) + + def check_dbfile(self): + + dbfile_path = Path(f'{self.run_string}/noisy_{self.run_string}.db') + if not dbfile_path.exists(): + print(f"* Database file {dbfile_path} not found!") + elif self.verbose: + print(f" => Database file {dbfile_path} found") + return( not dbfile_path.exists() ) + + def check_histograms(self): + + # First, find the submit files + directory_path = Path(self.run_string) + + submit_list = directory_path.glob('noise*.sub') + + missing = False + + for filepath in submit_list: + + # Ignore DAG + if '.dag.' in str(filepath): continue + + filestem = filepath.stem + hist_file = directory_path / Path(f'{filestem}.root') + if hist_file.exists(): + if self.verbose: print(f" => Found histogram file {hist_file}") + + # Check number of events? + try: + f = ROOT.TFile.Open(str(hist_file), 'r') + except Exception as e: + print(e) + missing = True + else: + n = f.Get("numEvents").GetVal() + if self.verbose: + print(f"{hist_file} found with {n} entries") + if n == 0: + print(f"{hist_file} found with {n} entries") + missing = True + + continue + + # Histogram doesn't exist + missing = True + print(f"* Histogram file {hist_file} missing! ", end="") + + # See if we can figure out why + logfile_path = directory_path / Path(f'{filestem}.log') + if not logfile_path.exists(): + print("=> log file not found") + continue + + import subprocess + if subprocess.call(['/bin/grep', "Killed", f"{logfile_path}"], + stdout=subprocess.DEVNULL): + # True means no match + pass + + else: + # False means match + # See if we can find the time + rc = subprocess.run(['/bin/grep', 'Job finished after', f"{logfile_path}"], + stdout=subprocess.PIPE, + universal_newlines=True) + + if rc.returncode: + # Can't find running time + print("=> job appears to have been killed") + else: + timestr = rc.stdout.replace('Job finished after ', '') + print(f"=> job appears to have been killed after {timestr}") + continue + + # Can't figure out why + print('=> unknown problem') + + return missing + +# Command-line execution +if __name__ == "__main__": + + # Parse the command-line arguments + args = parse_arguments() + + run_list = parseRunList(args.runs) + run_list.sort() + + good_runs = [] + missing_runs = [] + + jc = JobChecker() + jc.verbose = args.verbose + + for runnum in run_list: + + if args.verbose: print(f"\nRun {runnum}") + + if jc.check_run(runnum): + missing_runs.append(runnum) + else: + good_runs.append(runnum) + + print(f"Found {len(good_runs)} good runs and {len(missing_runs)} missing runs") + if args.write_missing: + missing_file="missing_runs.txt" + with open(missing_file, "w") as f: + [f.write(f"{run}\n") for run in missing_runs] + print(f"Wrote {len(missing_runs)} missing runs to {missing_file}") diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/findFaserRunsByType.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/findFaserRunsByType.py new file mode 100755 index 0000000000000000000000000000000000000000..5a6809ea3556f4bd5d56fc492ae615941b631372 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/findFaserRunsByType.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Sept 2022, E. Torrence +# +# Script to find FASER runs taken in Physics +# +# Usage: +# ./findRuns.py -h +# +import json +import argparse +import requests + +from pathlib import Path + +def parse_arguments(): + + description="Script to find PHYSICS runs in a range\n" + parser = argparse.ArgumentParser(description, + formatter_class=argparse.RawTextHelpFormatter) + + + parser.add_argument("runs", nargs='+', help="Specify FASER runs or range") + + parser.add_argument("-v", "--verbose", action="store_true", help="Debugging output") + parser.add_argument("-o", "--output", default="findRuns.txt", help="Specify output file") + parser.add_argument("-t", "--type", default="Physics", help="Run type to match") + return parser.parse_args() + +# Take a string and turn it into a list of integers +# Can specify single values, ranges, or comma separated lists of both +def parseRunList(runlist): + + run_list = [] + + # Check if this is a file with run numbers + if len(runlist) == 1: + path = Path(runlist[0]) + if path.exists() and path.is_file(): + print(f"Reading runs from {path}") + # Try reading each line as a run number + with path.open() as f: + for line in f.readlines(): + line = line.strip() + if len(line) == 0: continue + if line[0] in ['#', '!']: continue + if not line.isnumeric(): + print(f"Error parsing {line}") + continue + run_list.append(int(line)) + # Done reading file + return(run_list) + + for string in runlist: + tokens = string.split(',') + + for segment in tokens: + + if len(segment) == 0: continue + + if '-' in segment: # Range of runs + start, end = segment.split('-') + start = int(start) + end = int(end) + run_list.extend(list(range(int(start), int(end)+1))) + + else: + run_list.append(int(segment)) + + return(run_list) + +# Command-line execution +if __name__ == "__main__": + + # Parse the command-line arguments + args = parse_arguments() + + run_list = parseRunList(args.runs) + run_list.sort() + + with open(args.output, "w") as f: + f.write(f"# findRuns.py") + [f.write(f" {run}") for run in args.runs] + f.write("\n") + + # faser-runinfo address + url = "https://faser-runinfo.app.cern.ch/cgibin/" + + # Cycle through range + for run in run_list: + query = f"{url}/getRunInfo.py?runno={run}" + response = requests.get(query) + + if not response.json(): + if args.verbose: + print(f"Couldn't find run {run}") + + continue + + run_type = response.json()['type'] + if args.verbose: + print(f"Run {run} has type {run_type}") + if run_type != args.type: continue + + with open(args.output, "a") as f: + f.write(f"{run}\n") + + # End of loop over runs diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeEmptyNoisyStripDB.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeEmptyNoisyStripDB.py new file mode 100755 index 0000000000000000000000000000000000000000..3cfdedc306f71c4f93592118a95d23c7f2bc1e20 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeEmptyNoisyStripDB.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +import ROOT + +from PyCool import cool + +dbSvc = cool.DatabaseSvcFactory.databaseService() +# Data DB name +connectString = 'sqlite://;schema=noisy_strips.db;dbname=CONDBR3' + +print('Creating empty database') + +dbSvc.dropDatabase(connectString) + +db = dbSvc.createDatabase(connectString) + +noisyStripsSpec = cool.RecordSpecification() +noisyStripsSpec.extend('sensor', cool.StorageType.Int32) +noisyStripsSpec.extend('nstrips', cool.StorageType.Int32) +noisyStripsSpec.extend('noisyList', cool.StorageType.String64k) + +description = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>' +noisyStripsFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, noisyStripsSpec) +noisyStripsFolder = db.createFolder('/SCT/DAQ/NoisyStrips', noisyStripsFolderSpec, description, True) + +firstValid = cool.ValidityKeyMin +lastValid = cool.ValidityKeyMax + +for sensor in range(192): + noisyStripsRecord = cool.Record(noisyStripsSpec) + noisyStripsRecord['sensor'] = int(sensor) + noisyStripsRecord['nstrips'] = 0 + noisyStripsFolder.storeObject(firstValid, lastValid, noisyStripsRecord, sensor) + +db.closeDatabase() + +# Do this again for MC +connectString = 'sqlite://;schema=noisy_strips.db;dbname=OFLP200' + +print('Creating empty MC database') + +# Don't drop the DB we just made +#dbSvc.dropDatabase(connectString) + +# Create new DB (different name in same file for MC +db = dbSvc.createDatabase(connectString) + +noisyStripsFolder = db.createFolder('/SCT/DAQ/NoisyStrips', noisyStripsFolderSpec, description, True) + +firstValid = cool.ValidityKeyMin +lastValid = cool.ValidityKeyMax + +numNoisyStrips = 0 # This is used as a channel... +for sensor in range(192): + noisyStripsRecord = cool.Record(noisyStripsSpec) + noisyStripsRecord['sensor'] = int(sensor) + noisyStripsRecord['nstrips'] = 0 + noisyStripsFolder.storeObject(firstValid, lastValid, noisyStripsRecord, sensor) + +db.closeDatabase() + +print('Database completed') diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeNoisyStripDB.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeNoisyStripDB.py new file mode 100755 index 0000000000000000000000000000000000000000..150d10c2cfd889807bf672bd67e0162102da74b0 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/makeNoisyStripDB.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +import os +import sys +import ROOT +import argparse +import array +from PyCool import cool +from CoolConvUtilities.AtlCoolLib import indirectOpen + +parser = argparse.ArgumentParser() +parser.add_argument("file", nargs="+", help="full path to input file") +parser.add_argument("-t", "--threshold", type=float, default=0.001, help="add strips with an occupancy larger this threshold to the database") +parser.add_argument("--force", "-f", action="store_true", help="Overwrite existing DB") +parser.add_argument("--permissive", action="store_true", help="Allow some input files to be missing") +parser.add_argument("--output", "-o", default="noisy_strips.db", help="Specify output DB") +parser.add_argument("--isMC", action="store_true", help="Write MC DB (default: real data)") +parser.add_argument("--use_blob", action="store_true", help="Write to DB using blob (default: save as string") + +args = parser.parse_args() + +def GetKeyNames(self): + return [key.GetName() for key in f.GetListOfKeys()] + +ROOT.TFile.GetKeyNames = GetKeyNames + +numEvents = 0 +nfiles = 0 +HistDict = {} + +ROOT.TH1.AddDirectory(0) # This is necessary in order to have the histogram data after closing the file + +trigger = None +iovlo = cool.ValidityKeyMax +iovhi = cool.ValidityKeyMin + +# Keys to skip +skipList = ["numEvents", "trigger", "IOVLoRun", "IOVLoLB", "IOVHiRun", "IOVHiLB"] + +for inputfile in args.file: + # Check that this exists + if not os.path.exists(inputfile) : + if args.permissive: continue + print(f"File {inputfile} not found!") + sys.exit(1) + + try: + f = ROOT.TFile.Open(inputfile, "r") + except Exception as e: + print(e) + if args.permissive: continue + sys.exit(1) + + n = f.Get("numEvents").GetVal() + print(f"Found {n} events in {inputfile}") + if n == 0: continue + numEvents += n + lorun = f.Get("IOVLoRun").GetVal() + hirun = f.Get("IOVHiRun").GetVal() + lo = (lorun << 32) + hi = ((hirun+1) << 32) - 1 + if lo < iovlo: iovlo = lo + if hi > iovhi: iovhi = hi + + if trigger is None: + trigger = f.Get("trigger").GetVal() + else: + t = f.Get("trigger").GetVal() + if t != trigger: + print(f"Trigger mismatch! {t} != {trigger} in {inputfile}") + sys.exit(1) # This shouldn't happen + + for rootkey in f.GetKeyNames(): + + # skip over the root objects TParameters that store the trigger and number of events data + if rootkey in skipList: continue + + if rootkey in HistDict: # if sensor histogram has already been stored, then add to it + HistDict[rootkey].Add(f.Get(rootkey),1.0) + else: # if sensor histogram has not already been stored, then store this histogram + HistDict[rootkey] = f.Get(rootkey).Clone() + + nfiles += 1 + f.Close() + +print(f"Total {nfiles} analyzed with {numEvents} events") +print(f"Trigger mask = 0x{trigger:02x}") +print(f"IOV from {(iovlo >> 32)}/{(iovlo & 0xFFFFFFFF)} to {(iovhi >> 32)}/{(iovhi & 0xFFFFFFFF)}") + +# Write DB + +dbSvc = cool.DatabaseSvcFactory.databaseService() +dbname = "CONDBR3" # Real data +if args.isMC: + dbname="OFLP200" # MC + +connectString = f'sqlite://;schema={args.output};dbname={dbname}' + +print(f"Using connection string {connectString}") + +if os.path.exists(args.output): + if args.force: + print(f"Deleting {args.output} due to --force") + os.remove(args.output) + else: + print(f"File {args.output} exists, use --force to overwrite") + sys.exit(1) + +try: + print('Creating database') + dbSvc.dropDatabase(connectString) + db = dbSvc.createDatabase(connectString) +except Exception as e: + print(e) + sys.exit(1) + +noisyStripsSpec = cool.RecordSpecification() +noisyStripsSpec.extend('sensor', cool.StorageType.Int32) +noisyStripsSpec.extend('nstrips', cool.StorageType.Int32) +if args.use_blob: + noisyStripsSpec.extend('strip', cool.StorageType.Blob64k) # Array of ints + noisyStripsSpec.extend('occupancy', cool.StorageType.Blob64k) # Array of floats +else: + noisyStripsSpec.extend('noisyList', cool.StorageType.String64k) + +description = '<timeStamp>run-lumi</timeStamp><addrHeader><address_header clid="1238547719" service_type="71" /></addrHeader><typeName>CondAttrListCollection</typeName>' +noisyStripsFolderSpec = cool.FolderSpecification(cool.FolderVersioning.SINGLE_VERSION, noisyStripsSpec) + +print("Creating new folder") +noisyStripsFolder = db.createFolder('/SCT/DAQ/NoisyStrips', noisyStripsFolderSpec, description, True) + +firstValid = iovlo +lastValid = iovhi + +numNoisyStrips = 0 + +for dictkey in HistDict: + noisy = 0 + strip_array = array.array('i') + occ_array = array.array('d') + noisy_str = '' + HistDict[dictkey].Scale(1.0/float(numEvents)) + for bini in range(768): + if HistDict[dictkey].GetBinContent(bini+1) >= args.threshold: + noisy += 1 + numNoisyStrips += 1 + strip_array.append(int(bini)) + occ_array.append(HistDict[dictkey].GetBinContent(bini+1)) + noisy_str += f' {int(bini):3}:{HistDict[dictkey].GetBinContent(bini+1):.5f}' + + # Done with loop over bins + noisyStripsRecord = cool.Record(noisyStripsSpec) + noisyStripsRecord['sensor'] = int(dictkey) + noisyStripsRecord['nstrips'] = noisy + if args.use_blob: + strip_blob = noisyStripsRecord['strip'] + occ_blob = noisyStripsRecord['occupancy'] + if len(strip_array) > 0: + strip_blob.resize(4*len(strip_array)) # Length in bytes + occ_blob.resize(4*len(strip_array)) + strip_blob = strip_array.tobytes() + occ_blob = occ_array.tobytes() + + else: + noisyStripsRecord['noisyList'] = noisy_str + + noisyStripsFolder.storeObject(firstValid, lastValid, noisyStripsRecord, int(dictkey)) + +db.closeDatabase() + +print('Database completed') +print(f"Added {numNoisyStrips} strips to database") diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/mergeNoisyStripDB.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/mergeNoisyStripDB.py new file mode 100755 index 0000000000000000000000000000000000000000..121aedcc342604846ef9911559ef8b5efb0818a9 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/mergeNoisyStripDB.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +# +# Sept 2022, E. Torrence +# +# Script to merge individual run DBs into a master DB +# +# Usage: +# ./mergeNoisyDBRuns.py -h +# +import sys +import argparse +import subprocess + +from pathlib import Path + +def parse_arguments(): + + description="Script to merge DBs from individual runs into one DB\n" + parser = argparse.ArgumentParser(description, + formatter_class=argparse.RawTextHelpFormatter) + + + parser.add_argument("runs", nargs='+', help="Specify FASER runs or range") + + parser.add_argument("-v", "--verbose", action="store_true", help="Debugging output") + parser.add_argument("-a", "--append", action="store_true", help="Append (rather than overwrite) existing file") + parser.add_argument("-o", "--output", default="noisy_strips.db", help="Specify output DB name") + return parser.parse_args() + +# Take a string and turn it into a list of integers +# Can specify single values, ranges, or comma separated lists of both +def parseRunList(runlist): + + run_list = [] + + # Check if this is a file with run numbers + if len(runlist) == 1: + path = Path(runlist[0]) + if path.exists() and path.is_file(): + print(f"Reading runs from {path}") + # Try reading each line as a run number + with path.open() as f: + for line in f.readlines(): + line = line.strip() + if len(line) == 0: continue + if line[0] in ['#', '!']: continue + if not line.isnumeric(): + print(f"Error parsing {line}") + continue + run_list.append(int(line)) + # Done reading file + return(run_list) + elif '-' in runlist[0]: + pass + elif ',' in runlist[0]: + pass + elif not runlist[0].isnumeric(): + print(f"File {path} doesn't exist!") + return run_list + + for string in runlist: + tokens = string.split(',') + + for segment in tokens: + + if len(segment) == 0: continue + + if '-' in segment: # Range of runs + start, end = segment.split('-') + if not start.isnumeric(): + print(f"Found invalid run {start}") + continue + if not end.isnumeric(): + print(f"Found invalid run {end}") + continue + start = int(start) + end = int(end) + run_list.extend(list(range(int(start), int(end)+1))) + + else: + if not segment.isnumeric(): + print(f"Found invalid run {segment}") + continue + run_list.append(int(segment)) + + return(run_list) + + +# Command-line execution +if __name__ == "__main__": + + # Parse the command-line arguments + args = parse_arguments() + + run_list = parseRunList(args.runs) + run_list.sort() + + first = True + + for runnum in run_list: + + if args.verbose: print(f"\nRun {runnum}") + runstr = f'{runnum:06d}' + infile = Path(f'{runstr}/noisy_{runstr}.db') + if not infile.is_file(): + print(f"{runstr}/noisy_{runstr}.db doesn't exist!") + continue + + command = ['AtlCoolCopy'] + command.append(f'sqlite://;schema={runstr}/noisy_{runstr}.db;dbname=CONDBR3') + command.append(f'sqlite://;schema={args.output};dbname=CONDBR3') + if first: + first = False + target = Path(args.output) + if not target.is_file(): + print(f"Creating file {args.output}") + command.append("-create") + elif args.append: + print(f"Appending to existing file {args.output}") + else: + print(f"Deleting existing file {args.output}") + target.unlink() + command.append("-create") + + command.extend(["-alliov", "-nrls", f"{runnum}", "0"]) + + if args.verbose: print(command) + rc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + universal_newlines=True) + + if args.verbose: print(rc.stdout) + diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/runFaserScript.sh b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/runFaserScript.sh new file mode 100755 index 0000000000000000000000000000000000000000..97d599b73e1046223cc0c6e938062b1206c6e82c --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/runFaserScript.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# +# Wrapper to run any python script in the athena environment +# Typically used to set up a script for use in condor +# +# runFaserScript.sh --rel <release_directory> script.py arguments... +# +function print_usage { + echo "Usage: runFaserScript.sh --rel <release_directory> [--log <logfile>] script.py [arguments]" + echo " The first uption must be the release directory where asetup is called" + echo " All other options are passed to script.py" + echo " Options: " + echo " -h - print usage" + echo " --rel <release_directory> - specify release directory" + echo " --log <logfile> - redirect script output to logfile" + echo " -- End of options considered by this script" +} +# +release_directory="" +logfile="" +while [ -n "$1" ] +do + case "$1" in + -h | --help) + print_usage + exit 0;; + + --rel) + release_directory="$2"; + shift; + shift;; + + --log) + logfile="$2"; + shift; + shift;; + + --) # Signal that everything else should be executed + shift; + break;; + + *) + # Nothing we recognize, execute everything remaining + break;; + esac +done + +if [ -z "$release_directory" ]; then + echo "Must specify release" + print_usage + exit 1 +fi + +# Redirect to log file if requested +if [ ! -z "$logfile" ]; then +#logfile="post_`date +%m%d-%H%M%S`.log" + exec >& "$logfile" +fi +# +# Set up release +starting_directory=`pwd` +echo "cd $release_directory" +cd $release_directory +# +# Set up the release +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +# Must pass something or source will pass *this* script's arguments instead +source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh -- +echo "fsetup Athena,22.0.49" +asetup --input=calypso/asetup.faser Athena,22.0.49 +echo "source run/setup.sh" +source run/setup.sh +# +# Go back to where we started +echo "cd $starting_directory" +cd $starting_directory +# +# Now run the command +echo "$@" +eval "$@" diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/share/submitNoisyStripJobs.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/submitNoisyStripJobs.py new file mode 100755 index 0000000000000000000000000000000000000000..fa034fd773f32751a71c04538775a1f5ab148e58 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/share/submitNoisyStripJobs.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +# +# Sept 2022, E. Torrence +# +# Script to run noisy strip finder on a given run +# This creates condor submitssion scripts and a DAG +# and submits those to run the jobs +# +# Usage: +# submitNoisyStripJobs.py -h +# +import os +import sys +import time +import argparse +import subprocess + +from pathlib import Path + +def parse_arguments(): + + description="Script to submit jobs to find noisy strips" + parser = argparse.ArgumentParser(description, + formatter_class=argparse.RawTextHelpFormatter) + + + parser.add_argument("runs", nargs='+', help="Specify FASER runs") + + parser.add_argument("--per_job", type=int, default=25, help="Specify maximum files per job (default: 25)") + parser.add_argument("--release", default='.', help="Specify path to release directory (default: .)") + parser.add_argument("--nosubmit", action="store_true", help="Don't submit jobs") + parser.add_argument("--nocleanup", action="store_true", help="Don't cleanup output directory on completion") + parser.add_argument("--queue", default="longlunch", help="Specify queue (longlunch=2h (default), workday=8h)") + parser.add_argument("--rawdir", default="/eos/experiment/faser/raw/2022", + help="Specify raw data directory (default: /eos/experiment/faser/raw/2022)") + parser.add_argument("-n", "--nsubmit", default=100, help="Specify total number of jobs to submit at once (default: 100)") + + return parser.parse_args() + +# Take a string and turn it into a list of integers +# Can specify single values, ranges, or comma separated lists of both +def parseRunList(runlist): + + run_list = [] + + # Check if this is a file with run numbers + if len(runlist) == 1: + path = Path(runlist[0]) + if path.exists() and path.is_file(): + print(f"Reading runs from {path}") + # Try reading each line as a run number + with path.open() as f: + for line in f.readlines(): + line = line.strip() + if len(line) == 0: continue + if line[0] in ['#', '!']: continue + if not line.isnumeric(): + print(f"Error parsing {line}") + continue + run_list.append(int(line)) + # Done reading file + return(run_list) + + for string in runlist: + tokens = string.split(',') + + for segment in tokens: + + if len(segment) == 0: continue + + if '-' in segment: # Range of runs + start, end = segment.split('-') + start = int(start) + end = int(end) + run_list.extend(list(range(int(start), int(end)+1))) + + else: + run_list.append(int(segment)) + + return(run_list) + +# Command-line execution +if __name__ == "__main__": + + # Parse the command-line arguments + args = parse_arguments() + + run_list = parseRunList(args.runs) + run_list.sort() + + # Check some things + rel_dir = Path(args.release) + package_dir = rel_dir / Path("calypso/Tracker/TrackerRecAlgs/NoisyStripFinder") + + # Script to allow python scripts to be run in condor in the FASER environment + env_exec = package_dir / Path("share/runFaserScript.sh") + + if not env_exec.exists(): + print(f"Can't find executable in release directory {args.release}") + sys.exit(1) + + print(f"Start processing {len(run_list)} runs") + + nsubmitted = 0 + + for run in run_list: + print(f"Working on run {run}") + + runstr = f"{run:06d}" + + # Get file list + raw_dir = Path(f'{args.rawdir}/{runstr}') + file_list = list(raw_dir.glob("Faser-Physics*.raw")) + + # Now we need to decide what to do + nraw = len(file_list) + njobs = (nraw-1) // args.per_job + 1 + if njobs == 1: + print(f"{nraw} raw files found, submitting {njobs} job") + else: + print(f"{nraw} raw files found, submitting {njobs} jobs") + + if njobs == 0: continue + + # Create a directory for this + jobdir = Path(runstr) + if jobdir.exists(): + print(f"Directory {jobdir} exists, deleting...") + import shutil + shutil.rmtree(jobdir.resolve()) + + jobdir.mkdir(exist_ok=True) + submit_list = [] + + # Start the DAG file + dagfile = jobdir / Path(f"noise_{runstr}.dag") + with open(dagfile, 'w') as d: + d.write(f"# Auto-generated DAG submission script for {runstr}\n") + + for job in range(njobs): + + jobstr = f"{job:03d}" + if njobs == 1: + jobname = f"noise_{runstr}" + else: + jobname = f"noise_{runstr}_{jobstr}" + subfile = jobdir / Path(jobname+".sub") + + ilo = job * args.per_job + ihi = ilo + args.per_job + job_files = file_list[ilo:ihi] + + # + # Generate a job submission script + print(f"Writing {subfile}") + submit_list.append(jobname) + with open(subfile, "w") as f: + f.write(f"# Auto-generated submission script for {jobname}\n") + # Set the queue workday = 8h, longlunch = 2h might be enough + f.write(f'+JobFlavour = "{args.queue}"\n') + f.write(f"executable = {env_exec.resolve()}\n") + f.write(f"output = {jobdir.resolve()}/{jobname}.out\n") + f.write(f"error = {jobdir.resolve()}/{jobname}.err\n") + f.write(f"log = {jobdir.resolve()}/{jobname}.log\n") + # No newline as we need to add input files + f.write(f"arguments = --rel {rel_dir.resolve()} NoisyStripFinderJob.py --out {jobname}.root ") + [f.write(f" {filename}") for filename in job_files] + f.write("\n") + f.write("queue") + + # Also add this to our DAG + with open(dagfile, 'a') as d: + d.write(f"JOB {jobname} {subfile.name}\n") + # Also check that the histogram isn't empty + # This can fix some file read errors + d.write(f"SCRIPT POST {jobname} {env_exec.resolve()} --rel {rel_dir.resolve()} checkNoisyStripHist.py {jobname}.root $RETURN\n") + + # Done writing individual jobs + + # Add the merge job to the DAG + with open(dagfile, 'a') as d: + d.write(f"JOB merge_{runstr} merge_{runstr}.sub\n") + d.write("PARENT") + for jobname in submit_list: + d.write(f" {jobname}") + d.write(f" CHILD merge_{runstr}\n") + # Add a retry directive + d.write(f"RETRY ALL_NODES 1\n") + + # Write the merge job submit script + jobname = f"merge_{runstr}" + subfile = jobdir / Path(jobname+".sub") + with open(subfile, "w") as f: + f.write(f"# Auto-generated submission script for {jobname}\n") + f.write(f"output = {jobdir.resolve()}/{jobname}.out\n") + f.write(f"error = {jobdir.resolve()}/{jobname}.err\n") + f.write(f"log = {jobdir.resolve()}/{jobname}.log\n") + + #f.write('+JobFlavour = "workday"\n') # 8 hours, longlunch might be enough + #f.write(f"executable = {hist_exec.resolve()}\n") + f.write(f"executable = {env_exec.resolve()}\n") + + # No newline as we need to add input files + # f.write(f"arguments = --rel {rel_dir.resolve()} --force -o noisy_{runstr}.db") + f.write(f"arguments = --rel {rel_dir.resolve()} makeNoisyStripDB.py --force -o noisy_{runstr}.db") + [f.write(f" {filename}.root") for filename in submit_list] + f.write("\n") + + # Provide files to transfer + f.write(f"transfer_input_files = {submit_list[0]}.root") + [f.write(f",{filename}.root") for filename in submit_list[1:]] + f.write("\n") + f.write(f"should_transfer_files = IF_NEEDED\n") + + # Don't forget queue command + f.write("queue") + + # Do we want a cleanup script? + if not args.nocleanup: + with open(dagfile, 'a') as d: + d.write(f"SCRIPT POST merge_{runstr} cleanup.sh $RETURN\n") + + cleanup_file = jobdir / Path("cleanup.sh") + with open(cleanup_file, 'w') as f: + f.write("#!/bin/bash\n") + f.write('if [[ $1 != "0" ]]; then\n') + f.write(' exit $1\n') + f.write('fi\n') + # f.write('rm noise_{runstr}.dag.* \n') + f.write('rm *.log\n') + f.write('rm *.err\n') + f.write('rm eventLoopHeartBeat.txt\n') + f.write('rm *.cc\n') + for job in submit_list: + f.write(f'gzip {job}.out\n') + #f.write('gzip merge*.out\n') + f.write('exit 0\n') + + # And make it executable + import stat + cleanup_file.chmod(cleanup_file.stat().st_mode | stat.S_IEXEC) + + if not args.nosubmit: + print(f"Submitting noise_{runstr}.dag") + startdir = os.getcwd() + os.chdir(jobdir) + + # lxplus python3 is 3.6.8, so use old subprocess.run arguments + proc = subprocess.run(["/usr/bin/condor_submit_dag", f"noise_{runstr}.dag"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + + if len(proc.stdout) > 0: + print(proc.stdout) + if len(proc.stderr) > 0: + print(proc.stderr) + + # Chaange back to our starting point + os.chdir(startdir) + + nsubmitted += 1 + + # Don't flood the system, wait a few seconds here + time.sleep(5) + + # Have we reached our limit? + if nsubmitted >= int(args.nsubmit): + print(f"Quitting after submitting {nsubmitted} jobs") + print("Change this with --nsubmit option") + break + diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx index 71598696beb29fa13256f18193738eaee2b38ee5..c5f3f907852e40b072151c5e53c94ebdf6b3ea1b 100644 --- a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.cxx @@ -9,6 +9,7 @@ #include "TrackerRawData/FaserSCT_RDO_Container.h" #include "TrackerRawData/FaserSCT_RDORawData.h" #include "StoreGate/WriteHandle.h" +#include "xAODEventInfo/EventInfo.h" #include <sstream> #include <string.h> @@ -24,6 +25,7 @@ NoisyStripFinder::NoisyStripFinder(const std::string& name, ISvcLocator* pSvcLoc AthReentrantAlgorithm(name, pSvcLocator), m_idHelper{nullptr} { + m_iovrange = IOVRange(IOVTime(), IOVTime()); // Make sure this starts undefined } // Initialize method: @@ -32,6 +34,7 @@ StatusCode NoisyStripFinder::initialize() { ATH_CHECK(m_rdoContainerKey.initialize()); ATH_CHECK(m_FaserTriggerData.initialize()); + ATH_CHECK(m_eventInfo.initialize()); // Get the SCT ID helper ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID")); @@ -43,7 +46,7 @@ StatusCode NoisyStripFinder::initialize() { StatusCode NoisyStripFinder::execute(const EventContext& ctx) const { SG::ReadHandle<xAOD::FaserTriggerData> xaod(m_FaserTriggerData, ctx); - + int trig_int = xaod->tap(); int trigmask_int = m_triggerMask.value(); @@ -53,8 +56,22 @@ StatusCode NoisyStripFinder::execute(const EventContext& ctx) const { if (!(xaod->tap() & m_triggerMask.value())) return StatusCode::SUCCESS; // only process events that pass the trigger mask - ATH_MSG_INFO("trigger passed mask"); - ++m_numberOfEvents; + ATH_MSG_DEBUG("trigger passed mask"); + ++m_numberOfEvents; + + // Keep track of run + SG::ReadHandle<xAOD::EventInfo> xevt(m_eventInfo, ctx); + ATH_MSG_DEBUG("Found run number: " << xevt->runNumber()); + IOVTime iov(xevt->runNumber(), xevt->lumiBlock()); + ATH_MSG_DEBUG("IOV: " << iov); + + if (!m_iovrange.start().isValid()) + m_iovrange = IOVRange(iov, iov); + + if (iov > m_iovrange.stop()) + m_iovrange = IOVRange(m_iovrange.start(), iov); + + ATH_MSG_DEBUG("Range: " << m_iovrange); // First, we have to retrieve and access the container, not because we want to // use it, but in order to generate the proxies for the collections, if they @@ -99,17 +116,19 @@ StatusCode NoisyStripFinder::execute(const EventContext& ctx) const { StatusCode NoisyStripFinder::finalize() { ATH_MSG_INFO("NoisyStripFinder::finalize()"); - ATH_MSG_INFO( m_numberOfEvents << " events processed" ); + ATH_MSG_INFO( m_numberOfEvents << " events found" ); ATH_MSG_INFO( m_numberOfRDOCollection << " RDO collections processed" ); ATH_MSG_INFO( m_numberOfRDO<< " RawData" ); - ATH_MSG_INFO( "Number of sensors found = " << NoisyStrip_histmap.size() << " out of 144" ); + ATH_MSG_INFO( "Number of sensors found = " << NoisyStrip_histmap.size() << " out of 192" ); - for (int ihash = 0; ihash < 144; ++ihash){ // print out the sensors that are missing + for (int ihash = 0; ihash < 192; ++ihash){ // print out the sensors that are missing if ( NoisyStrip_histmap.count(ihash) == 0 ){ ATH_MSG_INFO("missing sensor # " << ihash); } } + ATH_MSG_INFO("IOV range found = " << m_iovrange); + const char *outputname = m_OutputRootName.value().c_str(); TFile* outputfile = new TFile(outputname,"RECREATE"); @@ -119,6 +138,27 @@ StatusCode NoisyStripFinder::finalize() TParameter("numEvents", m_numberOfEvents).Write(); TParameter("trigger", trigmask_int).Write(); + // Write IOV range so we can save this to the DB + if (m_iovrange.start().isValid()) { + long run = m_iovrange.start().run(); + long lb = m_iovrange.start().event(); + TParameter("IOVLoRun", run).Write(); // re_time() + TParameter("IOVLoLB", lb).Write(); + ATH_MSG_INFO("IOV Lo: " << run << "," << lb ); + } + else + ATH_MSG_WARNING("Starting IOV time invalid"); + + if (m_iovrange.stop().isValid()) { + long run = m_iovrange.stop().run(); + long lb = m_iovrange.stop().event(); + TParameter("IOVHiRun", run).Write(); + TParameter("IOVHiLB", lb).Write(); + ATH_MSG_INFO("IOV Hi: " << run << "," << lb ); + } + else + ATH_MSG_WARNING("Ending IOV time invalid"); + std::map<int,TH1D*>::iterator it = NoisyStrip_histmap.begin(); // Iterate over the map using Iterator till end. while (it != NoisyStrip_histmap.end()){ @@ -126,7 +166,8 @@ StatusCode NoisyStripFinder::finalize() ATH_MSG_INFO( "---------- hot strip occupancy >= 0.1 for Tracker Sensor hash = "<< it->first <<" ----------" ); int i = 1; while (i <= 768){ - if ( it->second->GetBinContent(i)/(double)m_numberOfEvents >= 0.1 ){ + // This is only for information + if ( it->second->GetBinContent(i)/(double)m_numberOfEvents >= 0.01 ){ ATH_MSG_INFO( "hot strip # = " << i-1 << ", hit occupancy = " << it->second->GetBinContent(i)/(double)m_numberOfEvents ); // print out hot strips } i++; diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h index a1d977595765f494217f8a63f044ba40cba26540..24009b93bba234368548e53052c42df7bcb86420 100644 --- a/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/src/NoisyStripFinder.h @@ -17,7 +17,8 @@ #include "GaudiKernel/ToolHandle.h" #include "StoreGate/ReadHandleKey.h" - +#include "AthenaKernel/IOVRange.h" +#include "xAODEventInfo/EventInfo.h" //STL #include <map> @@ -72,6 +73,7 @@ class NoisyStripFinder : public AthReentrantAlgorithm { SG::ReadHandleKey<FaserSCT_RDO_Container> m_rdoContainerKey{this, "DataObjectName", "FaserSCT_RDOs", "FaserSCT RDOs"}; SG::ReadHandleKey<xAOD::FaserTriggerData> m_FaserTriggerData{ this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"}; + SG::ReadHandleKey<xAOD::EventInfo> m_eventInfo{ this, "EventInfoKey", "EventInfo", "ReadHandleKey for xAOD::EventInfo"}; mutable int m_numberOfEvents{0}; mutable std::atomic<int> m_numberOfRDOCollection{0}; @@ -79,6 +81,9 @@ class NoisyStripFinder : public AthReentrantAlgorithm { mutable std::map<int,TH1D*> NoisyStrip_histmap; + // Keep track of first/last IOV seen + // Stored as (run << 32) + lumi block + mutable IOVRange m_iovrange; }; } #endif // NoisyStripFinder_H diff --git a/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py b/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py new file mode 100755 index 0000000000000000000000000000000000000000..f1d2ef1434110fa4a87a4567055e8f3d112f30c0 --- /dev/null +++ b/Tracker/TrackerRecAlgs/NoisyStripFinder/test/NoisyStripFinderDbg.py @@ -0,0 +1,55 @@ +#!/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 +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("file", nargs="+", help="full path to input file") +parser.add_argument("--nevents", "-n", default=-1, type=int, help="Number of events to process") +args = parser.parse_args() + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = args.file +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" +ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" +ConfigFlags.Input.ProjectName = "data21" +ConfigFlags.Input.isMC = False +ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" +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, OccupancyCut=-1)) +acc.merge(FaserSCT_ClusterizationCfg( + ConfigFlags, + DataObjectName="SCT_RDOs", + ClusterToolTimingPattern="XXX")) +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=args.nevents) +sys.exit(not sc.isSuccess()) diff --git a/Tracker/TrackerRecAlgs/PairVertex/CMakeLists.txt b/Tracker/TrackerRecAlgs/PairVertex/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..85053a1f49bd551ea136c5cd61f6cee40543ed26 --- /dev/null +++ b/Tracker/TrackerRecAlgs/PairVertex/CMakeLists.txt @@ -0,0 +1,12 @@ +atlas_subdir(PairVertex) + +atlas_add_component( + PairVertex + src/PairVertexAlg.h + src/PairVertexAlg.cxx + src/component/PairVertex_entries.cxx + LINK_LIBRARIES AthenaBaseComps StoreGateLib GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives +) + +atlas_install_python_modules(python/*.py) +# atlas_install_scripts(test/*.py) diff --git a/Tracker/TrackerRecAlgs/PairVertex/python/PairVertexAlgConfig.py b/Tracker/TrackerRecAlgs/PairVertex/python/PairVertexAlgConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..f98af1629a39bfc590ef3ab0929da4b849ad5ce6 --- /dev/null +++ b/Tracker/TrackerRecAlgs/PairVertex/python/PairVertexAlgConfig.py @@ -0,0 +1,90 @@ +""" + 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 PairVertexAlgCfg(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") + + PairVertexAlg = CompFactory.Tracker.PairVertexAlg("PairVertexAlg",**kwargs) + PairVertexAlg.ExtrapolationTool = actsExtrapolationTool + acc.addEventAlgo(PairVertexAlg) + return acc + +if __name__ == "__main__": + + 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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + + # Set up logging and new style config + log.setLevel(DEBUG) + Configurable.configurableRun3Behavior = True + + # Configure + ConfigFlags.Input.Files = [ + '/eos/experiment/faser/sim/mdc/foresee/110004/rec/r0007/FaserMC-MDC_FS_Amm_316MeV_2Em6-110004-00000-s0003-r0007-xAOD.root' + ] + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersionS + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + ConfigFlags.Input.ProjectName = "data21" # Needed to bypass autoconfig + ConfigFlags.Input.isMC = True # Needed to bypass autoconfig + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # FASER geometry + 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)) + + # algorithm + acc.merge(PairVertexAlgCfg(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 + + # Timing + #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) + + # 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) + + # Success should be 0 + sys.exit(not sc.isSuccess()) \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/PairVertex/python/__init__.py b/Tracker/TrackerRecAlgs/PairVertex/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.cxx b/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..99058166c7252ddbff852b0a09ec8d49a15e54fb --- /dev/null +++ b/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.cxx @@ -0,0 +1,163 @@ +#include "PairVertexAlg.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 { + +PairVertexAlg::PairVertexAlg(const std::string &name, ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator) {} + +StatusCode PairVertexAlg::initialize() +{ + ATH_CHECK(m_mcEventCollectionKey.initialize()); + ATH_CHECK(m_trackCollectionKey.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 PairVertexAlg::execute(const EventContext &ctx) const +{ + m_numberOfEvents++; + const Acts::GeometryContext gctx = + m_extrapolationTool->trackingGeometryTool()->getNominalGeometryContext().context(); + + std::vector<double> z_positions {}; + + 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; + } + + SG::ReadHandle<TrackCollection> tracks { m_trackCollectionKey, ctx }; + ATH_CHECK(tracks.isValid()); + + const Trk::TrackParameters* positive {nullptr}; + const Trk::TrackParameters* negative {nullptr}; + + for (auto trk : *tracks) + { + const Trk::TrackParameters* upstream {nullptr}; + if (trk == nullptr) + { + ATH_MSG_WARNING("Null pointer from TrackContainer."); + m_invalidTrackContainerEntries++; + continue; + } + auto parameters = trk->trackParameters(); + if (parameters == nullptr || parameters->empty()) + { + m_numberOfNoParameterTracks++; + ATH_MSG_WARNING("Track without parameters found."); + return StatusCode::SUCCESS; + } + for (auto state : *parameters) + { + if (state == nullptr) + { + m_numberOfNullParameters++; + ATH_MSG_WARNING("Null track parameters returned."); + continue; + } + if (!state->hasSurface()) + { + m_numberOfParametersWithoutSurface++; + ATH_MSG_WARNING("Track state without surface found."); + continue; + } + if (!upstream || upstream->associatedSurface().center().z() > state->associatedSurface().center().z()) + upstream = state; + } + if (!upstream) + { + m_numberOfNoUpstreamTracks++; + ATH_MSG_WARNING("Unable to find track parameters on any surface"); + continue; + } + auto momentum = upstream->momentum(); + double charge = upstream->charge(); + if (charge > 0 || momentum.mag() > positive->momentum().mag()) + { + positive = upstream; + } + else if (charge < 0 || momentum.mag() > negative->momentum().mag()) + { + negative = upstream; + } + } + + if (positive != nullptr) m_numberOfPositiveTracks++; + if (negative != nullptr) m_numberOfNegativeTracks++; + + if (positive != nullptr && negative != nullptr) m_numberOfOppositeSignPairs++; + + // 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 PairVertexAlg::finalize() +{ + ATH_MSG_INFO("Found " << m_numberOfOppositeSignPairs << " opposite sign pairs in " << m_numberOfEvents << " total events."); + ATH_MSG_INFO(m_numberOfPositiveTracks << " events had a positive track, and " << m_numberOfNegativeTracks << " had a negative track."); + ATH_MSG_INFO(m_numberOfNoUpstreamTracks << " tracks could not locate an upstream position."); + ATH_MSG_INFO(m_numberOfNoParameterTracks << " tracks in track pairs had no track parameters."); + ATH_MSG_INFO(m_numberOfNullParameters << " track parameters were null and " << m_numberOfParametersWithoutSurface << " had no associated surface."); + ATH_MSG_INFO(m_invalidTrackContainerEntries << " invalid TrackContainer entries found."); + return StatusCode::SUCCESS; +} + +} // Tracker diff --git a/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.h b/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..d15fddf6e288828d143218fa6d2f686a50076ba0 --- /dev/null +++ b/Tracker/TrackerRecAlgs/PairVertex/src/PairVertexAlg.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 2022 CERN for the benefit of the FASER collaboration +*/ + +#pragma once + +#include "GeoPrimitives/GeoPrimitives.h" +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include "GeneratorObjects/McEventCollection.h" +#include "TrkTrack/TrackCollection.h" + +class FaserSCT_ID; +namespace TrackerDD +{ + class SCT_DetectorManager; +} + +namespace Tracker +{ + class PairVertexAlg : public AthReentrantAlgorithm + { + public: + PairVertexAlg(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<TrackCollection> m_trackCollectionKey { this, "TrackCollection", "CKFTrackCollection" }; + + ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { this, "ExtrapolationTool", "FaserActsExtrapolationTool" }; + + mutable std::atomic<size_t> m_numberOfEvents{0}; + mutable std::atomic<size_t> m_numberOfPositiveTracks{0}; + mutable std::atomic<size_t> m_numberOfNegativeTracks{0}; + mutable std::atomic<size_t> m_numberOfOppositeSignPairs{0}; + mutable std::atomic<size_t> m_numberOfNoParameterTracks{0}; + mutable std::atomic<size_t> m_invalidTrackContainerEntries{0}; + mutable std::atomic<size_t> m_numberOfNullParameters{0}; + mutable std::atomic<size_t> m_numberOfParametersWithoutSurface{0}; + mutable std::atomic<size_t> m_numberOfNoUpstreamTracks{0}; + }; + +} \ No newline at end of file diff --git a/Tracker/TrackerRecAlgs/PairVertex/src/component/PairVertex_entries.cxx b/Tracker/TrackerRecAlgs/PairVertex/src/component/PairVertex_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..db08d4e764775c0a28da9e53538e2e5daae46932 --- /dev/null +++ b/Tracker/TrackerRecAlgs/PairVertex/src/component/PairVertex_entries.cxx @@ -0,0 +1,3 @@ +#include "../PairVertexAlg.h" + +DECLARE_COMPONENT(Tracker::PairVertexAlg) \ No newline at end of file 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..a94a20eeea879b7e959a6b5da5825671d9291276 100644 --- a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py +++ b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/python/TrackerPrepRawDataFormationConfig.py @@ -8,8 +8,8 @@ PileUpXingFolder=CompFactory.PileUpXingFolder from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg - from FaserSiLorentzAngleTool.FaserSCT_LorentzAngleConfig import FaserSCT_LorentzAngleCfg +from FaserSCT_ConditionsTools.FaserSCT_ConditionsSummaryToolConfig import FaserSCT_ConditionsSummaryToolCfg def FaserSCT_ClusterizationCommonCfg(flags, name="FaserSCT_ClusterizationToolCommon", **kwargs): @@ -20,7 +20,13 @@ def FaserSCT_ClusterizationCommonCfg(flags, name="FaserSCT_ClusterizationToolCom trackerClusterMakerTool = Tracker__TrackerClusterMakerTool(name = "TrackerClusterMakerTool") faserSCT_LorentzAngleTool=acc.popToolsAndMerge(FaserSCT_LorentzAngleCfg(flags)) kwargs.setdefault("timeBins", "01X") - clusteringTool = Tracker__FaserSCT_ClusteringTool(name, globalPosAlg = trackerClusterMakerTool, FaserSiLorentzAngleTool=faserSCT_LorentzAngleTool, **kwargs) + + FaserSCT_ConditionsSummaryTool = acc.popToolsAndMerge(FaserSCT_ConditionsSummaryToolCfg(flags)) + clusteringTool = Tracker__FaserSCT_ClusteringTool(name, + globalPosAlg=trackerClusterMakerTool, + FaserSiLorentzAngleTool=faserSCT_LorentzAngleTool, + conditionsTool=FaserSCT_ConditionsSummaryTool, + **kwargs) # clusteringTool.timeBins = "01X" # attach ToolHandles acc.setPrivateTools(clusteringTool) @@ -36,16 +42,20 @@ def FaserSCT_ClusterizationToolCfg(flags, name="FaserSCT_ClusterizationTool", ** def FaserSCT_ClusterizationBasicCfg(flags, **kwargs): """Return ComponentAccumulator for FaserSCT Clusterization""" acc = ComponentAccumulator() - pattern = kwargs.pop("ClusterToolTimingPattern","") + pattern = kwargs.pop("ClusterToolTimingPattern", "") + checkBadChannels = kwargs.pop("checkBadChannels", "False") # print("ClusterToolTimingPattern = ", pattern) if len(pattern) > 0 : - clusterTool = acc.popToolsAndMerge(FaserSCT_ClusterizationToolCfg(flags, timeBins = pattern )) + clusterTool = acc.popToolsAndMerge(FaserSCT_ClusterizationToolCfg(flags, timeBins=pattern, checkBadChannels=checkBadChannels)) else: - clusterTool = acc.popToolsAndMerge(FaserSCT_ClusterizationToolCfg(flags)) + clusterTool = acc.popToolsAndMerge(FaserSCT_ClusterizationToolCfg(flags, checkBadChannels=checkBadChannels)) + + FaserSCT_ConditionsSummaryTool = acc.popToolsAndMerge(FaserSCT_ConditionsSummaryToolCfg(flags)) kwargs.setdefault("SCT_ClusteringTool", clusterTool) kwargs.setdefault("DataObjectName", "SCT_RDOs") kwargs.setdefault("ClustersName", "SCT_ClusterContainer") + kwargs.setdefault("conditionsTool", FaserSCT_ConditionsSummaryTool) # kwargs.setdefault("SCT_FlaggedCondData", "SCT_Flags") Tracker__FaserSCT_Clusterization=CompFactory.Tracker.FaserSCT_Clusterization acc.addEventAlgo(Tracker__FaserSCT_Clusterization(**kwargs)) @@ -65,5 +75,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/TrackerPrepRawDataFormation/src/FaserSCT_Clusterization.cxx b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/src/FaserSCT_Clusterization.cxx index 640ba15148970d76ad415f4a6f127f167afe9d62..aa28620812293c71f962602105ee31888baf79de 100644 --- a/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/src/FaserSCT_Clusterization.cxx +++ b/Tracker/TrackerRecAlgs/TrackerPrepRawDataFormation/src/FaserSCT_Clusterization.cxx @@ -41,9 +41,9 @@ StatusCode FaserSCT_Clusterization::initialize() { // later and declare everything to be 'good' if it is NULL) if (m_checkBadModules.value()) { ATH_MSG_INFO("Clusterization has been asked to look at bad module info"); - // ATH_CHECK(m_pSummaryTool.retrieve()); + ATH_CHECK(m_pSummaryTool.retrieve()); } else { - // m_pSummaryTool.disable(); + m_pSummaryTool.disable(); } // m_clusterContainerLinkKey = m_clusterContainerKey.key(); diff --git a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx index 98b1c29f1f14f6f217b27d6223f7112e286e2111..8daed1f9c389e96ee2b8e83ddf01d61f548f8ee9 100755 --- a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx +++ b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.cxx @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2021 ChRN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration */ /*************************************************************************** @@ -73,12 +73,45 @@ namespace Tracker , m_chi2(0) , m_edm(0) , m_ndf(0) + , m_preYhistX_s1l1m0(0) + , m_preYhistY_s1l1m0(0) + , m_preXhistX_s1l1m0(0) + , m_preXhistY_s1l1m0(0) + , m_preYhistX_s1l1m1(0) + , m_preYhistY_s1l1m1(0) + , m_preXhistX_s1l1m1(0) + , m_preXhistY_s1l1m1(0) + , m_preYhistX_s1l1m2(0) + , m_preYhistY_s1l1m2(0) + , m_preXhistX_s1l1m2(0) + , m_preXhistY_s1l1m2(0) + , m_preYhistX_s1l1m3(0) + , m_preYhistY_s1l1m3(0) + , m_preXhistX_s1l1m3(0) + , m_preXhistY_s1l1m3(0) + , m_preYhistX_s1l1m4(0) + , m_preYhistY_s1l1m4(0) + , m_preXhistX_s1l1m4(0) + , m_preXhistY_s1l1m4(0) + , m_preYhistX_s1l1m5(0) + , m_preYhistY_s1l1m5(0) + , m_preXhistX_s1l1m5(0) + , m_preXhistY_s1l1m5(0) + , m_preYhistX_s1l1m6(0) + , m_preYhistY_s1l1m6(0) + , m_preXhistX_s1l1m6(0) + , m_preXhistY_s1l1m6(0) + , m_preYhistX_s1l1m7(0) + , m_preYhistY_s1l1m7(0) + , m_preXhistX_s1l1m7(0) + , m_preXhistY_s1l1m7(0) , m_thistSvc("THistSvc", name) { declareProperty("MaxChi2", m_maxchi2=20); declareProperty("UseBiasedResidual", m_bias=true); declareProperty("SaveAllClusterInfo", m_saveallcluster=true); declareProperty("SaveAllSPInfo", m_saveallsp=true); + declareProperty("MakeDoublets", m_doublets=true); } //----------------------------------------------------------------------- @@ -103,6 +136,12 @@ namespace Tracker m_tree= new TTree("spfit","tree"); TrackerSPFit::initializeTree(); + ATH_CHECK( m_trackerSeedContainerKey.initialize() ); + if (m_trackerSeedContainerKey.key().empty()){ + ATH_MSG_FATAL( "No name set for output track seeds"); + return StatusCode::FAILURE; + } + // create containers (requires the Identifier Helpers) ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); @@ -149,7 +188,71 @@ namespace Tracker m_chi2=new TH1D("chi2","chi2",100,0,100); m_edm=new TH1D("edm","edm",100,0,0.01); m_ndf=new TH1D("ndf","ndf",10,0,10); + m_preYhistX_s1l1m0=new TProfile("YvsX_s1l1m0","residual vs x for staion 1 layer 1 module 0",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m0=new TProfile("XvsX_s1l1m0","residual vs x for staion 1 layer 1 module 0",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m0=new TProfile("XvsY_s1l1m0","residual vs x for staion 1 layer 1 module 0",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m0=new TProfile("YvsY_s1l1m0","residual vs x for staion 1 layer 1 module 0",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m1=new TProfile("YvsX_s1l1m1","residual vs x for staion 1 layer 1 module 1",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m1=new TProfile("XvsX_s1l1m1","residual vs x for staion 1 layer 1 module 1",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m1=new TProfile("XvsY_s1l1m1","residual vs x for staion 1 layer 1 module 1",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m1=new TProfile("YvsY_s1l1m1","residual vs x for staion 1 layer 1 module 1",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m2=new TProfile("YvsX_s1l1m2","residual vs x for staion 1 layer 1 module 2",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m2=new TProfile("XvsX_s1l1m2","residual vs x for staion 1 layer 1 module 2",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m2=new TProfile("XvsY_s1l1m2","residual vs x for staion 1 layer 1 module 2",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m2=new TProfile("YvsY_s1l1m2","residual vs x for staion 1 layer 1 module 2",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m3=new TProfile("YvsX_s1l1m3","residual vs x for staion 1 layer 1 module 3",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m3=new TProfile("XvsX_s1l1m3","residual vs x for staion 1 layer 1 module 3",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m3=new TProfile("XvsY_s1l1m3","residual vs x for staion 1 layer 1 module 3",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m3=new TProfile("YvsY_s1l1m3","residual vs x for staion 1 layer 1 module 3",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m4=new TProfile("YvsX_s1l1m4","residual vs x for staion 1 layer 1 module 4",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m4=new TProfile("XvsX_s1l1m4","residual vs x for staion 1 layer 1 module 4",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m4=new TProfile("XvsY_s1l1m4","residual vs x for staion 1 layer 1 module 4",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m4=new TProfile("YvsY_s1l1m4","residual vs x for staion 1 layer 1 module 4",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m5=new TProfile("YvsX_s1l1m5","residual vs x for staion 1 layer 1 module 5",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m5=new TProfile("XvsX_s1l1m5","residual vs x for staion 1 layer 1 module 5",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m5=new TProfile("XvsY_s1l1m5","residual vs x for staion 1 layer 1 module 5",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m5=new TProfile("YvsY_s1l1m5","residual vs x for staion 1 layer 1 module 5",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m6=new TProfile("YvsX_s1l1m6","residual vs x for staion 1 layer 1 module 6",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m6=new TProfile("XvsX_s1l1m6","residual vs x for staion 1 layer 1 module 6",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m6=new TProfile("XvsY_s1l1m6","residual vs x for staion 1 layer 1 module 6",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m6=new TProfile("YvsY_s1l1m6","residual vs x for staion 1 layer 1 module 6",100,-150,150,-0.1,0.1); + m_preYhistX_s1l1m7=new TProfile("YvsX_s1l1m7","residual vs x for staion 1 layer 1 module 7",100,-150,150,-0.1,0.1); + m_preXhistX_s1l1m7=new TProfile("XvsX_s1l1m7","residual vs x for staion 1 layer 1 module 7",100,-150,150,-0.1,0.1); + m_preXhistY_s1l1m7=new TProfile("XvsY_s1l1m7","residual vs x for staion 1 layer 1 module 7",100,-150,150,-0.1,0.1); + m_preYhistY_s1l1m7=new TProfile("YvsY_s1l1m7","residual vs x for staion 1 layer 1 module 7",100,-150,150,-0.1,0.1); CHECK(m_thistSvc->regTree("/TrackerSPFit/spfit",m_tree)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m0",m_preYhistX_s1l1m0)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m0",m_preXhistX_s1l1m0)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m0",m_preXhistY_s1l1m0)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m0",m_preYhistY_s1l1m0)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m1",m_preYhistX_s1l1m1)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m1",m_preXhistX_s1l1m1)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m1",m_preXhistY_s1l1m1)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m1",m_preYhistY_s1l1m1)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m2",m_preYhistX_s1l1m2)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m2",m_preXhistX_s1l1m2)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m2",m_preXhistY_s1l1m2)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m2",m_preYhistY_s1l1m2)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m3",m_preYhistX_s1l1m3)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m3",m_preXhistX_s1l1m3)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m3",m_preXhistY_s1l1m3)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m3",m_preYhistY_s1l1m3)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m4",m_preYhistX_s1l1m4)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m4",m_preXhistX_s1l1m4)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m4",m_preXhistY_s1l1m4)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m4",m_preYhistY_s1l1m4)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m5",m_preYhistX_s1l1m5)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m5",m_preXhistX_s1l1m5)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m5",m_preXhistY_s1l1m5)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m5",m_preYhistY_s1l1m5)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m6",m_preYhistX_s1l1m6)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m6",m_preXhistX_s1l1m6)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m6",m_preXhistY_s1l1m6)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m6",m_preYhistY_s1l1m6)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_x_s1l1m7",m_preYhistX_s1l1m7)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_x_s1l1m7",m_preXhistX_s1l1m7)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualX_y_s1l1m7",m_preXhistY_s1l1m7)); + CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_residualY_y_s1l1m7",m_preYhistY_s1l1m7)); CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_x",m_hist_x)); CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_y",m_hist_y)); CHECK(m_thistSvc->regHist("/TrackerSPFit/sp/sp_z",m_hist_z)); @@ -220,6 +323,7 @@ namespace Tracker m_tree->Branch("track_p2",&m_track_p2); m_tree->Branch("track_p3",&m_track_p3); if(m_saveallcluster){ + m_tree->Branch("cluster_all_identify",&m_cluster_all_identify); m_tree->Branch("cluster_all_local_x",&m_cluster_all_local_x); m_tree->Branch("cluster_all_local_y",&m_cluster_all_local_y); m_tree->Branch("cluster_global_x",&m_cluster_all_global_x); @@ -234,21 +338,26 @@ namespace Tracker m_tree->Branch("cluster_all_strip",&m_cluster_all_strip); } if(m_saveallsp){ + m_tree->Branch("sp_all_identify0", &m_sp_all_identify0); + m_tree->Branch("sp_all_identify1", &m_sp_all_identify1); + m_tree->Branch("sp_all_x_local", &m_sp_all_x_local); + m_tree->Branch("sp_all_y_local", &m_sp_all_y_local); m_tree->Branch("sp_all_x", &m_sp_all_x); m_tree->Branch("sp_all_y", &m_sp_all_y); m_tree->Branch("sp_all_z", &m_sp_all_z); m_tree->Branch("sp_all_station", &m_sp_all_station); m_tree->Branch("sp_all_layer", &m_sp_all_layer); m_tree->Branch("sp_all_module", &m_sp_all_module); -// if(m_saveallcluster){ -// m_tree->Branch("sp_all_clus1_index", &m_sp_all_clus1_index); -// m_tree->Branch("sp_all_clus2_index", &m_sp_all_clus2_index); -// } + // if(m_saveallcluster){ + // m_tree->Branch("sp_all_clus1_index", &m_sp_all_clus1_index); + // m_tree->Branch("sp_all_clus2_index", &m_sp_all_clus2_index); + // } } } //------------------------------------------------------------------------- void TrackerSPFit::clearVariables() const { if(m_saveallcluster){ + m_cluster_all_identify.clear(); m_cluster_all_local_x.clear(); m_cluster_all_local_y.clear(); m_cluster_all_global_x.clear(); @@ -263,13 +372,17 @@ namespace Tracker m_cluster_all_strip.clear(); } if(m_saveallsp){ + m_sp_all_identify0.clear(); + m_sp_all_identify1.clear(); + m_sp_all_x_local.clear(); + m_sp_all_y_local.clear(); m_sp_all_x.clear(); m_sp_all_y.clear(); m_sp_all_z.clear(); -// if(m_saveallcluster){ -// m_sp_all_clus1_index.clear(); -// m_sp_all_clus2_index.clear(); -// } + // if(m_saveallcluster){ + // m_sp_all_clus1_index.clear(); + // m_sp_all_clus2_index.clear(); + // } m_sp_all_station.clear(); m_sp_all_layer.clear(); m_sp_all_module.clear(); @@ -316,6 +429,12 @@ namespace Tracker return StatusCode::SUCCESS; } + + SG::WriteHandle<TrackerSeedCollection> seedContainer(m_trackerSeedContainerKey, ctx); + ATH_CHECK(seedContainer.record( std::make_unique<TrackerSeedCollection>() ) ); + ATH_MSG_DEBUG("Created track seed container " << m_trackerSeedContainerKey.key()); + + //read cluster SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> sct_clcontainer( m_Sct_clcontainerKey, ctx ); if ((!sct_clcontainer.isValid())&&m_saveallcluster){ @@ -332,40 +451,44 @@ namespace Tracker const Tracker::FaserSCT_ClusterCollection *colNext=&(**clusit); FaserSCT_ClusterCollection::const_iterator clusters {colNext->begin()} ; FaserSCT_ClusterCollection::const_iterator clustersEnd {colNext->end() }; + ATH_MSG_DEBUG("loop over all clusters " ); for (; clusters != clustersEnd; ++clusters) { ++m_numberOfCluster; const Tracker::FaserSCT_Cluster* clus=&(**clusters); m_cluster_all_global_x.push_back(clus->globalPosition().x()); - m_cluster_all_global_y.push_back(clus->globalPosition().y()); - m_cluster_all_global_z.push_back(clus->globalPosition().z()); - m_cluster_all_local_x.push_back(clus->localPosition().x()); - m_cluster_all_local_y.push_back(clus->localPosition().y()); - m_cluster_all_phiwidth.push_back(clus->width().phiR()); - Identifier elementID = clus->identify(); - m_cluster_all_station.push_back( m_idHelper->station(elementID)); - m_cluster_all_layer.push_back( m_idHelper->layer(elementID)); - int ietamodule = m_idHelper->eta_module(elementID); - int iphimodule = m_idHelper->phi_module(elementID); - if(ietamodule<0)iphimodule+=4; - m_cluster_all_module.push_back(iphimodule); - m_cluster_all_side.push_back(m_idHelper->side(elementID)); - m_cluster_all_strip.push_back(m_idHelper->strip(elementID)); - m_cluster_all_size.push_back(clus->rdoList().size()); - } - } + m_cluster_all_global_y.push_back(clus->globalPosition().y()); + m_cluster_all_global_z.push_back(clus->globalPosition().z()); + m_cluster_all_local_x.push_back(clus->localPosition().x()); + m_cluster_all_local_y.push_back(clus->localPosition().y()); + m_cluster_all_phiwidth.push_back(clus->width().phiR()); + Identifier elementID = clus->identify(); + m_cluster_all_station.push_back( m_idHelper->station(elementID)); + m_cluster_all_identify.push_back( elementID.get_compact()); + m_cluster_all_layer.push_back( m_idHelper->layer(elementID)); + int ietamodule = m_idHelper->eta_module(elementID); + int iphimodule = m_idHelper->phi_module(elementID); + if(ietamodule<0)iphimodule+=4; + m_cluster_all_module.push_back(iphimodule); + m_cluster_all_side.push_back(m_idHelper->side(elementID)); + m_cluster_all_strip.push_back(m_idHelper->strip(elementID)); + m_cluster_all_size.push_back(clus->rdoList().size()); + ATH_MSG_DEBUG("cluster found in station/layer/phi/etamodule "<<m_idHelper->station(elementID)<<"/"<<m_idHelper->layer(elementID)<<"/"<<ietamodule<<"/"<<iphimodule ); + } + } } // retrieve SCT spacepoint container - SG::ReadHandle<FaserSCT_SpacePointContainer> sct_spcontainer( m_Sct_spcontainerKey, ctx ); + SG::ReadHandle<FaserSCT_SpacePointContainer> sct_spcontainer{ m_Sct_spcontainerKey, ctx }; if (!sct_spcontainer.isValid()){ msg(MSG:: FATAL) << "Could not find the data object "<< sct_spcontainer.name() << " !" << endmsg; return StatusCode::RECOVERABLE; } // save all the sp information + int nsp_sta[4] = {0}; if(m_saveallsp){ ATH_MSG_DEBUG( "SCT spacepoint container found: " << sct_spcontainer->size() << " collections" ); FaserSCT_SpacePointContainer::const_iterator it = sct_spcontainer->begin(); @@ -373,30 +496,39 @@ namespace Tracker for (; it != itend; ++it){ ++m_numberOfSPCol; + ATH_MSG_DEBUG( "loop over spacepoint collection " << m_numberOfSPCol ); const FaserSCT_SpacePointCollection *colNext=&(**it); FaserSCT_SpacePointCollection::const_iterator sp_begin= colNext->begin(); FaserSCT_SpacePointCollection::const_iterator sp_end= colNext->end(); Identifier elementID = colNext->identify(); + ATH_MSG_DEBUG("loop over all spacepoint in collection with size = "<<colNext->size()); for (; sp_begin != sp_end; ++sp_begin){ ++m_numberOfSP; + ATH_MSG_DEBUG("reading "<<m_numberOfSP<<" Spacepoint at station "<<m_idHelper->station(elementID)); const Tracker::FaserSCT_SpacePoint* sp=&(**sp_begin); + m_sp_all_x_local.push_back(sp->localParameters().x()); + m_sp_all_y_local.push_back(sp->localParameters().y()); m_sp_all_x.push_back(sp->globalPosition().x()); m_sp_all_y.push_back(sp->globalPosition().y()); m_sp_all_z.push_back(sp->globalPosition().z()); m_sp_all_station.push_back(m_idHelper->station(elementID)); + nsp_sta[m_idHelper->station(elementID)] += 1; m_sp_all_layer.push_back(m_idHelper->layer(elementID)); + m_sp_all_identify0.push_back(sp->clusterList().first->identify().get_compact()); + m_sp_all_identify1.push_back(sp->clusterList().second->identify().get_compact()); int ietamodule = m_idHelper->eta_module(elementID); int iphimodule = m_idHelper->phi_module(elementID); if(ietamodule<0)iphimodule+=4; m_sp_all_module.push_back(iphimodule); + ATH_MSG_DEBUG( "SCT spacepoint found: " << sp->globalPosition().x()<<" , "<<sp->globalPosition().y()<<" , "<<sp->globalPosition().z()<<" , "<<m_idHelper->station(elementID)<<" , "<<m_idHelper->layer(elementID)<<" , "<<m_idHelper->eta_module(elementID)<<" , "<<m_idHelper->phi_module(elementID) ); /* to be updated - if(m_saveallcluster){ - const Tracker::FaserSCT_ClusterCollection *ptr1 = sct_clcontainer->indexFindPtr(sp->elemIDList().first()); - const Tracker::FaserSCT_ClusterCollection *ptr2 = sct_clcontainer->indexFindPtr(sp->elemIDList().second()); - m_sp_all_clus1_index.push_back(findClusterIndex(sp,ptr1)); - m_sp_all_clus2_index.push_back(findClusterIndex(sp,ptr2)); - } - */ + if(m_saveallcluster){ + const Tracker::FaserSCT_ClusterCollection *ptr1 = sct_clcontainer->indexFindPtr(sp->elemIDList().first()); + const Tracker::FaserSCT_ClusterCollection *ptr2 = sct_clcontainer->indexFindPtr(sp->elemIDList().second()); + m_sp_all_clus1_index.push_back(findClusterIndex(sp,ptr1)); + m_sp_all_clus2_index.push_back(findClusterIndex(sp,ptr2)); + } + */ } } } @@ -407,12 +539,13 @@ namespace Tracker FaserSCT_SpacePointContainer::const_iterator it = sct_spcontainer->begin(); FaserSCT_SpacePointContainer::const_iterator itend = sct_spcontainer->end(); - std::vector<SP_Seed> sp_sta0; - std::vector<SP_Seed> sp_sta1; - std::vector<SP_Seed> sp_sta2; - sp_sta0.clear(); - sp_sta1.clear(); - sp_sta2.clear(); + std::vector<std::vector<SP_Seed>> sp_sta; + sp_sta.resize(4); + sp_sta[0].resize(nsp_sta[0]); + sp_sta[1].resize(nsp_sta[1]); + sp_sta[2].resize(nsp_sta[2]); + sp_sta[3].resize(nsp_sta[3]); + int index_sp_sta[4] = {0}; for (; it != itend; ++it){ const FaserSCT_SpacePointCollection *colNext=&(**it); // int nReceivedSPSCT = colNext->size(); @@ -423,6 +556,7 @@ namespace Tracker ATH_MSG_VERBOSE("reading SpacePoints collection "<<elementID.get_compact()<<" , and hash = "<<colNext->identifyHash() ); int istation = m_idHelper->station(elementID); +// if(istation !=0) continue; int ilayer = m_idHelper->layer(elementID); int ietamodule = m_idHelper->eta_module(elementID); int iphimodule = m_idHelper->phi_module(elementID); @@ -444,160 +578,192 @@ namespace Tracker m_hist_eta->Fill(sp->eta()); m_hist_phi->Fill(sp->phi()); Amg::Vector3D gloPos=sp->globalPosition(); + if(gloPos.x()>150||gloPos.x()<-150||gloPos.y()>150||gloPos.y()<-150||gloPos.z()==0)continue; + if(sqrt(gloPos.x()*gloPos.x()+gloPos.y()*gloPos.y()+gloPos.z()*gloPos.z())<0.1)continue; m_hist_x->Fill(gloPos.x()); m_hist_y->Fill(gloPos.y()); m_hist_z->Fill(gloPos.z()); struct SP_Seed tmp{gloPos,sp->globCovariance(),ilayer,imodule}; - ATH_MSG_DEBUG( "TrackerSPFit algorithm found no space points" ); - if(istation==1) - sp_sta0.push_back(tmp); - else if(istation==2) - sp_sta1.push_back(tmp); - else - sp_sta2.push_back(tmp); - - if ( ((istation-1)*3+ilayer) == 0 ) m_hist_x_y_plane0->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 1 ) m_hist_x_y_plane1->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 2 ) m_hist_x_y_plane2->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 3 ) m_hist_x_y_plane3->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 4 ) m_hist_x_y_plane4->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 5 ) m_hist_x_y_plane5->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 6 ) m_hist_x_y_plane6->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 7 ) m_hist_x_y_plane7->Fill(gloPos.x(),gloPos.y()); - if ( ((istation-1)*3+ilayer) == 8 ) m_hist_x_y_plane8->Fill(gloPos.x(),gloPos.y()); + sp_sta[istation][index_sp_sta[istation]]=tmp; + index_sp_sta[istation] += 1; + + if ( ((istation)*3+ilayer) == 0 ) m_hist_x_y_plane0->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 1 ) m_hist_x_y_plane1->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 2 ) m_hist_x_y_plane2->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 3 ) m_hist_x_y_plane3->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 4 ) m_hist_x_y_plane4->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 5 ) m_hist_x_y_plane5->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 6 ) m_hist_x_y_plane6->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 7 ) m_hist_x_y_plane7->Fill(gloPos.x(),gloPos.y()); + if ( ((istation)*3+ilayer) == 8 ) m_hist_x_y_plane8->Fill(gloPos.x(),gloPos.y()); } ATH_MSG_VERBOSE( size << " SpacePoints successfully added to Container !" ); } } - ATH_MSG_INFO( "TrackerSPFit number of spacepoints in each stations: "<<sp_sta0.size()<<" "<<sp_sta1.size()<<" "<<sp_sta2.size() ); + ATH_MSG_INFO( "TrackerSPFit number of spacepoints in each stations: "<<sp_sta[0].size()<<" "<<sp_sta[1].size()<<" "<<sp_sta[2].size() ); bool ifTrack=false; - if(sp_sta0.size()>2&&sp_sta0.size()<100) { - auto tracks_sta0=makeTrackSeg(sp_sta0,m_maxchi2); - ATH_MSG_INFO( "TrackerSPFit found "<<tracks_sta0.size()<<" track segments in station 0 " ); - if(tracks_sta0.size()>0){ - ifTrack=true; - for(auto track:tracks_sta0){ - auto pre=track.predicted; - auto pos=track.pos; - ++m_numberOfTrack; - m_trackId.push_back(int(m_numberOfTrack/3)); - m_sp_track_x.push_back(pos.x()); - m_sp_track_y.push_back(pos.y()); - m_sp_track_z.push_back(pos.z()); - m_sp_track_x_err.push_back(track.err.x()); - m_sp_track_y_err.push_back(track.err.y()); - m_sp_track_z_err.push_back(track.err.z()); - m_sp_track_x_predicted.push_back(pre.x()); - m_sp_track_y_predicted.push_back(pre.y()); - m_sp_track_z_predicted.push_back(pre.z()); - m_sp_track_x_residual.push_back(pre.x()-pos.x()); - m_sp_track_y_residual.push_back(pre.y()-pos.y()); - m_sp_track_z_residual.push_back(pre.z()-pos.z()); - ATH_MSG_DEBUG(" fill the result "<<pre.x()<<" "<<pre.y()<<" "<<pre.z()<<" "<<pos.x()<<" "<<pos.y()<<" "<<pos.z()); - m_sp_track_station.push_back(0); - m_sp_track_layer.push_back(track.layer); - m_sp_track_module.push_back(track.module); + for(int ista=0;ista<4;ista++){ + if(sp_sta[ista].size()>1&&sp_sta[ista].size()<100) { + auto tracks_sta0=makeTrackSeg(sp_sta[ista],m_maxchi2); + ATH_MSG_INFO( "TrackerSPFit found "<<tracks_sta0.size()<<" track segments in station "<<ista ); + if(tracks_sta0.size()>0){ + ifTrack=true; + ATH_MSG_DEBUG( "TrackerSPFit fill the track info0 " ); + + //make TrackerSeed if(m_bias){ - m_track_chi2.push_back(track.chi2); - m_track_edm.push_back(track.edm); - m_track_ndf.push_back(track.ndf); - m_track_p0.push_back(track.p0); - m_track_p1.push_back(track.p1); - m_track_p2.push_back(track.p2); - m_track_p3.push_back(track.p3); + for(size_t iseed=0;iseed<tracks_sta0.size();iseed+=3){ + Tracker::TrackerSeed* trackerSeed = new Tracker::TrackerSeed(); + trackerSeed->setStation(ista); + trackerSeed->set_id(TrackerSeed::TRIPLET_SP); + double ndf=tracks_sta0[iseed].ndf; + double* param=new double[6]; + param[0] = tracks_sta0[iseed].p0; + param[1] = tracks_sta0[iseed].p1; + param[2] = tracks_sta0[iseed].p2; + param[3] = tracks_sta0[iseed].p3; + param[4] = tracks_sta0[iseed].chi2; + param[5] = ndf; + // double* param[] = {tracks_sta0[iseed].p0, tracks_sta0[iseed].p1, tracks_sta0[iseed].p2, tracks_sta0[iseed].p3, tracks_sta0[iseed].chi2, ndf}; + trackerSeed->setParameters(param); + std::vector<const Tracker::FaserSCT_SpacePoint*> spseed; + spseed.clear(); + spseed.emplace_back(findSpacePoint(&*sct_spcontainer, tracks_sta0[iseed].pos.x(), tracks_sta0[iseed].pos.y(), tracks_sta0[iseed].pos.z())); + spseed.emplace_back(findSpacePoint(&*sct_spcontainer, tracks_sta0[iseed+1].pos.x(), tracks_sta0[iseed+1].pos.y(), tracks_sta0[iseed+1].pos.z())); + spseed.emplace_back(findSpacePoint(&*sct_spcontainer, tracks_sta0[iseed+2].pos.x(), tracks_sta0[iseed+2].pos.y(), tracks_sta0[iseed+2].pos.z())); + trackerSeed->add(spseed); + seedContainer->push_back(trackerSeed); + } + } - if(track.layer==0){ m_residual_x_plane0->Fill(pre.x()-pos.x());m_residual_y_plane0->Fill(pre.y()-pos.y());} - if(track.layer==1){ m_residual_x_plane1->Fill(pre.x()-pos.x());m_residual_y_plane1->Fill(pre.y()-pos.y());} - if(track.layer==2){ m_residual_x_plane2->Fill(pre.x()-pos.x());m_residual_y_plane2->Fill(pre.y()-pos.y());} - } - } - } - if(sp_sta1.size()>2&&sp_sta1.size()<100) { - auto tracks_sta1=makeTrackSeg(sp_sta1,m_maxchi2); - ATH_MSG_INFO( "TrackerSPFit found "<<tracks_sta1.size()<<" track segments in station 1 " ); - if(tracks_sta1.size()>0){ - ifTrack=true; - for(auto track:tracks_sta1){ - auto pre=track.predicted; - auto pos=track.pos; - ++m_numberOfTrack; - m_trackId.push_back(int(m_numberOfTrack/3)); - m_sp_track_x.push_back(pos.x()); - m_sp_track_y.push_back(pos.y()); - m_sp_track_z.push_back(pos.z()); - m_sp_track_x_err.push_back(track.err.x()); - m_sp_track_y_err.push_back(track.err.y()); - m_sp_track_z_err.push_back(track.err.z()); - m_sp_track_x_predicted.push_back(pre.x()); - m_sp_track_y_predicted.push_back(pre.y()); - m_sp_track_z_predicted.push_back(pre.z()); - m_sp_track_x_residual.push_back(pre.x()-pos.x()); - m_sp_track_y_residual.push_back(pre.y()-pos.y()); - m_sp_track_z_residual.push_back(pre.z()-pos.z()); - m_sp_track_station.push_back(1); - m_sp_track_layer.push_back(track.layer); - m_sp_track_module.push_back(track.module); - if(m_bias){ - m_track_chi2.push_back(track.chi2); - m_track_edm.push_back(track.edm); - m_track_ndf.push_back(track.ndf); - m_track_p0.push_back(track.p0); - m_track_p1.push_back(track.p1); - m_track_p2.push_back(track.p2); - m_track_p3.push_back(track.p3); + + for(auto track:tracks_sta0){ + auto pre=track.predicted; + auto pos=track.pos; + ++m_numberOfTrack; + m_trackId.push_back(int(m_numberOfTrack/3)); + m_sp_track_x.push_back(pos.x()); + m_sp_track_y.push_back(pos.y()); + m_sp_track_z.push_back(pos.z()); + m_sp_track_x_err.push_back(track.err.x()); + m_sp_track_y_err.push_back(track.err.y()); + m_sp_track_z_err.push_back(track.err.z()); + m_sp_track_x_predicted.push_back(pre.x()); + m_sp_track_y_predicted.push_back(pre.y()); + m_sp_track_z_predicted.push_back(pre.z()); + m_sp_track_x_residual.push_back(pre.x()-pos.x()); + m_sp_track_y_residual.push_back(pre.y()-pos.y()); + m_sp_track_z_residual.push_back(pre.z()-pos.z()); + ATH_MSG_DEBUG(" fill the result "<<pre.x()<<" "<<pre.y()<<" "<<pre.z()<<" "<<pos.x()<<" "<<pos.y()<<" "<<pos.z()); + ATH_MSG_DEBUG(" Station/layer/module = "<<ista<<"/"<<track.layer<<"/"<<track.module<<" , and track ID "<<m_numberOfTrack/3); + m_sp_track_station.push_back(0); + m_sp_track_layer.push_back(track.layer); + m_sp_track_module.push_back(track.module); + + if(m_bias){ + m_track_chi2.push_back(track.chi2); + m_track_edm.push_back(track.edm); + m_track_ndf.push_back(track.ndf); + m_track_p0.push_back(track.p0); + m_track_p1.push_back(track.p1); + m_track_p2.push_back(track.p2); + m_track_p3.push_back(track.p3); + + } + if(track.layer==0){ m_residual_x_plane0->Fill(pre.x()-pos.x());m_residual_y_plane0->Fill(pre.y()-pos.y());} + if(track.layer==1){ m_residual_x_plane1->Fill(pre.x()-pos.x());m_residual_y_plane1->Fill(pre.y()-pos.y());} + if(track.layer==2){ m_residual_x_plane2->Fill(pre.x()-pos.x());m_residual_y_plane2->Fill(pre.y()-pos.y());} + if(track.layer==1){ + ATH_MSG_DEBUG(" only fill the layer 1, module = "<<track.module); + ATH_MSG_DEBUG(" measured = "<<pos.x()<<" , "<<pos.y()<<" , "<<pos.z()); + ATH_MSG_DEBUG(" predicted = "<<pre.x()<<" , "<<pre.y()<<" , "<<pre.z()); + if(track.module==0){ + m_preYhistX_s1l1m0->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m0->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m0->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m0->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==1){ + m_preYhistX_s1l1m1->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m1->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m1->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m1->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==2){ + m_preYhistX_s1l1m2->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m2->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m2->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m2->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==3){ + m_preYhistX_s1l1m3->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m3->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m3->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m3->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==4){ + m_preYhistX_s1l1m4->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m4->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m4->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m4->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==5){ + m_preYhistX_s1l1m5->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m5->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m5->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m5->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==6){ + m_preYhistX_s1l1m6->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m6->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m6->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m6->Fill(pos.y(),pos.x()-pre.x()); + } + if(track.module==7){ + m_preYhistX_s1l1m7->Fill(pos.x(),pos.y()-pre.y()); + m_preYhistY_s1l1m7->Fill(pos.y(),pos.y()-pre.y()); + m_preXhistX_s1l1m7->Fill(pos.x(),pos.x()-pre.x()); + m_preXhistY_s1l1m7->Fill(pos.y(),pos.x()-pre.x()); + } + } } - if(track.layer==0){ m_residual_x_plane3->Fill(pre.x()-pos.x());m_residual_y_plane3->Fill(pre.y()-pos.y());} - if(track.layer==1){ m_residual_x_plane4->Fill(pre.x()-pos.x());m_residual_y_plane4->Fill(pre.y()-pos.y());} - if(track.layer==2){ m_residual_x_plane5->Fill(pre.x()-pos.x());m_residual_y_plane5->Fill(pre.y()-pos.y());} } - } - } - if(sp_sta2.size()>2&&sp_sta2.size()<100) { - auto tracks_sta2=makeTrackSeg(sp_sta2,m_maxchi2); - ATH_MSG_INFO( "TrackerSPFit found "<<tracks_sta2.size()<<" track segments in station 2 " ); - if(tracks_sta2.size()>0){ - ifTrack=true; - for(auto track:tracks_sta2){ - auto pre=track.predicted; - auto pos=track.pos; - ++m_numberOfTrack; - m_trackId.push_back(int(m_numberOfTrack/3)); - m_sp_track_x.push_back(pos.x()); - m_sp_track_y.push_back(pos.y()); - m_sp_track_z.push_back(pos.z()); - m_sp_track_x_err.push_back(track.err.x()); - m_sp_track_y_err.push_back(track.err.y()); - m_sp_track_z_err.push_back(track.err.z()); - m_sp_track_x_predicted.push_back(pre.x()); - m_sp_track_y_predicted.push_back(pre.y()); - m_sp_track_z_predicted.push_back(pre.z()); - m_sp_track_x_residual.push_back(pre.x()-pos.x()); - m_sp_track_y_residual.push_back(pre.y()-pos.y()); - m_sp_track_z_residual.push_back(pre.z()-pos.z()); - m_sp_track_station.push_back(2); - m_sp_track_layer.push_back(track.layer); - m_sp_track_module.push_back(track.module); - if(m_bias){ - m_track_chi2.push_back(track.chi2); - m_track_edm.push_back(track.edm); - m_track_ndf.push_back(track.ndf); - m_track_p0.push_back(track.p0); - m_track_p1.push_back(track.p1); - m_track_p2.push_back(track.p2); - m_track_p3.push_back(track.p3); + else if(m_doublets){ + for(unsigned int isp=0;isp<sp_sta[ista].size()-1;isp++){ + for(unsigned int jsp=isp+1;jsp<sp_sta[ista].size();jsp++){ + if(sp_sta[ista][isp].layer != sp_sta[ista][jsp].layer){ + Tracker::TrackerSeed* trackerSeed = new Tracker::TrackerSeed(); + trackerSeed->setStation(ista); + trackerSeed->set_id(TrackerSeed::DOUBLET_SP); + double* param = new double[6]; + double tmp_x_slope = (sp_sta[ista][jsp].pos.x()-sp_sta[ista][isp].pos.x())/(sp_sta[ista][jsp].pos.z()-sp_sta[ista][isp].pos.z()); + double tmp_x_offset = sp_sta[ista][isp].pos.x()-sp_sta[ista][isp].pos.x()*tmp_x_slope; + double tmp_y_slope = (sp_sta[ista][jsp].pos.y()-sp_sta[ista][isp].pos.y())/(sp_sta[ista][jsp].pos.z()-sp_sta[ista][isp].pos.z()); + double tmp_y_offset = sp_sta[ista][isp].pos.y()-sp_sta[ista][isp].pos.z()*tmp_y_slope; + param[0] = tmp_x_offset; + param[1] = tmp_x_slope; + param[2] = tmp_y_offset; + param[3] = tmp_y_slope; + param[4] = -999; + param[5] = -999; + trackerSeed->setParameters(param); + std::vector<const Tracker::FaserSCT_SpacePoint*> spseed; + spseed.clear(); + spseed.emplace_back(findSpacePoint(&*sct_spcontainer, sp_sta[ista][isp].pos.x(), sp_sta[ista][isp].pos.y(), sp_sta[ista][isp].pos.z())); + spseed.emplace_back(findSpacePoint(&*sct_spcontainer, sp_sta[ista][jsp].pos.x(), sp_sta[ista][jsp].pos.y(), sp_sta[ista][jsp].pos.z())); + trackerSeed->add(spseed); + seedContainer->push_back(trackerSeed); + } + } } - if(track.layer==0){ m_residual_x_plane6->Fill(pre.x()-pos.x());m_residual_y_plane6->Fill(pre.y()-pos.y());} - if(track.layer==1){ m_residual_x_plane7->Fill(pre.x()-pos.x());m_residual_y_plane7->Fill(pre.y()-pos.y());} - if(track.layer==2){ m_residual_x_plane8->Fill(pre.x()-pos.x());m_residual_y_plane8->Fill(pre.y()-pos.y());} } } } - if(ifTrack) - m_tree->Fill(); - else if(m_saveallcluster||m_saveallsp) + if(ifTrack||m_saveallcluster||m_saveallsp) m_tree->Fill(); + return StatusCode::SUCCESS; } @@ -610,6 +776,26 @@ namespace Tracker ATH_MSG_INFO( m_numberOfCluster<< " sct Cluster processed" ); ATH_MSG_INFO( m_numberOfSPCol<< " sct SP collections processed" ); ATH_MSG_INFO( m_numberOfSP<< " sct SP processed" ); + + + //do a fitting + TF1* fpol1=new TF1("fpol1","pol1(0)"); + m_preYhistX_s1l1m0->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 0 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m1->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 1 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m2->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 2 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m3->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 3 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m4->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 4 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m5->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 5 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m6->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 6 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); + m_preYhistX_s1l1m7->Fit(fpol1); + ATH_MSG_INFO("Fitting the residualY vs X for module 7 : parameter = "<<fpol1->GetParameter(0)<<" "<<fpol1->GetParameter(1)); return StatusCode::SUCCESS; } @@ -630,15 +816,17 @@ namespace Tracker for(unsigned int i0=0;i0<layer0.size();i0++){ for(unsigned int i1=0;i1<layer1.size();i1++){ for(unsigned int i2=0;i2<layer2.size();i2++){ - if(m_bias){ - //for biased residual - auto tmp=makeTrackSeg(layer0[i0],layer1[i1],layer2[i2],maxchi2); - tracks.insert(tracks.end(),tmp.begin(),tmp.end()); - } - else{ - //for un-biased residual - auto tmp=makeTrackSeg(layer0[i0],layer1[i1],layer2[i2]); - tracks.insert(tracks.end(),tmp.begin(),tmp.end()); + auto tmp_bias=makeTrackSeg(layer0[i0],layer1[i1],layer2[i2],maxchi2); + if(tmp_bias.size()>0){ + if(m_bias){ + //for biased residual + tracks.insert(tracks.end(),tmp_bias.begin(),tmp_bias.end()); + } + else{ + //for un-biased residual + auto tmp=makeTrackSeg(layer0[i0],layer1[i1],layer2[i2]); + tracks.insert(tracks.end(),tmp.begin(),tmp.end()); + } } } } @@ -716,7 +904,6 @@ namespace Tracker m_ndf->Fill(ndf); if(chi2<maxchi2){ -// result.Print(std::cout); const double *fitParam=result.GetParams(); ATH_MSG_DEBUG(" fit status: ook "<<chi2<<" "<<edm<<" "<<ndf<<" "<<fitParam[0]<<" "<<fitParam[1]<<" "<<fitParam[2]<<" "<<fitParam[3]); Amg::Vector3D err0(sqrt((sp0.cov)(0,0)),sqrt((sp0.cov)(1,1)),sqrt((sp0.cov)(2,2))); @@ -738,20 +925,37 @@ namespace Tracker return Amg::Vector3D(p[0]+p[1]*z,p[2]+p[3]*z,z); } - /* - * need to be updated - int TrackerSPFit::findClusterIndex(const Tracker::FaserSCT_SpacePoint* sp, const Tracker::FaserSCT_ClusterCollection* ptr)const { - if (ptr!=nullptr) { - //loop though collection to find matching PRD. - Tracker::FaserSCT_ClusterCollection::const_iterator collIt = ptr->begin(); - Tracker::FaserSCT_ClusterCollection::const_iterator collItEnd = ptr->end(); - for ( ; collIt!=collItEnd; collIt++) { - if ( (*collIt)->identify()==id1 ) - clus1= &(**collIt); + const FaserSCT_SpacePoint* TrackerSPFit::findSpacePoint(const FaserSCT_SpacePointContainer* spcontainer, double x, double y, double z) const{ + FaserSCT_SpacePointContainer::const_iterator it = spcontainer->begin(); + FaserSCT_SpacePointContainer::const_iterator itend = spcontainer->end(); + + for (; it != itend; ++it){ + const FaserSCT_SpacePointCollection *colNext=&(**it); + FaserSCT_SpacePointCollection::const_iterator sp_begin= colNext->begin(); + FaserSCT_SpacePointCollection::const_iterator sp_end= colNext->end(); + Identifier elementID = colNext->identify(); + for (; sp_begin != sp_end; ++sp_begin){ + const FaserSCT_SpacePoint* sp=&(**sp_begin); + if(pow(sp->globalPosition().x()-x,2)+pow(sp->globalPosition().y()-y,2)+pow(sp->globalPosition().z()-z,2)<0.001)return sp; } } - + return nullptr; } - */ + + /* + * need to be updated + int TrackerSPFit::findClusterIndex(const Tracker::FaserSCT_SpacePoint* sp, const Tracker::FaserSCT_ClusterCollection* ptr)const { + if (ptr!=nullptr) { +//loop though collection to find matching PRD. +Tracker::FaserSCT_ClusterCollection::const_iterator collIt = ptr->begin(); +Tracker::FaserSCT_ClusterCollection::const_iterator collItEnd = ptr->end(); +for ( ; collIt!=collItEnd; collIt++) { +if ( (*collIt)->identify()==id1 ) +clus1= &(**collIt); +} +} + +} +*/ } diff --git a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.h b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.h index ae76af9941ae8b6b6480699108d0ebf48b1125b7..40c06ec40161806f755bde01155382f15943574f 100755 --- a/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.h +++ b/Tracker/TrackerRecAlgs/TrackerSPFit/src/TrackerSPFit.h @@ -18,6 +18,8 @@ #include "TrackerSpacePoint/FaserSCT_SpacePoint.h" #include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" #include "TrackerSpacePoint/FaserSCT_SpacePointOverlapCollection.h" +#include "TrackerSpacePoint/TrackerSeedCollection.h" +#include "TrackerSpacePoint/TrackerSeed.h" #include "TrkEventPrimitives/LocalParameters.h" #include "GaudiKernel/ServiceHandle.h" @@ -27,6 +29,7 @@ #include <vector> #include "TH1.h" #include "TH2.h" +#include "TF1.h" #include "TTree.h" #include "TGraph2DErrors.h" #include "TMath.h" @@ -111,6 +114,8 @@ namespace Tracker SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_Sct_clcontainerKey{this, "SCT_ClustersName", "SCT clContainer"}; SG::ReadCondHandleKey<TrackerDD::SiDetectorElementCollection> m_SCTDetEleCollKey{this, "SCTDetEleCollKey", "SCT_DetectorElementCollection", "Key of SiDetectorElementCollection for SCT"}; + SG::WriteHandleKey<Tracker::TrackerSeedCollection> m_trackerSeedContainerKey{this, "FaserTrackerSeedName", "FaserTrackerSeedCollection" }; + const Tracker::FaserSCT_SpacePoint* findSpacePoint(const FaserSCT_SpacePointContainer* spcontainer, double x, double y, double z) const; const FaserSCT_ID* m_idHelper{nullptr}; mutable std::atomic<int> m_numberOfEvents{0}; @@ -161,6 +166,39 @@ namespace Tracker TH1* m_edm; TH1* m_ndf; ServiceHandle<ITHistSvc> m_thistSvc; + //for alignment constants + TProfile* m_preYhistX_s1l1m0; + TProfile* m_preYhistY_s1l1m0; + TProfile* m_preXhistX_s1l1m0; + TProfile* m_preXhistY_s1l1m0; + TProfile* m_preYhistX_s1l1m1; + TProfile* m_preYhistY_s1l1m1; + TProfile* m_preXhistX_s1l1m1; + TProfile* m_preXhistY_s1l1m1; + TProfile* m_preYhistX_s1l1m2; + TProfile* m_preYhistY_s1l1m2; + TProfile* m_preXhistX_s1l1m2; + TProfile* m_preXhistY_s1l1m2; + TProfile* m_preYhistX_s1l1m3; + TProfile* m_preYhistY_s1l1m3; + TProfile* m_preXhistX_s1l1m3; + TProfile* m_preXhistY_s1l1m3; + TProfile* m_preYhistX_s1l1m4; + TProfile* m_preYhistY_s1l1m4; + TProfile* m_preXhistX_s1l1m4; + TProfile* m_preXhistY_s1l1m4; + TProfile* m_preYhistX_s1l1m5; + TProfile* m_preYhistY_s1l1m5; + TProfile* m_preXhistX_s1l1m5; + TProfile* m_preXhistY_s1l1m5; + TProfile* m_preYhistX_s1l1m6; + TProfile* m_preYhistY_s1l1m6; + TProfile* m_preXhistX_s1l1m6; + TProfile* m_preXhistY_s1l1m6; + TProfile* m_preYhistX_s1l1m7; + TProfile* m_preYhistY_s1l1m7; + TProfile* m_preXhistX_s1l1m7; + TProfile* m_preXhistY_s1l1m7; mutable int m_eventNumber; mutable std::vector<double> m_sp_track_x; @@ -195,6 +233,7 @@ namespace Tracker mutable std::vector<double> m_cluster_all_local_x; mutable std::vector<double> m_cluster_all_local_y; mutable std::vector<double> m_cluster_all_phiwidth; + mutable std::vector<long long int> m_cluster_all_identify; mutable std::vector<int> m_cluster_all_size; mutable std::vector<int> m_cluster_all_station; mutable std::vector<int> m_cluster_all_layer; @@ -202,12 +241,17 @@ namespace Tracker mutable std::vector<int> m_cluster_all_side; mutable std::vector<int> m_cluster_all_strip; bool m_saveallsp; + mutable std::vector<double> m_sp_all_x_local; + mutable std::vector<double> m_sp_all_y_local; mutable std::vector<double> m_sp_all_x; mutable std::vector<double> m_sp_all_y; mutable std::vector<double> m_sp_all_z; mutable std::vector<int> m_sp_all_station; mutable std::vector<int> m_sp_all_layer; mutable std::vector<int> m_sp_all_module; + mutable std::vector<long long int> m_sp_all_identify0; + mutable std::vector<long long int> m_sp_all_identify1; + bool m_doublets; }; 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 26a36c20aa356dbf531e338d9596ecf744be0d00..ce2bb8484380954bef92acedff4efc3aa7107f55 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/TrackerSegmentFit/test/TrackerSegmentFitDbg.py b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/TrackerSegmentFitDbg.py index fa1a4a5377d702716a4d9ccfa8e62348898b9ab5..75c46defbbb45d3c815f9d11e0091c83836a6e1e 100644 --- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/TrackerSegmentFitDbg.py +++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/TrackerSegmentFitDbg.py @@ -14,7 +14,7 @@ from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg #from Digitization.DigitizationParametersConfig import writeDigitizationMetadata -from ScintRecAlgs.ScintRecAlgsConfig import WaveformReconstructionCfg +from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg @@ -26,14 +26,14 @@ Configurable.configurableRun3Behavior = True # Configure ConfigFlags.Input.Files = [ - '/eos/project-f/faser-commissioning/TI12Data/Run-001332/Faser-Physics-001332-00000.raw', + '/eos/project-f/faser-commissioning/TI12Data/Run-005684/Faser-Physics-005684-00000.raw', ] -ConfigFlags.Output.ESDFileName = "run001332.ESD.pool.root" -ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion +ConfigFlags.Output.ESDFileName = "run005684-00000.ESD.pool.root" +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion 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.GeoModel.FaserVersion = "FASER-02" # FASER geometry ConfigFlags.Common.isOnline = False ConfigFlags.GeoModel.Align.Dynamic = False ConfigFlags.Beam.NumberOfCollisions = 0. @@ -59,20 +59,27 @@ acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) # explicitly save RDO information from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg -itemList = [ "xAOD::EventInfo#*", - "xAOD::EventAuxInfo#*", - "FaserSCT_RDO_Container#*", - "xAOD::FaserTriggerData#*", - "xAOD::FaserTriggerDataAux#*", - "ScintWaveformContainer#*", - "TrackCollection#*", - "xAOD::WaveformHitContainer#*", - "xAOD::WaveformHitAuxContainer#*", - "xAOD::WaveformClock#*", - "xAOD::WaveformClockAuxInfo#*", - ] +itemList = [ "xAOD::EventInfo#*" + , "xAOD::EventAuxInfo#*" + , "xAOD::FaserTriggerData#*" + , "xAOD::FaserTriggerDataAux#*" + , "FaserSCT_RDO_Container#*" + , "Tracker::FaserSCT_ClusterContainer#*" + , "TrackCollection#*" +] acc.merge(OutputStreamCfg(ConfigFlags, "ESD", itemList)) -acc.getEventAlgo("OutputStreamESD").AcceptAlgs = ["Tracker::SegmentFitAlg"] + +# Waveform reconstruction +from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionOutputCfg +acc.merge(WaveformReconstructionOutputCfg(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 + # Timing #acc.merge(MergeRecoTimingObjCfg(ConfigFlags)) 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/Tracker/TrackerRecEvent/TrackerRIO_OnTrack/src/FaserSCT_ClusterOnTrack.cxx b/Tracker/TrackerRecEvent/TrackerRIO_OnTrack/src/FaserSCT_ClusterOnTrack.cxx index 5567e5cf9ab507ce8e7f076917055adef219e8e8..ba438dd9eef7845724e259b0a2e387a598df548b 100644 --- a/Tracker/TrackerRecEvent/TrackerRIO_OnTrack/src/FaserSCT_ClusterOnTrack.cxx +++ b/Tracker/TrackerRecEvent/TrackerRIO_OnTrack/src/FaserSCT_ClusterOnTrack.cxx @@ -87,8 +87,10 @@ const Trk::Surface& Tracker::FaserSCT_ClusterOnTrack::associatedSurface() const return ( detectorElement()->surface()); } -void Tracker::FaserSCT_ClusterOnTrack::setValues(const Trk::TrkDetElementBase* detEl, const Trk::PrepRawData* ) +void Tracker::FaserSCT_ClusterOnTrack::setValues(const Trk::TrkDetElementBase* detEl, const Trk::PrepRawData* prepRawData) { + const auto *cluster = dynamic_cast<const Tracker::FaserSCT_Cluster*>(prepRawData); + m_rio.setElement(cluster); m_detEl = dynamic_cast< const TrackerDD::SiDetectorElement* >(detEl); if (m_detEl) { // Set global position after setting the detector element diff --git a/Tracker/TrackerRecEvent/TrackerSpacePoint/TrackerSpacePoint/TrackerSeed.h b/Tracker/TrackerRecEvent/TrackerSpacePoint/TrackerSpacePoint/TrackerSeed.h index 80983149d647e9f5e41ec0c330a1e73ca78c8c43..dea1aa9581c58c38d90fe0aa9d113c9e38f266fd 100755 --- a/Tracker/TrackerRecEvent/TrackerSpacePoint/TrackerSpacePoint/TrackerSeed.h +++ b/Tracker/TrackerRecEvent/TrackerSpacePoint/TrackerSpacePoint/TrackerSeed.h @@ -15,13 +15,13 @@ namespace Tracker { public: - enum StrategyId{NULLID=0, TRIPLET_SP_FIRSTSTATION=1}; + enum StrategyId{NULLID=0, TRIPLET_SP_FIRSTSTATION=1, TRIPLET_SP=2, DOUBLET_SP=3};//, DOUBLET=2}; TrackerSeed(); TrackerSeed(const StrategyId, const TrackerSeed &); virtual ~TrackerSeed(); - TrackerSeed(const StrategyId, vector<const FaserSCT_SpacePoint*> seed); + TrackerSeed(const StrategyId, vector<const FaserSCT_SpacePoint*> seed, int stationId= 1 , double* param=0); void set_id(const StrategyId id) { m_strategyId = id; } StrategyId id() const { return m_strategyId; } @@ -30,6 +30,10 @@ namespace Tracker { vector<const FaserSCT_SpacePoint*> getSpacePoints() const {return m_seed;}; int size() const; + double* getParameters() const{return m_param;}; + int getStation() const{return m_stationId;}; + void setParameters(double* param); + void setStation(int station); TrackerSeed &operator=(const TrackerSeed &); @@ -40,6 +44,8 @@ namespace Tracker { StrategyId m_strategyId; vector<const FaserSCT_SpacePoint*> m_seed; + double* m_param; + int m_stationId; }; diff --git a/Tracker/TrackerRecEvent/TrackerSpacePoint/src/TrackerSeed.cxx b/Tracker/TrackerRecEvent/TrackerSpacePoint/src/TrackerSeed.cxx index 2e0f255193cc27af7b4f7b1ba76f36154f1d1faf..5d9f9e3bacd7655fcdae823019de6a5c0bd82730 100755 --- a/Tracker/TrackerRecEvent/TrackerSpacePoint/src/TrackerSeed.cxx +++ b/Tracker/TrackerRecEvent/TrackerSpacePoint/src/TrackerSeed.cxx @@ -4,32 +4,38 @@ namespace Tracker { TrackerSeed::TrackerSeed() : m_strategyId(NULLID) {} - TrackerSeed::TrackerSeed(const StrategyId id, const TrackerSeed& trackerSeed) : m_strategyId(id), m_seed(trackerSeed.m_seed) {} + TrackerSeed::TrackerSeed(const StrategyId id, const TrackerSeed& trackerSeed) : m_strategyId(id), m_seed(trackerSeed.m_seed), m_param(trackerSeed.m_param), m_stationId(trackerSeed.m_stationId) {} TrackerSeed::~TrackerSeed() {} - TrackerSeed::TrackerSeed(const StrategyId id, vector<const FaserSCT_SpacePoint*> seed) { m_strategyId = id; m_seed = seed; } + TrackerSeed::TrackerSeed(const StrategyId id, vector<const FaserSCT_SpacePoint*> seed, int stationId, double* param) { m_strategyId = id; m_seed = seed; m_param = param; m_stationId = stationId; } void TrackerSeed::add(vector<const FaserSCT_SpacePoint*> seed) { m_seed = seed; } int TrackerSeed::size() const { return m_seed.size(); } + void TrackerSeed::setParameters(double* param) { m_param = param; } + + void TrackerSeed::setStation(int station) { m_stationId= station; } + TrackerSeed& TrackerSeed::operator=(const TrackerSeed& trackSeed){ if(&trackSeed != this) { TrackerSeed::operator=(trackSeed); m_seed = trackSeed.m_seed; + m_param = trackSeed.m_param; + m_stationId = trackSeed.m_stationId; } return *this; } MsgStream& TrackerSeed::dump(MsgStream& stream) const { - stream << "TrackerSeed object" << endl; + stream << "TrackerSeed object at station " <<m_stationId<< " with strategy = "<<m_strategyId<< endl; this->TrackerSeed::dump(stream); return stream; } ostream& TrackerSeed::dump(ostream& stream) const { - stream << "TrackerSeed object" << endl; + stream << "TrackerSeed object at station " <<m_stationId<< " with strategy = "<<m_strategyId<< endl; this->TrackerSeed::dump(stream); return stream; } diff --git a/Tracker/TrackerRecTools/FaserSiClusterizationTool/CMakeLists.txt b/Tracker/TrackerRecTools/FaserSiClusterizationTool/CMakeLists.txt index 3e22c8a99050cf977d76fc3c7dd21c482188fc41..00988a7c35f348a6bc624b5faa248ea917d8c161 100644 --- a/Tracker/TrackerRecTools/FaserSiClusterizationTool/CMakeLists.txt +++ b/Tracker/TrackerRecTools/FaserSiClusterizationTool/CMakeLists.txt @@ -19,7 +19,7 @@ atlas_add_library( FaserSiClusterizationToolLib LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps AthenaKernel GeoPrimitives Identifier EventPrimitives GaudiKernel TrackerSimData TrackerIdentifier TrackerReadoutGeometry TrackerRawData TrackerPrepRawData - TrkParameters CxxUtils + TrkParameters CxxUtils FaserSCT_ConditionsToolsLib PRIVATE_LINK_LIBRARIES ${CLHEP_LIBRARIES} AthenaPoolUtilities FileCatalog FaserDetDescr TrkSurfaces TrkEventPrimitives ) diff --git a/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.cxx b/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.cxx index 2963d98dfdb966c92bf9541052bfe9d0e256b654..d034c3c15d008def9a2bb954674f532e329da74a 100644 --- a/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.cxx +++ b/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.cxx @@ -123,13 +123,13 @@ namespace Tracker ATH_CHECK(m_clusterMaker.retrieve()); -// if (m_checkBadChannels) { -// ATH_MSG_INFO("Clustering has been asked to look at bad channel info"); -// ATH_CHECK(m_conditionsTool.retrieve()); -// } else { -// m_conditionsTool.disable(); -// } - + if (m_checkBadChannels) { + ATH_MSG_INFO("Clustering has been asked to look at bad channel info"); + ATH_CHECK(m_conditionsTool.retrieve()); + } else { + m_conditionsTool.disable(); + } + if (m_doNewClustering and not m_lorentzAngleTool.empty()) { ATH_CHECK(m_lorentzAngleTool.retrieve()); } else { @@ -522,12 +522,12 @@ namespace Tracker unsigned int nBadStrips(0); for (unsigned int sn=thisStrip; sn!=thisStrip+nStrips; ++sn) { Identifier stripId = m_useRowInformation ? idHelper.strip_id(waferId,thisRow,sn) : idHelper.strip_id(waferId,sn); -// if (m_conditionsTool->isGood(stripId, InDetConditions::SCT_STRIP)) { + if (m_conditionsTool->isGood(stripId, InDetConditions::SCT_STRIP)) { currentVector.push_back(stripId); -// } else { -// currentVector.push_back(badId); -// ++nBadStrips; -// } + } else { + currentVector.push_back(badId); + ++nBadStrips; + } if (stripCount < 16) { hitsInThirdTimeBin = hitsInThirdTimeBin | (timePattern.test(0) << stripCount); } diff --git a/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.h b/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.h index 94a307a69bb6b79d1dbbe898039febf61f3150c0..0c56c468d21251e1b71b237c0591685244ff7b38 100644 --- a/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.h +++ b/Tracker/TrackerRecTools/FaserSiClusterizationTool/src/FaserSCT_ClusteringTool.h @@ -13,6 +13,7 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "Identifier/Identifier.h" //#include "FaserSCT_ConditionsTools/ISCT_DCSConditionsTool.h" +#include "FaserSCT_ConditionsTools/ISCT_ConditionsSummaryTool.h" #include "InDetCondTools/ISiLorentzAngleTool.h" #include "TrackerReadoutGeometry/SiDetectorElementCollection.h" #include "FaserSiClusterizationTool/IFaserSCT_ClusteringTool.h" @@ -70,6 +71,7 @@ namespace Tracker // ToolHandle<ISCT_DCSConditionsTool> m_conditionsTool{this, "FaserSCT_DCSConditionsTool", "FaserSCT_ConditionsTools", "Tool to retrieve SCT Conditions summary"}; const FaserSCT_ID* m_pHelper; //!< ID helper for FaserSCT + ToolHandle<ISCT_ConditionsSummaryTool> m_conditionsTool{this, "conditionsTool", "FaserSCT_ConditionsTools/FaserSCT_ConditionsSummaryTool", "Tool to retrieve SCT Conditions summary"}; ToolHandle< TrackerClusterMakerTool > m_clusterMaker{this, "globalPosAlg", "TrackerClusterMakerTool"}; ToolHandle<ISiLorentzAngleTool> m_lorentzAngleTool {this, "FaserSiLorentzAngleTool", "FaserSiLorentzAngleTool", "Tool to retreive Lorentz angle of SCT"}; @@ -130,9 +132,8 @@ namespace Tracker // Inline methods /////////////////////////////////////////////////////////////////// - inline bool FaserSCT_ClusteringTool::isBad(const Identifier& ) const { - return false; - // return (not m_conditionsTool->isGood(stripId, InDetConditions::SCT_STRIP)); + inline bool FaserSCT_ClusteringTool::isBad(const Identifier& stripId) const { + return (not m_conditionsTool->isGood(stripId, InDetConditions::SCT_STRIP)); } inline bool FaserSCT_ClusteringTool::testTimeBinsN(const std::bitset<3>& timePattern) const { diff --git a/Tracker/TrackerSimEvent/src/FaserSiHit.cxx b/Tracker/TrackerSimEvent/src/FaserSiHit.cxx index 80b632ff9d3b39838d48f60c998642dafa56510e..9fa64b3d5c8650318a0d56d4233e4173b1b83644 100644 --- a/Tracker/TrackerSimEvent/src/FaserSiHit.cxx +++ b/Tracker/TrackerSimEvent/src/FaserSiHit.cxx @@ -167,6 +167,17 @@ void FaserSiHit::print() const { std::cout << " Row Number " << getRow() << std::endl; std::cout << " Module Number " << getModule() << std::endl; std::cout << " Sensor " << getSensor() << std::endl; + std::cout << " Energy (MeV) " << energyLoss() << std::endl; + if (particleLink().isValid()) + { + std::cout << " Barcode " << particleLink().barcode() << std::endl; + const HepMC::GenParticle* particle = (particleLink()); + std::cout << " PDG ID " << particle->pdg_id() << std::endl; + } + else + { + std::cout << "Barcode/PDG ID Unknown " << std::endl; + } } int FaserSiHit::trackNumber() const diff --git a/Tracker/TrackerSimEvent/src/SiCharge.cxx b/Tracker/TrackerSimEvent/src/SiCharge.cxx index f24f342adb044ab4f6c79708207efff3b7193f2b..7d089dc004420ab9759be31c3f2bf3e90738c752 100644 --- a/Tracker/TrackerSimEvent/src/SiCharge.cxx +++ b/Tracker/TrackerSimEvent/src/SiCharge.cxx @@ -35,7 +35,7 @@ SiCharge::SiCharge(const double& charge,const double& time, m_charge(charge), m_time(time), m_processType(processType), - m_partLink(HepMcParticleLink((unsigned int) 0, 0)) + m_partLink(HepMcParticleLink()) {} diff --git a/Tracker/TrackerSimEvent/src/SiTotalCharge.cxx b/Tracker/TrackerSimEvent/src/SiTotalCharge.cxx index 2d17b4d1144e899f7d098bb3657f2d27ab669b98..f04abd9f70130ca4d77cf6293d9bf94c86ebecbb 100644 --- a/Tracker/TrackerSimEvent/src/SiTotalCharge.cxx +++ b/Tracker/TrackerSimEvent/src/SiTotalCharge.cxx @@ -18,14 +18,14 @@ SiTotalCharge::SiTotalCharge(const alloc_t& alloc) : m_charge(0), m_chargeComposition(alloc), - m_emptyLink((unsigned int) 0, 0) + m_emptyLink() {} // Copy constructor: SiTotalCharge::SiTotalCharge(const SiTotalCharge &totalCharge) : m_charge(totalCharge.m_charge), m_chargeComposition(totalCharge.m_chargeComposition), - m_emptyLink((unsigned int) 0, 0) + m_emptyLink() {} // Assignment operator: 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 bd4c0658954dc8c5e1fb0adde80e36c2e2b0583d..e15adcec74c6efaee85c11e388517683262c6522 100755 --- a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt +++ b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt @@ -11,87 +11,73 @@ find_package( nlohmann_json ) find_package( Acts COMPONENTS Core ) atlas_add_library( FaserActsGeometryLib - src/FaserActsSurfaceMappingTool.cxx - src/FaserActsMaterialMapping.cxx - src/FaserActsAlignmentStore.cxx - src/FaserActsDetectorElement.cxx - src/FaserActsLayerBuilder.cxx - src/CuboidVolumeBuilder.cxx - src/FaserActsJsonGeometryConverter.cxx - src/util/*.cxx - PUBLIC_HEADERS FaserActsGeometry - INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS} - LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json - TrackerIdentifier - TrackerReadoutGeometry - ActsInteropLib - FaserActsGeometryInterfacesLib - AthenaKernel - ActsCore - GeoModelFaserUtilities - ActsGeometryLib - ActsGeometryInterfacesLib - MagFieldInterfaces - MagFieldElements - MagFieldConditions - TrackerRawData - TrackerSimData - GeneratorObjects - TrackerSimEvent - TrackerSpacePoint - TrackerIdentifier - TrackerPrepRawData - TrkSpacePoint - TrkGeometry + src/FaserActsSurfaceMappingTool.cxx + src/FaserActsMaterialJsonWriterTool.cxx + src/FaserActsMaterialMapping.cxx + src/FaserActsAlignmentStore.cxx + src/FaserActsDetectorElement.cxx + src/FaserActsLayerBuilder.cxx + src/CuboidVolumeBuilder.cxx + src/util/*.cxx + PUBLIC_HEADERS FaserActsGeometry + INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS} + LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json + TrackerIdentifier + TrackerReadoutGeometry + ActsInteropLib + FaserActsGeometryInterfacesLib + AthenaKernel + ActsCore + GeoModelFaserUtilities + ActsGeometryLib + ActsGeometryInterfacesLib + MagFieldInterfaces + MagFieldElements + MagFieldConditions + GeneratorObjects + TrackerIdentifier + TrkGeometry ) # Component(s) in the package: atlas_add_component( FaserActsGeometry -##src/*.cxx - src/FaserActsSurfaceMappingTool.cxx - src/FaserActsMaterialMapping.cxx - src/FaserActsMaterialJsonWriterTool.cxx - src/FaserActsJsonGeometryConverter.cxx - src/FaserActsTrackingGeometrySvc.cxx - src/FaserActsTrackingGeometryTool.cxx - src/FaserActsWriteTrackingGeometry.cxx - src/FaserActsObjWriterTool.cxx - src/FaserActsExtrapolationAlg.cxx - src/FaserActsExtrapolationTool.cxx - src/FaserActsPropStepRootWriterSvc.cxx - src/FaserActsAlignmentCondAlg.cxx - src/NominalAlignmentCondAlg.cxx -#src/FaserActsKalmanFilterAlg.cxx - src/FaserActsVolumeMappingTool.cxx - src/components/*.cxx - PUBLIC_HEADERS FaserActsGeometry - INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS} - LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES} - EventInfo - AthenaBaseComps - GaudiKernel - FaserActsGeometryLib - ActsInteropLib - FaserActsGeometryInterfacesLib - ActsCore - ActsGeometryLib - ActsGeometryInterfacesLib - GeoModelFaserUtilities - MagFieldInterfaces - MagFieldElements - MagFieldConditions - TrackerRawData - TrackerSimData - GeneratorObjects - TrackerSimEvent - TrackerSpacePoint - TrackerIdentifier - TrackerPrepRawData - TrkSpacePoint - TrkGeometry + src/FaserActsSurfaceMappingTool.cxx + src/FaserActsMaterialMapping.cxx + src/FaserActsMaterialJsonWriterTool.cxx + src/FaserActsTrackingGeometrySvc.cxx + src/FaserActsTrackingGeometryTool.cxx + src/FaserActsWriteTrackingGeometry.cxx + src/FaserActsObjWriterTool.cxx + src/FaserActsExtrapolationAlg.cxx + src/FaserActsExtrapolationTool.cxx + src/FaserActsPropStepRootWriterSvc.cxx + src/FaserActsMaterialTrackWriterSvc.cxx + src/FaserActsAlignmentCondAlg.cxx + src/NominalAlignmentCondAlg.cxx + src/FaserActsVolumeMappingTool.cxx + src/components/*.cxx + PUBLIC_HEADERS FaserActsGeometry + INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS} + LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} ${BOOST_LIBRARIES} + EventInfo + AthenaBaseComps + GaudiKernel + FaserActsGeometryLib + ActsInteropLib + FaserActsGeometryInterfacesLib + ActsCore + ActsGeometryLib + ActsGeometryInterfacesLib + GeoModelFaserUtilities + MagFieldInterfaces + MagFieldElements + MagFieldConditions + GeneratorObjects + TrackerIdentifier + TrkGeometry - ) +) # Install files from the package: atlas_install_headers( FaserActsGeometry ) diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsDetectorElement.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsDetectorElement.h index c65bdb69bb6b2f27918c2927fdfd80f2c2d09cb3..f2576d69e66ed73fa3880f9288534f9ab2fb1389 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsDetectorElement.h +++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsDetectorElement.h @@ -24,7 +24,7 @@ namespace Acts { class SurfaceBounds; } -class FaserActsTrackingGeometrySvc; +class IFaserActsTrackingGeometrySvc; class FaserActsAlignmentStore; class IdentityHelper; @@ -87,7 +87,7 @@ private: mutable std::mutex m_cacheMutex; mutable std::shared_ptr<const Acts::Transform3> m_defTransform; - const FaserActsTrackingGeometrySvc* m_trackingGeometrySvc; + const IFaserActsTrackingGeometrySvc* m_trackingGeometrySvc; Identifier m_explicitIdentifier; diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h deleted file mode 100644 index f665a57565ea1cf26cb278f02f8c476da56b286e..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsJsonGeometryConverter.h +++ /dev/null @@ -1,261 +0,0 @@ -// This file is part of the Acts project. -// -// Copyright (C) 2017-2019 CERN for the benefit of the Acts project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Material/ISurfaceMaterial.hpp" -#include "Acts/Material/IVolumeMaterial.hpp" -#include "Acts/Material/MaterialSlab.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Definitions/Common.hpp" -#include "Acts/Utilities/Logger.hpp" -#include <Acts/Geometry/TrackingVolume.hpp> -#include <Acts/Surfaces/Surface.hpp> - -#include <map> - -#include <nlohmann/json.hpp> - -namespace Acts { - -/// @class FaserActsJsonGeometryConverter -/// -/// @brief read the material from Json -class FaserActsJsonGeometryConverter { - public: - using SurfaceMaterialMap = - std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>; - - using VolumeMaterialMap = - std::map<GeometryIdentifier, std::shared_ptr<const IVolumeMaterial>>; - - using DetectorMaterialMaps = std::pair<SurfaceMaterialMap, VolumeMaterialMap>; - - using geo_id_value = uint64_t; - - using SurfaceMaterialRep = std::map<geo_id_value, const ISurfaceMaterial*>; - using SurfaceRep = std::map<geo_id_value, const Surface*>; - using VolumeMaterialRep = std::map<geo_id_value, const IVolumeMaterial*>; - - /// @brief Layer representation for Json writing - struct LayerRep { - // the layer id - GeometryIdentifier layerID; - - SurfaceMaterialRep sensitives; - SurfaceRep sensitiveSurfaces; - SurfaceMaterialRep approaches; - SurfaceRep approacheSurfaces; - const ISurfaceMaterial* representing = nullptr; - const Surface* representingSurface = nullptr; - - /// The LayerRep is actually worth it to write out - operator bool() const { - return (!sensitives.empty() or !approaches.empty() or - representing != nullptr); - } - }; - - /// @brief Volume representation for Json writing - struct VolumeRep { - // The geometry id - GeometryIdentifier volumeID; - - /// The namne - std::string volumeName; - - std::map<geo_id_value, LayerRep> layers; - SurfaceMaterialRep boundaries; - SurfaceRep boundarySurfaces; - const IVolumeMaterial* material = nullptr; - - /// The VolumeRep is actually worth it to write out - operator bool() const { - return (!layers.empty() or !boundaries.empty() or material != nullptr); - } - }; - - /// @brief Detector representation for Json writing - struct DetectorRep { - std::map<geo_id_value, VolumeRep> volumes; - }; - - /// @class Config - /// Configuration of the Reader - class Config { - public: - /// The geometry version - std::string geoversion = "undefined"; - /// The detector tag - std::string detkey = "detector"; - /// The volume identification string - std::string volkey = "volumes"; - /// The name identification - std::string namekey = "Name"; - /// The boundary surface string - std::string boukey = "boundaries"; - /// The layer identification string - std::string laykey = "layers"; - /// The volume material string - std::string matkey = "material"; - /// The approach identification string - std::string appkey = "approach"; - /// The sensitive identification string - std::string senkey = "sensitive"; - /// The representing idntification string - std::string repkey = "representing"; - /// The bin keys - std::string bin0key = "bin0"; - /// The bin1 key - std::string bin1key = "bin1"; - /// The bin2 key - std::string bin2key = "bin2"; - /// The local to global tranfo key - std::string transfokeys = "tranformation"; - /// The type key -> proto, else - std::string typekey = "type"; - /// The data key - std::string datakey = "data"; - /// The geoid key - std::string geometryidkey = "Geoid"; - /// The surface geoid key - std::string surfacegeometryidkey = "SGeoid"; - /// The mapping key, add surface to map if true - std::string mapkey = "mapMaterial"; - /// The surface type key - std::string surfacetypekey = "stype"; - /// The surface position key - std::string surfacepositionkey = "sposition"; - /// The surface range key - std::string surfacerangekey = "srange"; - /// The default logger - std::shared_ptr<const Logger> logger; - /// The name of the writer - std::string name = ""; - - /// Steering to handle sensitive data - bool processSensitives = true; - /// Steering to handle approach data - bool processApproaches = true; - /// Steering to handle representing data - bool processRepresenting = true; - /// Steering to handle boundary data - bool processBoundaries = true; - /// Steering to handle volume data - bool processVolumes = true; - /// Steering to handle volume data - bool processDenseVolumes = false; - /// Add proto material to all surfaces - bool processnonmaterial = false; - /// Write out data - bool writeData = true; - - /// Constructor - /// - /// @param lname Name of the writer tool - /// @param lvl The output logging level - Config(const std::string& lname = "FaserActsJsonGeometryConverter", - Logging::Level lvl = Logging::INFO) - : logger(getDefaultLogger(lname, lvl)), name(lname) {} - }; - - /// Constructor - /// - /// @param cfg configuration struct for the reader - FaserActsJsonGeometryConverter(const Config& cfg); - - /// Destructor - ~FaserActsJsonGeometryConverter() = default; - - /// Convert method - /// - /// @param surfaceMaterialMap The indexed material map collection - std::pair< - std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>, - std::map<GeometryIdentifier, std::shared_ptr<const IVolumeMaterial>>> - jsonToMaterialMaps(const nlohmann::json& materialmaps); - - /// Convert method - /// - /// @param surfaceMaterialMap The indexed material map collection - nlohmann::json materialMapsToJson(const DetectorMaterialMaps& maps); - - /// Write method - /// - /// @param tGeometry is the tracking geometry which contains the material - nlohmann::json trackingGeometryToJson(const TrackingGeometry& tGeometry); - - private: - /// Convert to internal representation method, recursive call - /// - /// @param tGeometry is the tracking geometry which contains the material - void convertToRep(DetectorRep& detRep, const TrackingVolume& tVolume); - - /// Convert to internal representation method - /// - /// @param tGeometry is the tracking geometry which contains the material - LayerRep convertToRep(const Layer& tLayer); - - /// Create the Surface Material from Json - /// - factory method, ownership given - /// @param material is the json part representing a material object - const ISurfaceMaterial* jsonToSurfaceMaterial(const nlohmann::json& material); - - /// Create the Volume Material from Json - /// - factory method, ownership given - /// @param material is the json part representing a material object - const IVolumeMaterial* jsonToVolumeMaterial(const nlohmann::json& material); - - /// Create the Material Matrix from Json - /// - /// @param data is the json part representing a material data array - MaterialSlabMatrix jsonToMaterialMatrix(const nlohmann::json& data); - - /// Create the BinUtility for from Json - BinUtility jsonToBinUtility(const nlohmann::json& bin); - - /// Create the local to global transform for from Json - Transform3 jsonToTransform(const nlohmann::json& transfo); - - /// Create Json from a detector represenation - nlohmann::json detectorRepToJson(const DetectorRep& detRep); - - /// SurfaceMaterial to Json - /// - /// @param the SurfaceMaterial - nlohmann::json surfaceMaterialToJson(const ISurfaceMaterial& sMaterial); - - /// VolumeMaterial to Json - /// - /// @param the VolumeMaterial - nlohmann::json volumeMaterialToJson(const IVolumeMaterial& vMaterial); - - /// Add surface information to json surface - /// - /// @param The json surface The surface - void addSurfaceToJson(nlohmann::json& sjson, const Surface* surface); - - /// Default BinUtility to create proto material - /// - /// @param the Surface - Acts::BinUtility DefaultBin(const Acts::Surface& surface); - - /// Default BinUtility to create proto material - /// - /// @param the Volume - Acts::BinUtility DefaultBin(const Acts::TrackingVolume& volume); - - /// The config class - Config m_cfg; - - /// Private access to the logging instance - const Logger& logger() const { return *m_cfg.logger; } -}; - -} // namespace Acts diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsLayerBuilder.h b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsLayerBuilder.h index fbb91545d925fb04ea4e6ed03f9e0f9426881d46..52aa75240b5f548433a165b19ec837827c42107a 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsLayerBuilder.h +++ b/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsLayerBuilder.h @@ -10,6 +10,7 @@ // ATHENA #include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "GeoModelFaserUtilities/GeoModelExperiment.h" // ACTS #include "Acts/Geometry/GeometryContext.hpp" @@ -50,10 +51,14 @@ public: std::string configurationName = "undefined"; FaserActsDetectorElement::Subdetector subdetector = FaserActsDetectorElement::Subdetector::SCT; - const TrackerDD::SCT_DetectorManager* mng; + const TrackerDD::SCT_DetectorManager* mng=nullptr; + const GeoVDetectorManager* vetomng=nullptr; + const GeoVDetectorManager* triggermng=nullptr; + const GeoVDetectorManager* dipolemng=nullptr; std::shared_ptr<const Acts::LayerCreator> layerCreator = nullptr; std::shared_ptr<std::vector<std::shared_ptr<const FaserActsDetectorElement>>> elementStore; std::shared_ptr<std::map<Identifier, Acts::GeometryIdentifier>> identifierMap; + std::pair<size_t, size_t> MaterialBins = {30, 30}; int station; int plane; }; @@ -66,7 +71,6 @@ public: = Acts::getDefaultLogger("GMLayBldr", Acts::Logging::INFO)) : m_logger(std::move(logger)) { - // std::cout << "GMLB construct" << std::endl; m_cfg = cfg; } @@ -105,13 +109,17 @@ public: buildLayers(const Acts::GeometryContext&, std::vector<std::shared_ptr<const Acts::Surface> >&, FaserActs::CuboidVolumeBuilder::LayerConfig&, FaserActs::CuboidVolumeBuilder::SurfaceConfig&); private: + + FaserActs::CuboidVolumeBuilder::VolumeConfig buildScintVolume(const Acts::GeometryContext& ,double, double, double ,double, double, double , std::string ); +FaserActs::CuboidVolumeBuilder::VolumeConfig buildDipoleVolume(const Acts::GeometryContext& ,double , double , double , double , std::string ); + double m_ModuleWidth; double m_ModuleLength; /// configruation object Config m_cfg; - Acts::Vector3 m_worldDimensions = { 400.0_mm, 400.0_mm, 6000.0_mm }; - Acts::Vector3 m_worldCenter = {0.0, 0.0, 1276.0_mm}; - Acts::Vector3 m_trackerDimensions = { 400.0_mm, 400.0_mm, 1200.0_mm }; + Acts::Vector3 m_worldDimensions = { 600.0_mm, 600.0_mm, 8000.0_mm }; + Acts::Vector3 m_worldCenter = {0.0, 0.0, 0.0}; + Acts::Vector3 m_trackerDimensions = { 600.0_mm, 600.0_mm, 100.0_mm }; /// Private access to the logger const Acts::Logger& diff --git a/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py index a1c3c9f1f239befaaa4c10542706cacfdd18e4dd..d81e6fd90ce1bd9128b715857840fd93c9fcf126 100644 --- a/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py +++ b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py @@ -1,7 +1,7 @@ # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory -FaserActsWriteTrackingGeometry,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsSurfaceMappingTool,FaserActsVolumeMappingTool,FaserActsObjWriterTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsWriteTrackingGeometry","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsSurfaceMappingTool","FaserActsVolumeMappingTool","FaserActsObjWriterTool","FaserActsAlignmentCondAlg") +FaserActsExtrapolationTool,FaserActsMaterialTrackWriterSvc,FaserActsMaterialJsonWriterTool,FaserActsWriteTrackingGeometry,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsSurfaceMappingTool,FaserActsVolumeMappingTool,FaserActsObjWriterTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsExtrapolationTool","FaserActsMaterialTrackWriterSvc","FaserActsMaterialJsonWriterTool","FaserActsWriteTrackingGeometry","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsSurfaceMappingTool","FaserActsVolumeMappingTool","FaserActsObjWriterTool","FaserActsAlignmentCondAlg") @@ -35,11 +35,10 @@ def ActsPropStepRootWriterSvcCfg(configFlags, def ActsTrackingGeometryToolCfg(configFlags, name = "ActsTrackingGeometryTool" ) : result = ComponentAccumulator() - from FaserActsGeometry.FaserActsWriteTrackingGeometryConfig import FaserActsTrackingGeometrySvcCfg - acc = FaserActsTrackingGeometrySvcCfg(configFlags) + acc = ActsTrackingGeometrySvcCfg(configFlags) result.merge(acc) -# Acts_ActsTrackingGeometryTool = CompFactory.ActsTrackingGeometryTool - actsTrackingGeometryTool = FaserActsTrackingGeometryTool("TrackingGeometryTool") + Acts_ActsTrackingGeometryTool = FaserActsTrackingGeometryTool + actsTrackingGeometryTool = Acts_ActsTrackingGeometryTool("TrackingGeometryTool") result.addPublicTool(actsTrackingGeometryTool) return result, actsTrackingGeometryTool @@ -69,7 +68,7 @@ def ActsAlignmentCondAlgCfg(configFlags, name = "ActsAlignmentCondAlg", **kwargs return result from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg -def ActsExtrapolationToolCfg(configFlags, name="ActsExtrapolationTool", **kwargs) : +def ActsExtrapolationToolCfg(configFlags, name="FaserActsExtrapolationTool", **kwargs) : result=ComponentAccumulator() acc = MagneticFieldSvcCfg(configFlags) @@ -78,18 +77,18 @@ def ActsExtrapolationToolCfg(configFlags, name="ActsExtrapolationTool", **kwargs acc, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(configFlags) result.merge(acc) - Acts_ActsExtrapolationTool = CompFactory.ActsExtrapolationTool + Acts_ActsExtrapolationTool = CompFactory.FaserActsExtrapolationTool actsExtrapolationTool = Acts_ActsExtrapolationTool(name, **kwargs) result.addPublicTool(actsExtrapolationTool, primary=True) return result -def ActsMaterialTrackWriterSvcCfg(name="ActsMaterialTrackWriterSvc", +def ActsMaterialTrackWriterSvcCfg(name="FaserActsMaterialTrackWriterSvc", FilePath="MaterialTracks_mapping.root", TreeName="material-tracks") : result = ComponentAccumulator() - Acts_ActsMaterialTrackWriterSvc = CompFactory.ActsMaterialTrackWriterSvc + Acts_ActsMaterialTrackWriterSvc = CompFactory.FaserActsMaterialTrackWriterSvc ActsMaterialTrackWriterSvc = Acts_ActsMaterialTrackWriterSvc(name, FilePath=FilePath, TreeName=TreeName) @@ -115,10 +114,10 @@ def ActsSurfaceMappingToolCfg(configFlags, name = "FaserActsSurfaceMappingTool" result=ComponentAccumulator() acc, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(configFlags) - result.merge(acc) - + result.merge(acc) Acts_ActsSurfaceMappingTool = CompFactory.FaserActsSurfaceMappingTool ActsSurfaceMappingTool = Acts_ActsSurfaceMappingTool(name) + ActsSurfaceMappingTool.TrackingGeometryTool = actsTrackingGeometryTool from AthenaCommon.Constants import INFO ActsSurfaceMappingTool.OutputLevel = INFO @@ -134,6 +133,7 @@ def ActsVolumeMappingToolCfg(configFlags, name = "ActsVolumeMappingTool" ) : Acts_ActsVolumeMappingTool = CompFactory.FaserActsVolumeMappingTool FaserActsVolumeMappingTool = Acts_ActsVolumeMappingTool(name) + FaserActsVolumeMappingTool.TrackingGeometryTool = actsTrackingGeometryTool from AthenaCommon.Constants import INFO FaserActsVolumeMappingTool.OutputLevel = INFO @@ -144,7 +144,7 @@ def ActsVolumeMappingToolCfg(configFlags, name = "ActsVolumeMappingTool" ) : def ActsMaterialJsonWriterToolCfg(name= "ActsMaterialJsonWriterTool", **kwargs) : result=ComponentAccumulator() - Acts_ActsMaterialJsonWriterTool = CompFactory.ActsMaterialJsonWriterTool + Acts_ActsMaterialJsonWriterTool = CompFactory.FaserActsMaterialJsonWriterTool ActsMaterialJsonWriterTool = Acts_ActsMaterialJsonWriterTool(name, **kwargs) from AthenaCommon.Constants import INFO @@ -156,7 +156,7 @@ def ActsMaterialJsonWriterToolCfg(name= "ActsMaterialJsonWriterTool", **kwargs) def ActsObjWriterToolCfg(name= "ActsObjWriterTool", **kwargs) : result=ComponentAccumulator() - Acts_ActsObjWriterTool = CompFactory.ActsObjWriterTool + Acts_ActsObjWriterTool = FaserActsObjWriterTool ActsObjWriterTool = Acts_ActsObjWriterTool(name, **kwargs) from AthenaCommon.Constants import INFO diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsExtrapolationConfig.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsExtrapolationConfig.py index 8720049d249df0064baddab4a91edea401ea2ae1..b16eb1df868645e26f18a9e7b7c6fc390d548e66 100644 --- a/Tracking/Acts/FaserActsGeometry/python/FaserActsExtrapolationConfig.py +++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsExtrapolationConfig.py @@ -10,10 +10,10 @@ from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg FaserActsExtrapolationAlg,FaserActsExtrapolationTool,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsExtrapolationAlg","FaserActsExtrapolationTool","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsAlignmentCondAlg") -def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): - acc = ComponentAccumulator() - acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) - return acc +#def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) +# return acc def FaserActsAlignmentCondAlgCfg(flags, **kwargs): @@ -29,11 +29,14 @@ def FaserActsExtrapolationAlgBasicCfg(flags, **kwargs): actsExtrapolationTool=FaserActsExtrapolationTool("FaserActsExtrapolationTool") actsExtrapolationTool.FieldMode="FASER" #actsExtrapolationTool.FieldMode="Constant" - actsExtrapolationTool.TrackingGeometryTool=FaserActsTrackingGeometryTool("TrackingGeometryTool") + from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg + result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags) + actsExtrapolationTool.TrackingGeometryTool=actsTrackingGeometryTool actsExtrapolationAlg.ExtrapolationTool=actsExtrapolationTool actsExtrapolationAlg.EtaRange=[1, 10] actsExtrapolationAlg.PtRange=[0.1, 100] actsExtrapolationAlg.NParticlesPerEvent=int(1e4) + acc.merge(result) acc.addEventAlgo(actsExtrapolationAlg) return acc @@ -51,7 +54,7 @@ def FaserActsExtrapolationAlgCfg(flags, **kwargs): # Initialize field service acc.merge(MagneticFieldSvcCfg(flags)) - acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) + #acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) #acc.merge(FaserActsAlignmentCondAlgCfg(flags)) acc.merge(FaserActsExtrapolationAlgBasicCfg(flags, **kwargs)) acc.merge(FaserActsExtrapolationAlg_OutputCfg(flags)) diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialMapping_jobOptions.py index 6466848fb515373c2b33bd8c0978d4f162e053bb..92c1b6039a754f68dd5c562575a0dc3b9cc2e9d5 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 +""" ############################################################### # @@ -24,10 +26,6 @@ from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg def ActsMaterialMappingCfg(configFlags, name = "FaserActsMaterialMapping", **kwargs): result = ComponentAccumulator() - MaterialStepConverterTool = ActsMaterialStepConverterToolCfg() - kwargs["MaterialStepConverterTool"] = MaterialStepConverterTool.getPrimary() - result.merge(MaterialStepConverterTool) - ActsSurfaceMappingTool = ActsSurfaceMappingToolCfg(configFlags) kwargs["SurfaceMappingTool"] = ActsSurfaceMappingTool.getPrimary() result.merge(ActsSurfaceMappingTool) @@ -62,11 +60,10 @@ if "__main__" == __name__: ## Just enable ID for the moment. ConfigFlags.Input.isMC = True ConfigFlags.Beam.Type = "collisions" - ConfigFlags.GeoModel.FaserVersion = "FASER-01" - ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion + ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion ConfigFlags.TrackingGeometry.MaterialSource = "geometry-maps.json" - ConfigFlags.Concurrency.NumThreads = 1 - ConfigFlags.Concurrency.NumConcurrentEvents = 1 + ConfigFlags.GeoModel.Align.Dynamic = False ConfigFlags.lock() ConfigFlags.dump() @@ -74,7 +71,7 @@ if "__main__" == __name__: cfg = MainServicesCfg(ConfigFlags) cfg.merge(FaserGeometryCfg(ConfigFlags)) - cfg.merge(ActsMaterialTrackWriterSvcCfg("ActsMaterialTrackWriterSvc", + cfg.merge(ActsMaterialTrackWriterSvcCfg("FaserActsMaterialTrackWriterSvc", "MaterialTracks_mapping.root")) cfg.merge(PoolReadCfg(ConfigFlags)) @@ -99,4 +96,4 @@ if "__main__" == __name__: log.info("CONFIG DONE") - cfg.run(80000) + cfg.run(-1) diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialValidationAlg.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialValidationAlg.py new file mode 100644 index 0000000000000000000000000000000000000000..640d9ee07decdef52c815f2695076d554d662c95 --- /dev/null +++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsMaterialValidationAlg.py @@ -0,0 +1,66 @@ +""" +This job options file will run an example extrapolation using the +Acts tracking geometry and the Acts extrapolation toolchain. + +Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +""" + +# start from scratch with component accumulator + + +from FaserActsGeometry.ActsGeometryConfig import FaserActsExtrapolationToolCfg +from FaserActsGeometry.FaserActsExtrapolationConfig import FaserActsExtrapolationAlgCfg + + +if "__main__" == __name__: + from AthenaCommon.Configurable import Configurable + from AthenaCommon.Logging import log + from AthenaCommon.Constants import INFO + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + from FaserActsGeometry.ActsGeometryConfig import FaserActsMaterialTrackWriterSvcCfg + + Configurable.configurableRun3Behavior = True + + ## Just enable ID for the moment. + ConfigFlags.Input.isMC = True + ConfigFlags.GeoModel.FaserVersion = "FASER-01" + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" + ConfigFlags.TrackingGeometry.MaterialSource = "material-maps.json" + #ConfigFlags.Concurrency.NumThreads = 10 + #ConfigFlags.Concurrency.NumConcurrentEvents = 10 + + ConfigFlags.lock() + ConfigFlags.dump() + + cfg = MainServicesCfg(ConfigFlags) + +# alignCondAlgCfg = ActsAlignmentCondAlgCfg(ConfigFlags) +# cfg.merge(alignCondAlgCfg) + cfg.merge(FaserActsMaterialTrackWriterSvcCfg(ConfigFlags, "FaserActsMaterialTrackWriterSvc", "MaterialTracks_mapped.root")) + + print('DEF WRITER : ') + extrapol = FaserActsExtrapolationToolCfg(ConfigFlags, + InteractionMultiScatering = True, + InteractionEloss = True, + InteractionRecord = True) + cfg.merge(extrapol) + + alg = FaserActsExtrapolationAlgCfg(ConfigFlags, + OutputLevel=INFO, + NParticlesPerEvent=int(1e3), + EtaRange=[4.8, 100], + PtRange=[999, 1001], + XRange=[-150, 150], + YRange=[-150, 150], + WriteMaterialTracks = True, + ExtrapolationTool=extrapol.getPrimary()) + + cfg.merge(alg) + + #tgSvc = cfg.getService("FaserActsTrackingGeometrySvc") + #cfg.printConfig() + + log.info("CONFIG DONE") + + cfg.run(100) diff --git a/Tracking/Acts/FaserActsGeometry/python/FaserActsWriteTrackingGeometryConfig.py b/Tracking/Acts/FaserActsGeometry/python/FaserActsWriteTrackingGeometryConfig.py index 2aef1dac095cf13d8b44ddbdf490d186be67c45b..77e6921bfa63b17816a019964ec94ff80875db5c 100644 --- a/Tracking/Acts/FaserActsGeometry/python/FaserActsWriteTrackingGeometryConfig.py +++ b/Tracking/Acts/FaserActsGeometry/python/FaserActsWriteTrackingGeometryConfig.py @@ -6,12 +6,12 @@ from AthenaConfiguration.ComponentFactory import CompFactory #from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg -FaserActsWriteTrackingGeometry,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsObjWriterTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsWriteTrackingGeometry","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsObjWriterTool","FaserActsAlignmentCondAlg") +FaserActsMaterialJsonWriterTool,FaserActsWriteTrackingGeometry,FaserActsTrackingGeometrySvc,FaserActsTrackingGeometryTool,FaserActsObjWriterTool,FaserActsAlignmentCondAlg = CompFactory.getComps("FaserActsMaterialJsonWriterTool","FaserActsWriteTrackingGeometry","FaserActsTrackingGeometrySvc","FaserActsTrackingGeometryTool","FaserActsObjWriterTool","FaserActsAlignmentCondAlg") -def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): - acc = ComponentAccumulator() - acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) - return acc +#def FaserActsTrackingGeometrySvcCfg(flags, **kwargs): +# acc = ComponentAccumulator() +# acc.addService(FaserActsTrackingGeometrySvc(name = "FaserActsTrackingGeometrySvc", **kwargs)) +# return acc def FaserActsAlignmentCondAlgCfg(flags, **kwargs): @@ -24,8 +24,15 @@ def FaserActsAlignmentCondAlgCfg(flags, **kwargs): def FaserActsWriteTrackingGeometryBasicCfg(flags, **kwargs): acc = ComponentAccumulator() actsWriteTrackingGeometry=FaserActsWriteTrackingGeometry(**kwargs) - actsWriteTrackingGeometry.TrackingGeometryTool=FaserActsTrackingGeometryTool("TrackingGeometryTool") - actsWriteTrackingGeometry.ObjWriterTool=FaserActsObjWriterTool("FaserActsObjWriterTool",OutputDirectory="./", SubDetectors=["Station_1","Station_2","Station_3"]) + from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg + result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags) + acc.merge(result) + actsWriteTrackingGeometry.TrackingGeometryTool=actsTrackingGeometryTool + actsWriteTrackingGeometry.ObjWriterTool=FaserActsObjWriterTool("FaserActsObjWriterTool",OutputDirectory="./", SubDetectors=["Station_0","Station_1","Station_2","Station_3"]) + actsWriteTrackingGeometry.MaterialJsonWriterTool= FaserActsMaterialJsonWriterTool(OutputFile = "geometry-maps.json", + processSensitives = False, + processnonmaterial = False) + acc.addEventAlgo(actsWriteTrackingGeometry) return acc @@ -38,7 +45,7 @@ def FaserActsWriteTrackingGeometry_OutputCfg(flags): def FaserActsWriteTrackingGeometryCfg(flags, **kwargs): #acc = FaserGeometryCfg(flags) acc = FaserSCT_GeometryCfg(flags) - acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) + #acc.merge(FaserActsTrackingGeometrySvcCfg(flags, **kwargs)) #acc.merge(FaserActsAlignmentCondAlgCfg(flags)) acc.merge(FaserActsWriteTrackingGeometryBasicCfg(flags, **kwargs)) acc.merge(FaserActsWriteTrackingGeometry_OutputCfg(flags)) diff --git a/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx b/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx index 76416ff7b7a917a9e47a18a87ac125686b6d386a..e382d4cd31a023ef9a9fb4bb8afa744920bb500e 100644 --- a/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/CuboidVolumeBuilder.cxx @@ -75,12 +75,11 @@ 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, + 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)); } } @@ -124,15 +123,15 @@ std::shared_ptr<Acts::TrackingVolume> CuboidVolumeBuilder::buildVolume( SurfaceConfig sCfg; sCfg.position = cfg.position; // Rotation of the surfaces: +pi/2 around axis y - Acts::Vector3 xPos(0., 0., 1.); - Acts::Vector3 yPos(0., 1., 0.); - Acts::Vector3 zPos(-1., 0., 0.); - sCfg.rotation.col(0) = xPos; - sCfg.rotation.col(1) = yPos; - sCfg.rotation.col(2) = zPos; + //Acts::Vector3 xPos(0., 0., 1.); + //Acts::Vector3 yPos(0., 1., 0.); + //Acts::Vector3 zPos(-1., 0., 0.); + //sCfg.rotation.col(0) = xPos; + //sCfg.rotation.col(1) = yPos; + //sCfg.rotation.col(2) = zPos; // Bounds sCfg.rBounds = std::make_shared<const Acts::RectangleBounds>( - Acts::RectangleBounds(cfg.length.y() * 0.5, cfg.length.z() * 0.5)); + Acts::RectangleBounds(cfg.length.x() * 0.5, cfg.length.y() * 0.5)); LayerConfig lCfg; lCfg.surfaceCfg = sCfg; diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx index 8c913b6ad5e1667a83c1f29aedcb650c2ab84c56..5f0735b99c7192d7d761191046157b42340e7cf9 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsAlignmentCondAlg.h" +#include "FaserActsAlignmentCondAlg.h" // ATHENA #include "EventInfo/EventID.h" diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsAlignmentCondAlg.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsAlignmentCondAlg.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx index 2a790d184273f5aee8c69389500e6d1f94a9ab2d..5545334849da0bb6b068c768773ae4878e52b5f5 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx @@ -11,7 +11,7 @@ #include "GeoPrimitives/CLHEPtoEigenConverter.h" // PACKAGE -#include "FaserActsGeometry/FaserActsTrackingGeometrySvc.h" +// #include "FaserActsTrackingGeometrySvc.h" #include "FaserActsGeometry/FaserActsAlignmentStore.h" #include "FaserActsGeometry/FaserActsGeometryContext.h" #include "ActsInterop/IdentityHelper.h" @@ -60,7 +60,6 @@ FaserActsDetectorElement::FaserActsDetectorElement(const TrackerDD::SiDetectorEl } else if (boundsType == Trk::SurfaceBounds::Trapezoid) { std::string shapeString = detElem->getMaterialGeom()->getLogVol()->getShape()->type(); - //std::cout << __FUNCTION__ << "tapezoid, GeoLogVol -> shape says: " << shapeString << std::endl; const TrackerDD::SiDetectorDesign &design = detElem->design(); diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.cxx index 0eca15c20fcd100e2711573588e9c68a3fecf094..6fd900f61a006f870af727f7bb8f434c30c37583 100755 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsExtrapolationAlg.h" +#include "FaserActsExtrapolationAlg.h" // ATHENA #include "AthenaKernel/RNGWrapper.h" @@ -18,14 +18,14 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Utilities/Logger.hpp" #include "Acts/Surfaces/PerigeeSurface.hpp" +#include "ActsInterop/Logger.h" // PACKAGE +#include "ActsGeometryInterfaces/IActsMaterialTrackWriterSvc.h" +#include "FaserActsGeometry/FaserActsGeometryContext.h" #include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" -#include "ActsInterop/Logger.h" -#include "FaserActsGeometry/FaserActsGeometryContext.h" -#include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h" -//#include "FaserActsGeometry/IFaserActsMaterialTrackWriterSvc.h" +#include "FaserActsGeometryInterfaces/IFaserActsPropStepRootWriterSvc.h" // OTHER #include "CLHEP/Random/RandomEngine.h" @@ -40,8 +40,8 @@ FaserActsExtrapolationAlg::FaserActsExtrapolationAlg(const std::string& name, ISvcLocator* pSvcLocator) : AthReentrantAlgorithm(name, pSvcLocator), m_propStepWriterSvc("FaserActsPropStepRootWriterSvc", name), - m_rndmGenSvc("AthRNGSvc", name)//, - //m_materialTrackWriterSvc("FaserActsMaterialTrackWriterSvc", name) + m_rndmGenSvc("AthRNGSvc", name), + m_materialTrackWriterSvc("FaserActsMaterialTrackWriterSvc", name) { } @@ -53,9 +53,9 @@ StatusCode FaserActsExtrapolationAlg::initialize() { ATH_CHECK( m_extrapolationTool.retrieve() ); ATH_CHECK( m_propStepWriterSvc.retrieve() ); - //if (m_writeMaterialTracks) { - //ATH_CHECK( m_materialTrackWriterSvc.retrieve() ); - //} + if (m_writeMaterialTracks) { + ATH_CHECK( m_materialTrackWriterSvc.retrieve() ); + } m_objOut = std::make_unique<std::ofstream>("steps.obj"); @@ -75,14 +75,23 @@ StatusCode FaserActsExtrapolationAlg::execute(const EventContext& ctx) const for (size_t i = 0; i < m_nParticlePerEvent; i++) { - double d0 = 0; - double z0 = 0; +// double d0 = 0; +// double z0 = 0; double phi = rngEngine->flat() * 2*M_PI - M_PI; std::vector<double> etaRange = m_etaRange; + std::vector<double> xRange = m_xRange; + std::vector<double> yRange = m_yRange; double etaMin = etaRange.at(0); double etaMax = etaRange.at(1); double eta = rngEngine->flat() * std::abs(etaMax - etaMin) + etaMin; + double xMin = xRange.at(0); + double xMax = xRange.at(1); + double yMin = yRange.at(0); + double yMax = yRange.at(1); + double x0 = rngEngine->flat() * std::abs(xMax - xMin) + xMin; + double y0 = rngEngine->flat() * std::abs(yMax - yMin) + yMin; + std::vector<double> ptRange = m_ptRange; double ptMin = ptRange.at(0) * 1_GeV; double ptMax = ptRange.at(1) * 1_GeV; @@ -104,7 +113,7 @@ StatusCode FaserActsExtrapolationAlg::execute(const EventContext& ctx) const double t = 0; Acts::BoundVector pars; - pars << d0, z0, phi, theta, qop, t; + pars << x0, y0, phi, theta, qop, t; std::optional<Acts::BoundSymMatrix> cov = std::nullopt; if(charge != 0.) { @@ -116,6 +125,13 @@ StatusCode FaserActsExtrapolationAlg::execute(const EventContext& ctx) const auto output = m_extrapolationTool->propagationSteps(ctx, startParameters); m_propStepWriterSvc->write(output.first); writeStepsObj(output.first); + if(m_writeMaterialTracks){ + Acts::RecordedMaterialTrack track; + track.first.first = Acts::Vector3(0,0,0); + track.first.second = momentum; + track.second = std::move(output.second); + m_materialTrackWriterSvc->write(track); + } } diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsExtrapolationAlg.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.h similarity index 85% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsExtrapolationAlg.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.h index 96bbda658b550011f6a897a730ed56a99641e330..75887540e81178080c0556c88d7cdbd2758ff7a4 100755 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsExtrapolationAlg.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationAlg.h @@ -35,7 +35,7 @@ namespace Acts { } } -//class IFaserActsMaterialTrackWriterSvc; +class IActsMaterialTrackWriterSvc; class EventContext; class IAthRNGSvc; @@ -56,13 +56,15 @@ private: ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool{this, "ExtrapolationTool", "FaserActsExtrapolationTool"}; // poor-mans Particle Gun is included here right now + Gaudi::Property<std::vector<double>> m_xRange{this, "XRange", {-150, 150}, ""}; + Gaudi::Property<std::vector<double>> m_yRange{this, "YRange", {-150, 150}, ""}; Gaudi::Property<std::vector<double>> m_etaRange{this, "EtaRange", {4, 10}, ""}; Gaudi::Property<std::vector<double>> m_ptRange{this, "PtRange", {0.1, 1000}, ""}; Gaudi::Property<size_t> m_nParticlePerEvent{this, "NParticlesPerEvent", 1, "The number of particles per event"}; // this does not work right now - //Gaudi::Property<bool> m_writeMaterialTracks{this, "WriteMaterialTracks", false, ""}; - //ServiceHandle<IFaserActsMaterialTrackWriterSvc> m_materialTrackWriterSvc; + Gaudi::Property<bool> m_writeMaterialTracks{this, "WriteMaterialTracks", false, ""}; + ServiceHandle<IActsMaterialTrackWriterSvc> m_materialTrackWriterSvc; mutable std::mutex m_writeMutex{}; mutable std::unique_ptr<std::ofstream> m_objOut; diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx index e84a69c6a3fe54ee30ecb046a0606a1e264da5e5..0e92508b08f01b792c15913a45f37cda8c0eb5c0 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx @@ -2,15 +2,15 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsExtrapolationTool.h" +#include "FaserActsExtrapolationTool.h" // ATHENA #include "GaudiKernel/IInterface.h" #include "GaudiKernel/PhysicalConstants.h" // PACKAGE -#include "FaserActsGeometry/FaserActsTrackingGeometrySvc.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" +// #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometrySvc.h" +// #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" #include "ActsInterop/Logger.h" // ACTS @@ -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 @@ -227,7 +228,7 @@ FaserActsExtrapolationTool::propagate(const EventContext& ctx, auto parameters = boost::apply_visitor([&](const auto& propagator) -> std::unique_ptr<const Acts::CurvilinearTrackParameters> { auto result = propagator.propagate(startParameters, options); if (!result.ok()) { - ATH_MSG_ERROR("Got error during propagation:" << result.error() + ATH_MSG_WARNING("Got error during propagation:" << result.error() << ". Returning empty parameters."); return nullptr; } @@ -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/FaserActsGeometry/FaserActsExtrapolationTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsExtrapolationTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx deleted file mode 100644 index c707a004396881bce6589e8f84f0ebf590d3e213..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsJsonGeometryConverter.cxx +++ /dev/null @@ -1,1071 +0,0 @@ -// This file is part of the Acts project. -// -// Copyright (C) 2017-2019 CERN for the benefit of the Acts project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "FaserActsGeometry/FaserActsJsonGeometryConverter.h" - -#include "Acts/Geometry/ApproachDescriptor.hpp" -#include "Acts/Geometry/CuboidVolumeBounds.hpp" -#include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp" -#include "Acts/Geometry/CylinderVolumeBounds.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingVolume.hpp" -#include "Acts/Material/BinnedSurfaceMaterial.hpp" -#include "Acts/Material/HomogeneousSurfaceMaterial.hpp" -#include "Acts/Material/HomogeneousVolumeMaterial.hpp" -#include "Acts/Material/InterpolatedMaterialMap.hpp" -#include "Acts/Material/MaterialGridHelper.hpp" -#include "Acts/Material/ProtoSurfaceMaterial.hpp" -#include "Acts/Material/ProtoVolumeMaterial.hpp" -#include "Acts/Surfaces/RectangleBounds.hpp" -#include "Acts/Surfaces/SurfaceArray.hpp" -#include "Acts/Utilities/BinUtility.hpp" -#include "Acts/Utilities/BinningType.hpp" -#include <Acts/Surfaces/AnnulusBounds.hpp> -#include <Acts/Surfaces/CylinderBounds.hpp> -#include <Acts/Surfaces/RadialBounds.hpp> -#include <Acts/Surfaces/SurfaceBounds.hpp> -#include <Acts/Definitions/Algebra.hpp> - - -#include <cstdio> -#include <fstream> -#include <iostream> -#include <map> -#include <sstream> -#include <stdexcept> -#include <string> - -#include <boost/algorithm/string.hpp> -#include <boost/algorithm/string/finder.hpp> -#include <boost/algorithm/string/iter_find.hpp> - -namespace { - -using json = nlohmann::json; - -// helper functions to encode/decode indefinite material -// -// encoded either as `null` for vacuum or to an array of material parameters - -json encodeMaterial(const Acts::Material& material) { - if (!material) { - return nullptr; - } - json encoded = json::array(); - for (unsigned i = 0; i < material.parameters().size(); ++i) { - encoded.push_back(material.parameters()[i]); - } - return encoded; -} - -Acts::Material decodeMaterial(const json& encoded) { - if (encoded.is_null()) { - return {}; - } - Acts::Material::ParametersVector params = - Acts::Material::ParametersVector::Zero(); - for (auto i = params.size(); 0 < i--;) { - // .at(...) ensures bound checks - params[i] = encoded.at(i); - } - return Acts::Material(params); -} - -// helper functions to encode/decode concrete material slabs -// -// encoded as an object w/ two entries: `material` and `thickness` - -json encodeMaterialSlab(const Acts::MaterialSlab& slab) { - return { - {"material", encodeMaterial(slab.material())}, - {"thickness", slab.thickness()}, - }; -} - -Acts::MaterialSlab decodeMaterialSlab(const json& encoded) { - return Acts::MaterialSlab(decodeMaterial(encoded.at("material")), - encoded.at("thickness").get<float>()); -} - -} // namespace - -Acts::FaserActsJsonGeometryConverter::FaserActsJsonGeometryConverter( - const Acts::FaserActsJsonGeometryConverter::Config& cfg) - : m_cfg(std::move(cfg)) { - // Validate the configuration - if (!m_cfg.logger) { - throw std::invalid_argument("Missing logger"); - } -} - -std::pair<std::map<Acts::GeometryIdentifier, - std::shared_ptr<const Acts::ISurfaceMaterial>>, - std::map<Acts::GeometryIdentifier, - std::shared_ptr<const Acts::IVolumeMaterial>>> -Acts::FaserActsJsonGeometryConverter::jsonToMaterialMaps(const json& materialmaps) { - auto& j = materialmaps; - // The return maps - std::pair<SurfaceMaterialMap, VolumeMaterialMap> maps; - ACTS_VERBOSE("j2a: Reading material maps from json file."); - ACTS_VERBOSE("j2a: Found entries for " << j.count(m_cfg.volkey) - << " volume(s)."); - // Structured binding - for (auto& [key, value] : j.items()) { - // Check if this the volume key - if (key == m_cfg.volkey) { - // Get the volume json - auto volj = value; - for (auto& [vkey, vvalue] : volj.items()) { - // Create the volume id - int vid = std::stoi(vkey); - Acts::GeometryIdentifier volumeID; - volumeID.setVolume(vid); - ACTS_VERBOSE("j2a: -> Found Volume " << vid); - // Loop through the information in the volume - for (auto& [vckey, vcvalue] : vvalue.items()) { - if (vckey == m_cfg.boukey and m_cfg.processBoundaries and - not vcvalue.empty()) { - ACTS_VERBOSE("j2a: --> BoundarySurface(s) to be parsed"); - for (auto& [bkey, bvalue] : vcvalue.items()) { - // Create the boundary id - int bid = std::stoi(bkey); - Acts::GeometryIdentifier boundaryID(volumeID); - boundaryID.setBoundary(bid); - ACTS_VERBOSE("j2a: ---> Found boundary surface " << bid); - if (bvalue[m_cfg.mapkey] == true) { - auto boumat = jsonToSurfaceMaterial(bvalue); - maps.first[boundaryID] = - std::shared_ptr<const ISurfaceMaterial>(boumat); - } - } - } else if (vckey == m_cfg.laykey) { - ACTS_VERBOSE("j2a: --> Layer(s) to be parsed"); - // Loop over layers and repeat - auto layj = vcvalue; - for (auto& [lkey, lvalue] : layj.items()) { - // Create the layer id - int lid = std::stoi(lkey); - Acts::GeometryIdentifier layerID(volumeID); - layerID.setLayer(lid); - ACTS_VERBOSE("j2a: ---> Found Layer " << lid); - // Finally loop over layer components - for (auto& [lckey, lcvalue] : lvalue.items()) { - if (lckey == m_cfg.repkey and m_cfg.processRepresenting and - not lcvalue.empty()) { - ACTS_VERBOSE("j2a: ----> Found representing surface"); - if (lcvalue[m_cfg.mapkey] == true) { - auto repmat = jsonToSurfaceMaterial(lcvalue); - maps.first[layerID] = - std::shared_ptr<const Acts::ISurfaceMaterial>(repmat); - } - } else if (lckey == m_cfg.appkey and m_cfg.processApproaches and - not lcvalue.empty()) { - ACTS_VERBOSE("j2a: ----> Found approach surface(s)"); - // Loop over approach surfaces - for (auto& [askey, asvalue] : lcvalue.items()) { - // Create the layer id, todo set to max value - int aid = (askey == "*") ? 0 : std::stoi(askey); - Acts::GeometryIdentifier approachID(layerID); - approachID.setApproach(aid); - ACTS_VERBOSE("j2a: -----> Approach surface " << askey); - if (asvalue[m_cfg.mapkey] == true) { - auto appmat = jsonToSurfaceMaterial(asvalue); - maps.first[approachID] = - std::shared_ptr<const Acts::ISurfaceMaterial>(appmat); - } - } - } else if (lckey == m_cfg.senkey and m_cfg.processSensitives and - not lcvalue.empty()) { - ACTS_VERBOSE("j2a: ----> Found sensitive surface(s)"); - // Loop over sensitive surfaces - for (auto& [sskey, ssvalue] : lcvalue.items()) { - // Create the layer id, todo set to max value - int sid = (sskey == "*") ? 0 : std::stoi(sskey); - Acts::GeometryIdentifier senisitiveID(layerID); - senisitiveID.setSensitive(sid); - ACTS_VERBOSE("j2a: -----> Sensitive surface " << sskey); - if (ssvalue[m_cfg.mapkey] == true) { - auto senmat = jsonToSurfaceMaterial(ssvalue); - maps.first[senisitiveID] = - std::shared_ptr<const Acts::ISurfaceMaterial>(senmat); - } - } - } - } - } - - } else if (m_cfg.processVolumes and vckey == m_cfg.matkey and - not vcvalue.empty()) { - ACTS_VERBOSE("--> VolumeMaterial to be parsed"); - if (vcvalue[m_cfg.mapkey] == true) { - auto intermat = jsonToVolumeMaterial(vcvalue); - maps.second[volumeID] = - std::shared_ptr<const Acts::IVolumeMaterial>(intermat); - } - } - } - } - } else if (key == m_cfg.geoversion) { - ACTS_VERBOSE("Detector version: " << m_cfg.geoversion); - } - } - - // Return the filled maps - return maps; -} - -/// Convert method -/// -json Acts::FaserActsJsonGeometryConverter::materialMapsToJson( - const DetectorMaterialMaps& maps) { - DetectorRep detRep; - // Collect all GeometryIdentifiers per VolumeID for the formatted output - for (auto& [key, value] : maps.first) { - geo_id_value vid = key.volume(); - auto volRep = detRep.volumes.find(vid); - if (volRep == detRep.volumes.end()) { - detRep.volumes.insert({vid, VolumeRep()}); - volRep = detRep.volumes.find(vid); - volRep->second.volumeID = key; - } - geo_id_value lid = key.layer(); - if (lid != 0) { - // we are on a layer, get the layer rep - auto layRep = volRep->second.layers.find(lid); - if (layRep == volRep->second.layers.end()) { - volRep->second.layers.insert({lid, LayerRep()}); - layRep = volRep->second.layers.find(lid); - layRep->second.layerID = key; - } - // now insert appropriately - geo_id_value sid = key.sensitive(); - geo_id_value aid = key.approach(); - if (sid != 0) { - layRep->second.sensitives.insert({sid, value.get()}); - } else if (aid != 0) { - layRep->second.approaches.insert({aid, value.get()}); - } else { - layRep->second.representing = value.get(); - } - - } else { - // not on a layer can only be a boundary surface - geo_id_value bid = key.boundary(); - volRep->second.boundaries.insert({bid, value.get()}); - } - } - for (auto& [key, value] : maps.second) { - // find the volume representation - geo_id_value vid = key.volume(); - auto volRep = detRep.volumes.find(vid); - if (volRep == detRep.volumes.end()) { - detRep.volumes.insert({vid, VolumeRep()}); - volRep = detRep.volumes.find(vid); - volRep->second.volumeID = key; - } - volRep->second.material = value.get(); - } - // convert the detector representation to json format - return detectorRepToJson(detRep); -} - -/// Create Json from a detector represenation -json Acts::FaserActsJsonGeometryConverter::detectorRepToJson(const DetectorRep& detRep) { - json detectorj; - ACTS_VERBOSE("a2j: Writing json from detector representation"); - ACTS_VERBOSE("a2j: Found entries for " << detRep.volumes.size() - << " volume(s)."); - - json volumesj; - for (auto& [key, value] : detRep.volumes) { - json volj; - ACTS_VERBOSE("a2j: -> Writing Volume: " << key); - volj[m_cfg.namekey] = value.volumeName; - std::ostringstream svolumeID; - svolumeID << value.volumeID; - volj[m_cfg.geometryidkey] = svolumeID.str(); - if (m_cfg.processVolumes && value.material) { - volj[m_cfg.matkey] = volumeMaterialToJson(*value.material); - } - // Write the layers - if (not value.layers.empty()) { - ACTS_VERBOSE("a2j: ---> Found " << value.layers.size() << " layer(s) "); - json layersj; - for (auto& [lkey, lvalue] : value.layers) { - ACTS_VERBOSE("a2j: ----> Convert layer " << lkey); - json layj; - std::ostringstream slayerID; - slayerID << lvalue.layerID; - layj[m_cfg.geometryidkey] = slayerID.str(); - // First check for approaches - if (not lvalue.approaches.empty() and m_cfg.processApproaches) { - ACTS_VERBOSE("a2j: -----> Found " << lvalue.approaches.size() - << " approach surface(s)"); - json approachesj; - for (auto& [akey, avalue] : lvalue.approaches) { - ACTS_VERBOSE("a2j: ------> Convert approach surface " << akey); - approachesj[std::to_string(akey)] = surfaceMaterialToJson(*avalue); - if (lvalue.approacheSurfaces.find(akey) != - lvalue.approacheSurfaces.end()) - addSurfaceToJson(approachesj[std::to_string(akey)], - lvalue.approacheSurfaces.at(akey)); - } - // Add to the layer json - layj[m_cfg.appkey] = approachesj; - } - // Then check for sensitive - if (not lvalue.sensitives.empty() and m_cfg.processSensitives) { - ACTS_VERBOSE("a2j: -----> Found " << lvalue.sensitives.size() - << " sensitive surface(s)"); - json sensitivesj; - for (auto& [skey, svalue] : lvalue.sensitives) { - ACTS_VERBOSE("a2j: ------> Convert sensitive surface " << skey); - sensitivesj[std::to_string(skey)] = surfaceMaterialToJson(*svalue); - if (lvalue.sensitiveSurfaces.find(skey) != - lvalue.sensitiveSurfaces.end()) - addSurfaceToJson(sensitivesj[std::to_string(skey)], - lvalue.sensitiveSurfaces.at(skey)); - } - // Add to the layer json - layj[m_cfg.senkey] = sensitivesj; - } - // Finally check for representing - if (lvalue.representing != nullptr and m_cfg.processRepresenting) { - ACTS_VERBOSE("a2j: ------> Convert representing surface "); - layj[m_cfg.repkey] = surfaceMaterialToJson(*lvalue.representing); - if (lvalue.representingSurface != nullptr) - addSurfaceToJson(layj[m_cfg.repkey], lvalue.representingSurface); - } - layersj[std::to_string(lkey)] = layj; - } - volj[m_cfg.laykey] = layersj; - } - // Write the boundary surfaces - if (not value.boundaries.empty()) { - ACTS_VERBOSE("a2j: ---> Found " << value.boundaries.size() - << " boundary/ies "); - json boundariesj; - for (auto& [bkey, bvalue] : value.boundaries) { - ACTS_VERBOSE("a2j: ----> Convert boundary " << bkey); - boundariesj[std::to_string(bkey)] = surfaceMaterialToJson(*bvalue); - if (value.boundarySurfaces.find(bkey) != value.boundarySurfaces.end()) - addSurfaceToJson(boundariesj[std::to_string(bkey)], - value.boundarySurfaces.at(bkey)); - } - volj[m_cfg.boukey] = boundariesj; - } - - volumesj[std::to_string(key)] = volj; - } - // Assign the volume json to the detector json - detectorj[m_cfg.volkey] = volumesj; - - return detectorj; -} - -/// Create the Surface Material -const Acts::ISurfaceMaterial* -Acts::FaserActsJsonGeometryConverter::jsonToSurfaceMaterial(const json& material) { - Acts::ISurfaceMaterial* sMaterial = nullptr; - // The bin utility for deescribing the data - Acts::BinUtility bUtility; - for (auto& [key, value] : material.items()) { - if (key == m_cfg.transfokeys and not value.empty()) { - bUtility = Acts::BinUtility(jsonToTransform(value)); - break; - } - } - // Convert the material - Acts::MaterialSlabMatrix mpMatrix; - // Structured binding - for (auto& [key, value] : material.items()) { - // Check json keys - if (key == m_cfg.bin0key and not value.empty()) { - bUtility += jsonToBinUtility(value); - } else if (key == m_cfg.bin1key and not value.empty()) { - bUtility += jsonToBinUtility(value); - } - if (key == m_cfg.datakey and not value.empty()) { - mpMatrix = jsonToMaterialMatrix(value); - } - } - - // We have protoMaterial - if (mpMatrix.empty()) { - sMaterial = new Acts::ProtoSurfaceMaterial(bUtility); - } else if (bUtility.bins() == 1) { - sMaterial = new Acts::HomogeneousSurfaceMaterial(mpMatrix[0][0]); - } else { - sMaterial = new Acts::BinnedSurfaceMaterial(bUtility, mpMatrix); - } - // return what you have - return sMaterial; -} - -/// Create the Volume Material -const Acts::IVolumeMaterial* Acts::FaserActsJsonGeometryConverter::jsonToVolumeMaterial( - const json& material) { - Acts::IVolumeMaterial* vMaterial = nullptr; - // The bin utility for deescribing the data - Acts::BinUtility bUtility; - for (auto& [key, value] : material.items()) { - if (key == m_cfg.transfokeys and not value.empty()) { - bUtility = Acts::BinUtility(jsonToTransform(value)); - break; - } - } - // Convert the material - std::vector<Material> mmat; - // Structured binding - for (auto& [key, value] : material.items()) { - // Check json keys - if (key == m_cfg.bin0key and not value.empty()) { - bUtility += jsonToBinUtility(value); - } else if (key == m_cfg.bin1key and not value.empty()) { - bUtility += jsonToBinUtility(value); - } else if (key == m_cfg.bin2key and not value.empty()) { - bUtility += jsonToBinUtility(value); - } - if (key == m_cfg.datakey and not value.empty()) { - for (const auto& bin : value) { - mmat.push_back(decodeMaterial(bin)); - } - } - } - - // We have protoMaterial - if (mmat.empty()) { - vMaterial = new Acts::ProtoVolumeMaterial(bUtility); - } else if (mmat.size() == 1) { - vMaterial = new Acts::HomogeneousVolumeMaterial(mmat[0]); - } else { - if (bUtility.dimensions() == 2) { - std::function<Acts::Vector2(Acts::Vector3)> transfoGlobalToLocal; - Acts::Grid2D grid = createGrid2D(bUtility, transfoGlobalToLocal); - - Acts::Grid2D::point_t min = grid.minPosition(); - Acts::Grid2D::point_t max = grid.maxPosition(); - Acts::Grid2D::index_t nBins = grid.numLocalBins(); - - Acts::EAxis axis1(min[0], max[0], nBins[0]); - Acts::EAxis axis2(min[1], max[1], nBins[1]); - - // Build the grid and fill it with data - MaterialGrid2D mGrid(std::make_tuple(axis1, axis2)); - - for (size_t bin = 0; bin < mmat.size(); bin++) { - mGrid.at(bin) = mmat[bin].parameters(); - } - MaterialMapper<MaterialGrid2D> matMap(transfoGlobalToLocal, mGrid); - vMaterial = - new Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid2D>>( - std::move(matMap), bUtility); - } else if (bUtility.dimensions() == 3) { - std::function<Acts::Vector3(Acts::Vector3)> transfoGlobalToLocal; - Acts::Grid3D grid = createGrid3D(bUtility, transfoGlobalToLocal); - - Acts::Grid3D::point_t min = grid.minPosition(); - Acts::Grid3D::point_t max = grid.maxPosition(); - Acts::Grid3D::index_t nBins = grid.numLocalBins(); - - Acts::EAxis axis1(min[0], max[0], nBins[0]); - Acts::EAxis axis2(min[1], max[1], nBins[1]); - Acts::EAxis axis3(min[2], max[2], nBins[2]); - - // Build the grid and fill it with data - MaterialGrid3D mGrid(std::make_tuple(axis1, axis2, axis3)); - - for (size_t bin = 0; bin < mmat.size(); bin++) { - mGrid.at(bin) = mmat[bin].parameters(); - } - MaterialMapper<MaterialGrid3D> matMap(transfoGlobalToLocal, mGrid); - vMaterial = - new Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid3D>>( - std::move(matMap), bUtility); - } - } - // return what you have - return vMaterial; -} - -json Acts::FaserActsJsonGeometryConverter::trackingGeometryToJson( - const Acts::TrackingGeometry& tGeometry) { - DetectorRep detRep; - convertToRep(detRep, *tGeometry.highestTrackingVolume()); - return detectorRepToJson(detRep); -} - -void Acts::FaserActsJsonGeometryConverter::convertToRep( - DetectorRep& detRep, const Acts::TrackingVolume& tVolume) { - // The writer reader volume representation - VolumeRep volRep; - volRep.volumeName = tVolume.volumeName(); - // there are confined volumes - if (tVolume.confinedVolumes() != nullptr) { - // get through the volumes - auto& volumes = tVolume.confinedVolumes()->arrayObjects(); - // loop over the volumes - for (auto& vol : volumes) { - // recursive call - convertToRep(detRep, *vol); - } - } - // there are dense volumes - if (m_cfg.processDenseVolumes && !tVolume.denseVolumes().empty()) { - // loop over the volumes - for (auto& vol : tVolume.denseVolumes()) { - // recursive call - convertToRep(detRep, *vol); - } - } - // Get the volume Id - Acts::GeometryIdentifier volumeID = tVolume.geometryId(); - geo_id_value vid = volumeID.volume(); - - // Write the material if there's one - if (tVolume.volumeMaterial() != nullptr) { - volRep.material = tVolume.volumeMaterial(); - } else if (m_cfg.processnonmaterial == true) { - Acts::BinUtility bUtility = DefaultBin(tVolume); - Acts::IVolumeMaterial* bMaterial = new Acts::ProtoVolumeMaterial(bUtility); - volRep.material = bMaterial; - } - // there are confied layers - if (tVolume.confinedLayers() != nullptr) { - // get the layers - auto& layers = tVolume.confinedLayers()->arrayObjects(); - // loop of the volumes - for (auto& lay : layers) { - auto layRep = convertToRep(*lay); - if (layRep) { - // it's a valid representation so let's go with it - Acts::GeometryIdentifier layerID = lay->geometryId(); - geo_id_value lid = layerID.layer(); - volRep.layers.insert({lid, std::move(layRep)}); - } - } - } - // Let's finally check the boundaries - for (auto& bsurf : tVolume.boundarySurfaces()) { - // the surface representation - auto& bssfRep = bsurf->surfaceRepresentation(); - if (bssfRep.surfaceMaterial() != nullptr) { - Acts::GeometryIdentifier boundaryID = bssfRep.geometryId(); - geo_id_value bid = boundaryID.boundary(); - // Ignore if the volumeID is not correct (i.e. shared boundary) - // if (boundaryID.value(Acts::GeometryIdentifier::volume_mask) == vid){ - volRep.boundaries[bid] = bssfRep.surfaceMaterial(); - volRep.boundarySurfaces[bid] = &bssfRep; - // } - } else if (m_cfg.processnonmaterial == true) { - // if no material suface exist add a default one for the mapping - // configuration - Acts::GeometryIdentifier boundaryID = bssfRep.geometryId(); - geo_id_value bid = boundaryID.boundary(); - Acts::BinUtility bUtility = DefaultBin(bssfRep); - Acts::ISurfaceMaterial* bMaterial = - new Acts::ProtoSurfaceMaterial(bUtility); - volRep.boundaries[bid] = bMaterial; - volRep.boundarySurfaces[bid] = &bssfRep; - } - } - // Write if it's good - if (volRep) { - volRep.volumeName = tVolume.volumeName(); - volRep.volumeID = volumeID; - detRep.volumes.insert({vid, std::move(volRep)}); - } - return; -} - -Acts::FaserActsJsonGeometryConverter::LayerRep Acts::FaserActsJsonGeometryConverter::convertToRep( - const Acts::Layer& tLayer) { - LayerRep layRep; - // fill layer ID information - layRep.layerID = tLayer.geometryId(); - if (m_cfg.processSensitives and tLayer.surfaceArray() != nullptr) { - for (auto& ssf : tLayer.surfaceArray()->surfaces()) { - if (ssf != nullptr && ssf->surfaceMaterial() != nullptr) { - Acts::GeometryIdentifier sensitiveID = ssf->geometryId(); - geo_id_value sid = sensitiveID.sensitive(); - layRep.sensitives.insert({sid, ssf->surfaceMaterial()}); - layRep.sensitiveSurfaces.insert({sid, ssf}); - } else if (m_cfg.processnonmaterial == true) { - // if no material suface exist add a default one for the mapping - // configuration - Acts::GeometryIdentifier sensitiveID = ssf->geometryId(); - geo_id_value sid = sensitiveID.sensitive(); - Acts::BinUtility sUtility = DefaultBin(*ssf); - Acts::ISurfaceMaterial* sMaterial = - new Acts::ProtoSurfaceMaterial(sUtility); - layRep.sensitives.insert({sid, sMaterial}); - layRep.sensitiveSurfaces.insert({sid, ssf}); - } - } - } - // the representing - if (!(tLayer.surfaceRepresentation().geometryId() == GeometryIdentifier())) { - if (tLayer.surfaceRepresentation().surfaceMaterial() != nullptr) { - layRep.representing = tLayer.surfaceRepresentation().surfaceMaterial(); - layRep.representingSurface = &tLayer.surfaceRepresentation(); - } else if (m_cfg.processnonmaterial == true) { - // if no material suface exist add a default one for the mapping - // configuration - Acts::BinUtility rUtility = DefaultBin(tLayer.surfaceRepresentation()); - Acts::ISurfaceMaterial* rMaterial = - new Acts::ProtoSurfaceMaterial(rUtility); - layRep.representing = rMaterial; - layRep.representingSurface = &tLayer.surfaceRepresentation(); - } - } - // the approach - if (tLayer.approachDescriptor() != nullptr) { - for (auto& asf : tLayer.approachDescriptor()->containedSurfaces()) { - // get the surface and check for material - if (asf->surfaceMaterial() != nullptr) { - Acts::GeometryIdentifier approachID = asf->geometryId(); - geo_id_value aid = approachID.approach(); - layRep.approaches.insert({aid, asf->surfaceMaterial()}); - layRep.approacheSurfaces.insert({aid, asf}); - } else if (m_cfg.processnonmaterial == true) { - // if no material suface exist add a default one for the mapping - // configuration - Acts::GeometryIdentifier approachID = asf->geometryId(); - geo_id_value aid = approachID.approach(); - Acts::BinUtility aUtility = DefaultBin(*asf); - Acts::ISurfaceMaterial* aMaterial = - new Acts::ProtoSurfaceMaterial(aUtility); - layRep.approaches.insert({aid, aMaterial}); - layRep.approacheSurfaces.insert({aid, asf}); - } - } - } - // return the layer representation - return layRep; -} - -json Acts::FaserActsJsonGeometryConverter::surfaceMaterialToJson( - const Acts::ISurfaceMaterial& sMaterial) { - json smj; - // A bin utility needs to be written - const Acts::BinUtility* bUtility = nullptr; - // Check if we have a proto material - auto psMaterial = dynamic_cast<const Acts::ProtoSurfaceMaterial*>(&sMaterial); - if (psMaterial != nullptr) { - // Type is proto material - smj[m_cfg.typekey] = "proto"; - // by default the protoMaterial is not used for mapping - smj[m_cfg.mapkey] = false; - bUtility = &(psMaterial->binUtility()); - } else { - // Now check if we have a homogeneous material - auto hsMaterial = - dynamic_cast<const Acts::HomogeneousSurfaceMaterial*>(&sMaterial); - if (hsMaterial != nullptr) { - // type is homogeneous - smj[m_cfg.typekey] = "homogeneous"; - smj[m_cfg.mapkey] = true; - if (m_cfg.writeData) { - smj[m_cfg.datakey] = json::array({ - json::array({ - encodeMaterialSlab(hsMaterial->materialSlab(0, 0)), - }), - }); - } - } else { - // Only option remaining: BinnedSurface material - auto bsMaterial = - dynamic_cast<const Acts::BinnedSurfaceMaterial*>(&sMaterial); - if (bsMaterial != nullptr) { - // type is binned - smj[m_cfg.typekey] = "binned"; - smj[m_cfg.mapkey] = true; - bUtility = &(bsMaterial->binUtility()); - // convert the data - // get the material matrix - if (m_cfg.writeData) { - json mmat = json::array(); - for (const auto& mpVector : bsMaterial->fullMaterial()) { - json mvec = json::array(); - for (const auto& mp : mpVector) { - mvec.push_back(encodeMaterialSlab(mp)); - } - mmat.push_back(std::move(mvec)); - } - smj[m_cfg.datakey] = std::move(mmat); - } - } - } - } - // add the bin utility - if (bUtility != nullptr && !bUtility->binningData().empty()) { - std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key}; - // loop over dimensions and write - auto& binningData = bUtility->binningData(); - // loop over the dimensions - for (size_t ibin = 0; ibin < binningData.size(); ++ibin) { - json binj; - auto cbData = binningData[ibin]; - binj.push_back(Acts::binningValueNames[cbData.binvalue]); - if (cbData.option == Acts::closed) { - binj.push_back("closed"); - } else { - binj.push_back("open"); - } - binj.push_back(cbData.bins()); - // If protoMaterial has a non uniform binning (non default) then it is - // used by default in the mapping - if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1) - smj[m_cfg.mapkey] = true; - // If it's not a proto map, write min / max - if (smj[m_cfg.typekey] != "proto") { - std::pair<double, double> minMax = {cbData.min, cbData.max}; - binj.push_back(minMax); - } - smj[binkeys[ibin]] = binj; - } - std::vector<double> transfo; - Acts::Transform3 transfo_matrix = bUtility->transform(); - if (not transfo_matrix.isApprox(Acts::Transform3::Identity())) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - transfo.push_back(transfo_matrix(j, i)); - } - } - smj[m_cfg.transfokeys] = transfo; - } - } - return smj; -} - -json Acts::FaserActsJsonGeometryConverter::volumeMaterialToJson( - const Acts::IVolumeMaterial& vMaterial) { - json smj; - // A bin utility needs to be written - const Acts::BinUtility* bUtility = nullptr; - // Check if we have a proto material - auto pvMaterial = dynamic_cast<const Acts::ProtoVolumeMaterial*>(&vMaterial); - if (pvMaterial != nullptr) { - // Type is proto material - smj[m_cfg.typekey] = "proto"; - // by default the protoMaterial is not used for mapping - smj[m_cfg.mapkey] = false; - bUtility = &(pvMaterial->binUtility()); - } else { - // Now check if we have a homogeneous material - auto hvMaterial = - dynamic_cast<const Acts::HomogeneousVolumeMaterial*>(&vMaterial); - if (hvMaterial != nullptr) { - // type is homogeneous - smj[m_cfg.typekey] = "homogeneous"; - smj[m_cfg.mapkey] = true; - if (m_cfg.writeData) { - // array of encoded materials w/ one entry - smj[m_cfg.datakey] = json::array({ - encodeMaterial(hvMaterial->material({0, 0, 0})), - }); - } - } else { - // Only option remaining: material map - auto bvMaterial2D = dynamic_cast< - const Acts::InterpolatedMaterialMap<MaterialMapper<MaterialGrid2D>>*>( - &vMaterial); - // Now check if we have a 2D map - if (bvMaterial2D != nullptr) { - // type is binned - smj[m_cfg.typekey] = "interpolated2D"; - smj[m_cfg.mapkey] = true; - bUtility = &(bvMaterial2D->binUtility()); - // convert the data - if (m_cfg.writeData) { - json mmat = json::array(); - MaterialGrid2D grid = bvMaterial2D->getMapper().getGrid(); - for (size_t bin = 0; bin < grid.size(); bin++) { - mmat.push_back(encodeMaterial(grid.at(bin))); - } - smj[m_cfg.datakey] = std::move(mmat); - } - } else { - // Only option remaining: material map - auto bvMaterial3D = dynamic_cast<const Acts::InterpolatedMaterialMap< - MaterialMapper<MaterialGrid3D>>*>(&vMaterial); - // Now check if we have a 3D map - if (bvMaterial3D != nullptr) { - // type is binned - smj[m_cfg.typekey] = "interpolated3D"; - smj[m_cfg.mapkey] = true; - bUtility = &(bvMaterial3D->binUtility()); - // convert the data - if (m_cfg.writeData) { - json mmat = json::array(); - MaterialGrid3D grid = bvMaterial3D->getMapper().getGrid(); - for (size_t bin = 0; bin < grid.size(); bin++) { - mmat.push_back(encodeMaterial(grid.at(bin))); - } - smj[m_cfg.datakey] = std::move(mmat); - } - } - } - } - } - // add the bin utility - if (bUtility != nullptr && !bUtility->binningData().empty()) { - std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key, - m_cfg.bin2key}; - // loop over dimensions and write - auto& binningData = bUtility->binningData(); - // loop over the dimensions - for (size_t ibin = 0; ibin < binningData.size(); ++ibin) { - json binj; - auto cbData = binningData[ibin]; - binj.push_back(Acts::binningValueNames[cbData.binvalue]); - if (cbData.option == Acts::closed) { - binj.push_back("closed"); - } else { - binj.push_back("open"); - } - binj.push_back(cbData.bins()); - // If protoMaterial has a non uniform binning (non default) then it is - // used by default in the mapping - if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1) - smj[m_cfg.mapkey] = true; - // If it's not a proto map, write min / max - if (smj[m_cfg.typekey] != "proto") { - std::pair<double, double> minMax = {cbData.min, cbData.max}; - binj.push_back(minMax); - } - smj[binkeys[ibin]] = binj; - } - std::vector<double> transfo; - Acts::Transform3 transfo_matrix = bUtility->transform(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - transfo.push_back(transfo_matrix(j, i)); - } - } - smj[m_cfg.transfokeys] = transfo; - } - return smj; -} - -void Acts::FaserActsJsonGeometryConverter::addSurfaceToJson(json& sjson, - const Surface* surface) { - // Get the ID of the surface (redundant but help readability) - std::ostringstream SurfaceID; - SurfaceID << surface->geometryId(); - sjson[m_cfg.surfacegeometryidkey] = SurfaceID.str(); - - // Cast the surface bound to both disk and cylinder - const Acts::SurfaceBounds& surfaceBounds = surface->bounds(); - auto sTransform = surface->transform(GeometryContext()); - - const Acts::RadialBounds* radialBounds = - dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds); - const Acts::CylinderBounds* cylinderBounds = - dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds); - const Acts::AnnulusBounds* annulusBounds = - dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds); - - if (radialBounds != nullptr) { - sjson[m_cfg.surfacetypekey] = "Disk"; - sjson[m_cfg.surfacepositionkey] = sTransform.translation().z(); - sjson[m_cfg.surfacerangekey] = {radialBounds->rMin(), radialBounds->rMax()}; - } - if (cylinderBounds != nullptr) { - sjson[m_cfg.surfacetypekey] = "Cylinder"; - sjson[m_cfg.surfacepositionkey] = cylinderBounds->get(CylinderBounds::eR); - sjson[m_cfg.surfacerangekey] = { - -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ), - cylinderBounds->get(CylinderBounds::eHalfLengthZ)}; - } - if (annulusBounds != nullptr) { - sjson[m_cfg.surfacetypekey] = "Annulus"; - sjson[m_cfg.surfacepositionkey] = sTransform.translation().z(); - sjson[m_cfg.surfacerangekey] = { - {annulusBounds->rMin(), annulusBounds->rMax()}, - {annulusBounds->phiMin(), annulusBounds->phiMax()}}; - } -} - -/// Create the Material Matrix -Acts::MaterialSlabMatrix Acts::FaserActsJsonGeometryConverter::jsonToMaterialMatrix( - const json& data) { - Acts::MaterialSlabMatrix mpMatrix; - // the input data must be array[array[object]] - for (auto& outer : data) { - Acts::MaterialSlabVector mpVector; - for (auto& inner : outer) { - mpVector.emplace_back(decodeMaterialSlab(inner)); - } - mpMatrix.push_back(std::move(mpVector)); - } - return mpMatrix; -} - -/// Create the BinUtility for this -Acts::BinUtility Acts::FaserActsJsonGeometryConverter::jsonToBinUtility( - const json& bin) { - if (bin.size() >= 3) { - // finding the iterator position to determine the binning value - auto bit = std::find(Acts::binningValueNames.begin(), - Acts::binningValueNames.end(), bin[0]); - size_t indx = std::distance(Acts::binningValueNames.begin(), bit); - Acts::BinningValue bval = Acts::BinningValue(indx); - Acts::BinningOption bopt = bin[1] == "open" ? Acts::open : Acts::closed; - unsigned int bins = bin[2]; - float min = 0; - float max = 0; - if (bin.size() >= 4 && bin[3].size() == 2) { - min = bin[3][0]; - max = bin[3][1]; - } - return Acts::BinUtility(bins, min, max, bopt, bval); - } - return Acts::BinUtility(); -} - -/// Create the local to global transform -Acts::Transform3 Acts::FaserActsJsonGeometryConverter::jsonToTransform( - const json& transfo) { - Transform3 transform; - int i = 0; - int j = 0; - for (auto& element : transfo) { - transform(j, i) = element; - j++; - if (j == 4) { - i++; - j = 0; - } - } - return transform; -} - -Acts::BinUtility Acts::FaserActsJsonGeometryConverter::DefaultBin( - const Acts::Surface& surface) { - Acts::BinUtility bUtility; - - const Acts::SurfaceBounds& surfaceBounds = surface.bounds(); - const Acts::RadialBounds* radialBounds = - dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds); - const Acts::CylinderBounds* cylinderBounds = - dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds); - const Acts::AnnulusBounds* annulusBounds = - dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds); - const Acts::RectangleBounds* rectangleBounds = - dynamic_cast<const Acts::RectangleBounds*>(&surfaceBounds); - - if (radialBounds != nullptr) { - bUtility += BinUtility( - 1, - radialBounds->get(RadialBounds::eAveragePhi) - - radialBounds->get(RadialBounds::eHalfPhiSector), - radialBounds->get(RadialBounds::eAveragePhi) + - radialBounds->get(RadialBounds::eHalfPhiSector), - (radialBounds->get(RadialBounds::eHalfPhiSector) - M_PI) < s_epsilon - ? Acts::closed - : Acts::open, - Acts::binPhi); - bUtility += BinUtility(1, radialBounds->rMin(), radialBounds->rMax(), - Acts::open, Acts::binR); - return bUtility; - } - if (cylinderBounds != nullptr) { - bUtility += BinUtility( - 1, - cylinderBounds->get(CylinderBounds::eAveragePhi) - - cylinderBounds->get(CylinderBounds::eHalfPhiSector), - cylinderBounds->get(CylinderBounds::eAveragePhi) + - cylinderBounds->get(CylinderBounds::eHalfPhiSector), - (cylinderBounds->get(CylinderBounds::eHalfPhiSector) - M_PI) < s_epsilon - ? Acts::closed - : Acts::open, - Acts::binPhi); - bUtility += - BinUtility(1, -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ), - cylinderBounds->get(CylinderBounds::eHalfLengthZ), - Acts::open, Acts::binZ); - return bUtility; - } - if (annulusBounds != nullptr) { - bUtility += BinUtility(1, annulusBounds->get(AnnulusBounds::eMinPhiRel), - annulusBounds->get(AnnulusBounds::eMaxPhiRel), - Acts::open, Acts::binPhi); - bUtility += BinUtility(1, annulusBounds->rMin(), annulusBounds->rMax(), - Acts::open, Acts::binR); - return bUtility; - } - if (rectangleBounds != nullptr) { - bUtility += BinUtility(1, rectangleBounds->get(RectangleBounds::eMinX), - rectangleBounds->get(RectangleBounds::eMaxX), - Acts::open, Acts::binX); - bUtility += BinUtility(1, rectangleBounds->get(RectangleBounds::eMinY), - rectangleBounds->get(RectangleBounds::eMaxY), - Acts::open, Acts::binY); - return bUtility; - } - ACTS_INFO( - "No corresponding bound found for the surface : " << surface.name()); - return bUtility; -} - -Acts::BinUtility Acts::FaserActsJsonGeometryConverter::DefaultBin( - const Acts::TrackingVolume& volume) { - Acts::BinUtility bUtility; - - auto cyBounds = - dynamic_cast<const CylinderVolumeBounds*>(&(volume.volumeBounds())); - auto cutcylBounds = - dynamic_cast<const CutoutCylinderVolumeBounds*>(&(volume.volumeBounds())); - auto cuBounds = - dynamic_cast<const CuboidVolumeBounds*>(&(volume.volumeBounds())); - - if (cyBounds != nullptr) { - bUtility += BinUtility(1, cyBounds->get(CylinderVolumeBounds::eMinR), - cyBounds->get(CylinderVolumeBounds::eMaxR), - Acts::open, Acts::binR); - bUtility += BinUtility( - 1, -cyBounds->get(CylinderVolumeBounds::eHalfPhiSector), - cyBounds->get(CylinderVolumeBounds::eHalfPhiSector), - (cyBounds->get(CylinderVolumeBounds::eHalfPhiSector) - M_PI) < s_epsilon - ? Acts::closed - : Acts::open, - Acts::binPhi); - bUtility += - BinUtility(1, -cyBounds->get(CylinderVolumeBounds::eHalfLengthZ), - cyBounds->get(CylinderVolumeBounds::eHalfLengthZ), - Acts::open, Acts::binZ); - return bUtility; - } - if (cutcylBounds != nullptr) { - bUtility += - BinUtility(1, cutcylBounds->get(CutoutCylinderVolumeBounds::eMinR), - cutcylBounds->get(CutoutCylinderVolumeBounds::eMaxR), - Acts::open, Acts::binR); - bUtility += BinUtility(1, -M_PI, M_PI, Acts::closed, Acts::binPhi); - bUtility += BinUtility( - 1, -cutcylBounds->get(CutoutCylinderVolumeBounds::eHalfLengthZ), - cutcylBounds->get(CutoutCylinderVolumeBounds::eHalfLengthZ), Acts::open, - Acts::binZ); - return bUtility; - } else if (cuBounds != nullptr) { - bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthX), - cuBounds->get(CuboidVolumeBounds::eHalfLengthX), - Acts::open, Acts::binX); - bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthY), - cuBounds->get(CuboidVolumeBounds::eHalfLengthY), - Acts::open, Acts::binY); - bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthZ), - cuBounds->get(CuboidVolumeBounds::eHalfLengthZ), - Acts::open, Acts::binZ); - return bUtility; - } - ACTS_INFO( - "No corresponding bound found for the volume : " << volume.volumeName()); - return bUtility; -} \ No newline at end of file diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx index df260a0f6e8da85b268940795f33775f54b60d5b..c5f6a68ab01b8da95f3d62149d23bdf41684263d 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsLayerBuilder.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + */ // ATHENA #include "TrackerReadoutGeometry/SiDetectorElement.h" #include "TrackerReadoutGeometry/SiDetectorElementCollection.h" @@ -11,11 +11,14 @@ #include "FaserActsGeometry/FaserActsDetectorElement.h" #include "FaserActsGeometry/CuboidVolumeBuilder.h" #include "ActsInterop/IdentityHelper.h" +#include "GeoModelKernel/GeoBox.h" +#include "GeoModelKernel/GeoTube.h" // ACTS #include "Acts/Material/ProtoSurfaceMaterial.hpp" #include "Acts/Surfaces/CylinderSurface.hpp" #include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/DiscSurface.hpp" #include "Acts/Surfaces/RectangleBounds.hpp" #include "Acts/Geometry/GenericApproachDescriptor.hpp" #include "Acts/Geometry/ApproachDescriptor.hpp" @@ -23,6 +26,7 @@ #include "Acts/Geometry/LayerCreator.hpp" #include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Definitions/Common.hpp" +#include "Acts/Geometry/PassiveLayerBuilder.hpp" #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/Units.hpp" #include "Acts/Utilities/BinningType.hpp" @@ -35,67 +39,132 @@ using namespace Acts::UnitLiterals; FaserActs::CuboidVolumeBuilder::Config FaserActsLayerBuilder::buildVolume(const Acts::GeometryContext& gctx) { - //Acts::CuboidVolumeBuilder::Config cvbConfig; FaserActs::CuboidVolumeBuilder::Config cvbConfig; - //std::vector<Acts::CuboidVolumeBuilder::VolumeConfig> volumeConfigs = {}; std::vector<FaserActs::CuboidVolumeBuilder::VolumeConfig> volumeConfigs = {}; - - for (int iStation=1; iStation<4; iStation++) { + //build the tracker stations + // 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++) { + + FaserActs::CuboidVolumeBuilder::VolumeConfig volumeConfig; - //Acts::CuboidVolumeBuilder::VolumeConfig volumeConfig; - FaserActs::CuboidVolumeBuilder::VolumeConfig volumeConfig; + std::vector<FaserActs::CuboidVolumeBuilder::LayerConfig> layerConfigs; + layerConfigs.clear(); - //std::vector<Acts::CuboidVolumeBuilder::LayerConfig> layerConfigs; - std::vector<FaserActs::CuboidVolumeBuilder::LayerConfig> layerConfigs; - layerConfigs.clear(); + for (int iPlane=0; iPlane<3; iPlane++) { - for (int iPlane=0; iPlane<3; iPlane++) { + m_cfg.station = iStation; + m_cfg.plane = iPlane; + std::vector<std::shared_ptr<const Acts::Surface>> surfaces; + surfaces.clear(); - m_cfg.station = iStation; - m_cfg.plane = iPlane; - std::vector<std::shared_ptr<const Acts::Surface>> surfaces; - surfaces.clear(); + FaserActs::CuboidVolumeBuilder::SurfaceConfig surfacecfg; - //Acts::CuboidVolumeBuilder::SurfaceConfig surfacecfg; - FaserActs::CuboidVolumeBuilder::SurfaceConfig surfacecfg; - - //Acts::CuboidVolumeBuilder::LayerConfig layercfg; - FaserActs::CuboidVolumeBuilder::LayerConfig layercfg; - layercfg.binsX = 2; - layercfg.binsY = 4; + FaserActs::CuboidVolumeBuilder::LayerConfig layercfg; + layercfg.binsX = 2; + layercfg.binsY = 4; - buildLayers(gctx, surfaces, layercfg, surfacecfg); + buildLayers(gctx, surfaces, layercfg, surfacecfg); - layercfg.surfaceCfg = surfacecfg; - layercfg.active = true; + layercfg.surfaceCfg = surfacecfg; + layercfg.active = true; - layercfg.surfaces = surfaces; - layerConfigs.push_back(layercfg); + layercfg.surfaces = surfaces; + layerConfigs.push_back(layercfg); - if (iPlane == 1) { - volumeConfig.position = Acts::Vector3(0, 0, surfacecfg.position.z()); - } - if (iStation == 0 && iPlane == 1) { - cvbConfig.position = Acts::Vector3(0, 0, surfacecfg.position.z()); - } + if (iPlane == 1) { + volumeConfig.position = Acts::Vector3(0, 0, surfacecfg.position.z()); + } } + volumeConfig.length = m_trackerDimensions; + volumeConfig.layerCfg = layerConfigs; + volumeConfig.name = "Station_" + std::to_string(iStation); + volumeConfigs.emplace_back(volumeConfig); - volumeConfig.length = m_trackerDimensions; - volumeConfig.layerCfg = layerConfigs; - volumeConfig.name = "Station_" + std::to_string(iStation); - volumeConfigs.push_back(volumeConfig); } - - //cvbConfig.position = m_worldCenter; + //build the veto/trigger stations + //first build veto station, then trigger station + //veto station + //Veto A, VetoRadiator, Veto B + auto vetoManager = static_cast<const GeoVDetectorManager*>(m_cfg.vetomng); + if(vetoManager!=nullptr){ + for(unsigned int i=0; i<vetoManager->getNumTreeTops(); i++){ + auto vol0 = vetoManager->getTreeTop(i)->getLogVol(); + //get the shape params and translation + const GeoBox* shape = dynamic_cast<const GeoBox*>(vol0->getShape()); + auto trans = vetoManager->getTreeTop(i)->getX(); + if(vetoManager->getTreeTop(i)->getNChildVols()==0){ + volumeConfigs.emplace_back(buildScintVolume(gctx, trans.translation().x(),trans.translation().y(),trans.translation().z(), shape->getXHalfLength(),shape->getYHalfLength(),shape->getZHalfLength(),vol0->getName())); + } + else{ + for(size_t j =0 ;j< vetoManager->getTreeTop(i)->getNChildVols();j++){ + auto childtrans=vetoManager->getTreeTop(i)->getXToChildVol(j); + const GeoBox* childshape = dynamic_cast<const GeoBox*>(vetoManager->getTreeTop(i)->getChildVol(j)->getLogVol()->getShape()); + volumeConfigs.emplace_back(buildScintVolume(gctx, trans.translation().x() + childtrans.translation().x(),trans.translation().y() + childtrans.translation().y(),trans.translation().z() + childtrans.translation().z(), childshape->getXHalfLength(), childshape->getXHalfLength(), childshape->getZHalfLength(),vol0->getName()+std::string("_")+std::to_string(j))); + } + } + } + } + //build trigger stations + auto triggerManager = static_cast<const GeoVDetectorManager*>(m_cfg.triggermng); + if(triggerManager!=nullptr){ + for(unsigned int i=0; i<triggerManager->getNumTreeTops(); i++){ + auto vol0 = triggerManager->getTreeTop(i)->getLogVol(); + //get the shape params and translation + const GeoBox* shape = dynamic_cast<const GeoBox*>(vol0->getShape()); + auto trans = triggerManager->getTreeTop(i)->getX(); + if(triggerManager->getTreeTop(i)->getNChildVols()==0){ + volumeConfigs.emplace_back(buildScintVolume(gctx, trans.translation().x(), trans.translation().y(),trans.translation().z(), shape->getXHalfLength(), shape->getYHalfLength(), shape->getZHalfLength(),vol0->getName())); + } + else{ + for(size_t j =0 ;j< triggerManager->getTreeTop(i)->getNChildVols();j++){ + auto childtrans=triggerManager->getTreeTop(i)->getXToChildVol(j); + const GeoBox* childshape = dynamic_cast<const GeoBox*>(triggerManager->getTreeTop(i)->getChildVol(j)->getLogVol()->getShape()); + volumeConfigs.emplace_back(buildScintVolume(gctx, trans.translation().x() + childtrans.translation().x(), trans.translation().y() + childtrans.translation().y(), trans.translation().z() + childtrans.translation().z(), childshape->getXHalfLength(), childshape->getYHalfLength(), childshape->getZHalfLength(),vol0->getName()+std::string("_")+std::to_string(j))); + } + } + } + } + + //build dipole magnets + auto dipoleManager = static_cast<const GeoVDetectorManager*>(m_cfg.dipolemng); + for(unsigned int i=0; i<dipoleManager->getNumTreeTops(); i++){ + auto vol0 = dipoleManager->getTreeTop(i)->getLogVol(); + //get the shape params and translation + const GeoTube* shape = dynamic_cast<const GeoTube*>(vol0->getShape()); + auto trans = dipoleManager->getTreeTop(i)->getX(); + if(dipoleManager->getTreeTop(i)->getNChildVols()==0){ + volumeConfigs.emplace_back(buildDipoleVolume(gctx, trans.translation().z(), shape->getZHalfLength(), shape->getRMin(), shape->getRMax(), vol0->getName()+std::string("_")+std::to_string(i))); + } + else{ + for(size_t j =0 ;j< dipoleManager->getTreeTop(i)->getNChildVols();j++){ + auto childtrans=dipoleManager->getTreeTop(i)->getXToChildVol(j); + const GeoTube* childshape = dynamic_cast<const GeoTube*>(dipoleManager->getTreeTop(i)->getChildVol(j)->getLogVol()->getShape()); + volumeConfigs.emplace_back(buildDipoleVolume(gctx, trans.translation().z() + childtrans.translation().z(), childshape->getZHalfLength(), childshape->getRMin(), childshape->getRMax(), vol0->getName()+std::string("_")+std::to_string(j))); + } + } + } + + //sort the geometry by the Z position, neccessary to have the correct boundary + auto sortFunc = [](FaserActs::CuboidVolumeBuilder::VolumeConfig& v1, FaserActs::CuboidVolumeBuilder::VolumeConfig& v2){return v1.position.z()<v2.position.z();}; + std::sort(volumeConfigs.begin(),volumeConfigs.end(), sortFunc); + //check volume positions + if (logger().doPrint(Acts::Logging::VERBOSE)) { + for(auto iter: volumeConfigs) ACTS_VERBOSE(" build volume centerred at Z = " << iter.position.z()); + } + + cvbConfig.position = m_worldCenter; cvbConfig.length = m_worldDimensions; cvbConfig.volumeCfg = volumeConfigs; return cvbConfig; } -void + void FaserActsLayerBuilder::buildLayers(const Acts::GeometryContext& gctx, std::vector<std::shared_ptr<const Surface>>& surfaces, FaserActs::CuboidVolumeBuilder::LayerConfig& layercfg, @@ -103,36 +172,35 @@ FaserActsLayerBuilder::buildLayers(const Acts::GeometryContext& gctx, { auto siDetMng = static_cast<const TrackerDD::SCT_DetectorManager*>(m_cfg.mng); - + for (int iRow = 0; iRow < 4; iRow++) { - for (int iModule = -1; iModule < 2; iModule++) { - for (int iSensor = 0; iSensor < 2; iSensor++) { - //for (int iSensor = 0; iSensor < 1; iSensor++) { // only use the first sensor to construct the surface + for (int iModule = -1; iModule < 2; iModule++) { + for (int iSensor = 0; iSensor < 2; iSensor++) { + + if (iModule == 0) continue; + const TrackerDD::SiDetectorElement* siDetElement = siDetMng->getDetectorElement(m_cfg.station, m_cfg.plane, iRow, iModule, iSensor) ; - if (iModule == 0) continue; - const TrackerDD::SiDetectorElement* siDetElement = siDetMng->getDetectorElement(m_cfg.station, m_cfg.plane, iRow, iModule, iSensor) ; + if (logger().doPrint(Acts::Logging::VERBOSE)) { + ACTS_VERBOSE("Found SCT sensor (" << m_cfg.station << "/" << m_cfg.plane << "/" << iRow << "/" << iModule << "/" << iSensor << ") with global center at (" << siDetElement->center().x() << ", " << siDetElement->center().y() << ", " << siDetElement->center().z() << ")." ); + } - if (logger().doPrint(Acts::Logging::VERBOSE)) { - ACTS_VERBOSE("Found SCT sensor (" << m_cfg.station << "/" << m_cfg.plane << "/" << iRow << "/" << iModule << "/" << iSensor << ") with global center at (" << siDetElement->center().x() << ", " << siDetElement->center().y() << ", " << siDetElement->center().z() << ")." ); - } + auto element = std::make_shared<const FaserActsDetectorElement>(siDetElement); - auto element = std::make_shared<const FaserActsDetectorElement>(siDetElement); + surfaces.push_back(element->surface().getSharedPtr()); - surfaces.push_back(element->surface().getSharedPtr()); + m_cfg.elementStore->push_back(element); - m_cfg.elementStore->push_back(element); - - m_ModuleWidth = siDetElement->width(); - m_ModuleLength = siDetElement->length(); - } - } + m_ModuleWidth = siDetElement->width(); + m_ModuleLength = siDetElement->length(); + } + } } Acts::ProtoLayer pl(gctx, surfaces); if (logger().doPrint(Acts::Logging::VERBOSE)) { - ACTS_VERBOSE(" Plane's zMin / zMax: " << pl.min(Acts::binZ) << " / " << pl.max(Acts::binZ)); + ACTS_VERBOSE(" Plane's zMin / zMax: " << pl.min(Acts::binZ) << " / " << pl.max(Acts::binZ)); } std::shared_ptr<const Acts::ProtoSurfaceMaterial> materialProxy = nullptr; @@ -146,54 +214,208 @@ FaserActsLayerBuilder::buildLayers(const Acts::GeometryContext& gctx, if (std::abs(layerZInner) > std::abs(layerZOuter)) std::swap(layerZInner, layerZOuter); - auto rBounds = std::make_shared<const Acts::RectangleBounds>( 0.5*layercfg.binsY*m_ModuleWidth, 0.5*layercfg.binsX*m_ModuleLength ) ; - - Transform3 transformNominal(Translation3(0., 0., layerZ)); - - Transform3 transformInner(Translation3(0., 0., layerZInner)); - - Transform3 transformOuter(Translation3(0., 0., layerZOuter)); - - std::shared_ptr<Acts::PlaneSurface> innerBoundary - = Acts::Surface::makeShared<Acts::PlaneSurface>(transformInner, rBounds); - - std::shared_ptr<Acts::PlaneSurface> nominalSurface - = Acts::Surface::makeShared<Acts::PlaneSurface>(transformNominal, rBounds); - - std::shared_ptr<Acts::PlaneSurface> outerBoundary - = Acts::Surface::makeShared<Acts::PlaneSurface>(transformOuter, rBounds); - - size_t matBinsX = layercfg.binsX; - size_t matBinsY = layercfg.binsY; - - Acts::BinUtility materialBinUtil( - matBinsX, -0.5*layercfg.binsY*m_ModuleWidth, 0.5*layercfg.binsY*m_ModuleWidth, Acts::open, Acts::binX); - materialBinUtil += Acts::BinUtility( - matBinsY, -0.5*layercfg.binsX*m_ModuleLength, 0.5*layercfg.binsX*m_ModuleLength, Acts::open, Acts::binY, transformInner); - - materialProxy - = std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil); - - ACTS_VERBOSE("[L] Layer is marked to carry support material on Surface ( " - "inner=0 / center=1 / outer=2 ) : " << "inner"); - ACTS_VERBOSE("with binning: [" << matBinsX << ", " << matBinsY << "]"); - - ACTS_VERBOSE("Created ApproachSurfaces for layer at:"); - ACTS_VERBOSE(" - inner: Z=" << layerZInner); - ACTS_VERBOSE(" - central: Z=" << layerZ); - ACTS_VERBOSE(" - outer: Z=" << layerZOuter); - - - // set material on inner - // @TODO: make this configurable somehow - innerBoundary->assignSurfaceMaterial(materialProxy); - - std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces; - aSurfaces.push_back(std::move(innerBoundary)); - aSurfaces.push_back(std::move(nominalSurface)); - aSurfaces.push_back(std::move(outerBoundary)); - - layercfg.approachDescriptor = new Acts::GenericApproachDescriptor(aSurfaces); - + auto rBounds = std::make_shared<const Acts::RectangleBounds>( 0.5*layercfg.binsY*m_ModuleWidth, 0.5*layercfg.binsX*m_ModuleLength ) ; + + Transform3 transformNominal(Translation3(0., 0., layerZ)); + + Transform3 transformInner(Translation3(0., 0., layerZInner)); + + Transform3 transformOuter(Translation3(0., 0., layerZOuter)); + + std::shared_ptr<Acts::PlaneSurface> innerBoundary + = Acts::Surface::makeShared<Acts::PlaneSurface>(transformInner, rBounds); + + std::shared_ptr<Acts::PlaneSurface> nominalSurface + = Acts::Surface::makeShared<Acts::PlaneSurface>(transformNominal, rBounds); + + std::shared_ptr<Acts::PlaneSurface> outerBoundary + = Acts::Surface::makeShared<Acts::PlaneSurface>(transformOuter, rBounds); + + size_t matBinsX = layercfg.binsX*m_cfg.MaterialBins.first; + size_t matBinsY = layercfg.binsY*m_cfg.MaterialBins.second; + + Acts::BinUtility materialBinUtil( + matBinsX, -0.5*layercfg.binsY*m_ModuleWidth, 0.5*layercfg.binsY*m_ModuleWidth, Acts::open, Acts::binX); + materialBinUtil += Acts::BinUtility( + matBinsY, -0.5*layercfg.binsX*m_ModuleLength, 0.5*layercfg.binsX*m_ModuleLength, Acts::open, Acts::binY, transformInner); + + materialProxy + = std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil); + + ACTS_VERBOSE("[L] Layer is marked to carry support material on Surface ( " + "inner=0 / center=1 / outer=2 ) : " << "inner"); + ACTS_VERBOSE("with binning: [" << matBinsX << ", " << matBinsY << "]"); + + ACTS_VERBOSE("Created ApproachSurfaces for layer at:"); + ACTS_VERBOSE(" - inner: Z=" << layerZInner); + ACTS_VERBOSE(" - central: Z=" << layerZ); + ACTS_VERBOSE(" - outer: Z=" << layerZOuter); + + + // set material on inner + // @TODO: make this configurable somehow + innerBoundary->assignSurfaceMaterial(materialProxy); + + + std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces; + aSurfaces.push_back(std::move(innerBoundary)); + aSurfaces.push_back(std::move(nominalSurface)); + aSurfaces.push_back(std::move(outerBoundary)); + + layercfg.approachDescriptor = new Acts::GenericApproachDescriptor(aSurfaces); + +} + + +FaserActs::CuboidVolumeBuilder::VolumeConfig FaserActsLayerBuilder::buildDipoleVolume(const Acts::GeometryContext& gctx, double zpos, double zhalflength, double rmin, double rmax, std::string name){ + + FaserActs::CuboidVolumeBuilder::VolumeConfig volumeConfig; + + std::vector<FaserActs::CuboidVolumeBuilder::LayerConfig> layerConfigs; + layerConfigs.clear(); + + FaserActs::CuboidVolumeBuilder::LayerConfig layercfg; + FaserActs::CuboidVolumeBuilder::SurfaceConfig surfacecfg; + surfacecfg.position = Acts::Vector3(0, 0, zpos); + surfacecfg.thickness=zhalflength; + + std::vector<std::shared_ptr<const Acts::Surface>> surfaces; + surfaces.clear(); + + layercfg.binsX = 1; + layercfg.binsY = 1; + + layercfg.active = true; + + //bounds are hard coded + layercfg.surfaceCfg = surfacecfg; + + Transform3 transformCenter(Translation3(0., 0., (zpos)*1_mm)); + + std::shared_ptr<Acts::DiscSurface> centerBoundary = + Acts::Surface::makeShared<Acts::DiscSurface>( + transformCenter, rmin, rmax); + + Transform3 transformInner(Translation3(0., 0., (zpos-zhalflength)*1_mm)); + + std::shared_ptr<Acts::DiscSurface> innerBoundary = + Acts::Surface::makeShared<Acts::DiscSurface>( + transformInner, rmin, rmax); + + Transform3 transformOuter(Translation3(0., 0., (zpos+zhalflength)*1_mm)); + + std::shared_ptr<Acts::DiscSurface> outerBoundary = + Acts::Surface::makeShared<Acts::DiscSurface>( + transformOuter, rmin, rmax); + + +// size_t matBinsX = m_cfg.MaterialBins.first; + size_t matBinsY = m_cfg.MaterialBins.second; +// set bin size to 1 at phi and MaterialBins-Y at r direction + Acts::BinUtility materialBinUtil(1, -M_PI, M_PI, Acts::closed, Acts::binPhi); + materialBinUtil += + Acts::BinUtility(matBinsY, rmin, rmax, Acts::open, Acts::binR, transformInner); + + std::shared_ptr<const Acts::ProtoSurfaceMaterial> materialProxy = + std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil); + + + innerBoundary->assignSurfaceMaterial(materialProxy); + + std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces; + aSurfaces.push_back(std::move(innerBoundary)); +// aSurfaces.push_back(std::move(centerBoundary)); +// aSurfaces.push_back(std::move(outerBoundary)); + Acts::ProtoLayer pl(gctx, aSurfaces); + + layercfg.surfaces = aSurfaces; + layercfg.approachDescriptor = new Acts::GenericApproachDescriptor(aSurfaces); + + layerConfigs.push_back(layercfg); + volumeConfig.position = Acts::Vector3(0, 0, zpos); + Acts::Vector3 length= { 500.0*1_mm, 500.0*1_mm, zhalflength*2.*1_mm }; + volumeConfig.length = length; + //volumeConfig.layerCfg = {}; + volumeConfig.layerCfg = layerConfigs; + volumeConfig.name = name; + + return volumeConfig; + } +FaserActs::CuboidVolumeBuilder::VolumeConfig FaserActsLayerBuilder::buildScintVolume(const Acts::GeometryContext& gctx, double xpos, double ypos, double zpos, double xhalflength, double yhalflength, double zhalflength, std::string name){ + + FaserActs::CuboidVolumeBuilder::VolumeConfig volumeConfig; + + std::vector<FaserActs::CuboidVolumeBuilder::LayerConfig> layerConfigs; + layerConfigs.clear(); + + FaserActs::CuboidVolumeBuilder::LayerConfig layercfg; + FaserActs::CuboidVolumeBuilder::SurfaceConfig surfacecfg; + surfacecfg.position = Acts::Vector3(xpos, ypos, zpos); + surfacecfg.thickness=zhalflength; + + std::vector<std::shared_ptr<const Acts::Surface>> surfaces; + surfaces.clear(); + + layercfg.binsX = 1; + layercfg.binsY = 1; + + layercfg.active = true; + + //bounds are hard coded + layercfg.surfaceCfg = surfacecfg; + + auto rBounds = std::make_shared<const Acts::RectangleBounds>( xhalflength*1_mm, yhalflength*1_mm) ; +// surfacecfg.rBounds=rBounds; + + + Transform3 transformInner(Translation3(xpos*1_mm, ypos*1_mm, (zpos-zhalflength)*1_mm)); + + std::shared_ptr<Acts::PlaneSurface> innerBoundary = + Acts::Surface::makeShared<Acts::PlaneSurface>( + transformInner, rBounds); + + Transform3 transformCenter(Translation3(xpos*1_mm, ypos*1_mm, zpos*1_mm)); + std::shared_ptr<Acts::PlaneSurface> centerBoundary = + Acts::Surface::makeShared<Acts::PlaneSurface>( + transformCenter, rBounds); + + Transform3 transformOuter(Translation3(xpos*1_mm, ypos*1_mm, (zpos+zhalflength)*1_mm)); + + std::shared_ptr<Acts::PlaneSurface> outerBoundary = + Acts::Surface::makeShared<Acts::PlaneSurface>( + transformOuter, rBounds); + + +// set bin size to 2 + Acts::BinUtility materialBinUtil(2, (0.-xhalflength)*1_mm, xhalflength*1_mm, Acts::open, Acts::binX); + materialBinUtil += + Acts::BinUtility(2, (0.-yhalflength)*1_mm, yhalflength*1_mm, Acts::open, Acts::binY, transformInner); + + std::shared_ptr<const Acts::ProtoSurfaceMaterial> materialProxy = + std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil); + + + innerBoundary->assignSurfaceMaterial(materialProxy); + + std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces; + aSurfaces.push_back(std::move(innerBoundary)); + aSurfaces.push_back(std::move(centerBoundary)); + aSurfaces.push_back(std::move(outerBoundary)); + Acts::ProtoLayer pl(gctx, aSurfaces); + + layercfg.surfaces = aSurfaces; + layercfg.approachDescriptor = new Acts::GenericApproachDescriptor(aSurfaces); + + layerConfigs.push_back(layercfg); + volumeConfig.position = Acts::Vector3(0, 0, zpos); + Acts::Vector3 length= { 500.0*1_mm, 500.0*1_mm, zhalflength*2.*1_mm }; + volumeConfig.length = length; + //volumeConfig.layerCfg = {}; + volumeConfig.layerCfg = layerConfigs; + volumeConfig.name = name; + + return volumeConfig; + +} diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx index feeb6f7a79425845048565d73f47f044dad45ccf..b138bc60a986ed75890b5f17c15fd46c2d043581 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.cxx @@ -2,10 +2,11 @@ Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsMaterialJsonWriterTool.h" +#include "FaserActsMaterialJsonWriterTool.h" #include "ActsInterop/Logger.h" + #include <fstream> #include <ios> #include <iostream> @@ -26,8 +27,8 @@ FaserActsMaterialJsonWriterTool::initialize() { ATH_MSG_INFO("Starting Material writer"); - m_cfg.name = "FaserActsJsonGeometryConverter"; - m_cfg.logger = makeActsAthenaLogger(this, "FaserActsJsonGeometryConverter"); +// m_cfg.name = "FaserActsJsonGeometryConverter"; +// m_cfg.logger = makeActsAthenaLogger(this, "FaserActsJsonGeometryConverter"); m_cfg.processSensitives = m_processSensitives; m_cfg.processApproaches = m_processApproaches; m_cfg.processRepresenting = m_processRepresenting; @@ -42,8 +43,9 @@ FaserActsMaterialJsonWriterTool::initialize() void FaserActsMaterialJsonWriterTool::write(const Acts::MaterialMapJsonConverter::DetectorMaterialMaps& detMaterial) const { + ATH_MSG_INFO("Start writing material"); // Evoke the converter - Acts::MaterialMapJsonConverter jmConverter(m_cfg); + Acts::MaterialMapJsonConverter jmConverter(m_cfg, Acts::Logging::INFO); auto jout = jmConverter.materialMapsToJson(detMaterial); // And write the file std::ofstream ofj(m_filePath); @@ -53,8 +55,9 @@ FaserActsMaterialJsonWriterTool::write(const Acts::MaterialMapJsonConverter::Det void FaserActsMaterialJsonWriterTool::write(const Acts::TrackingGeometry& tGeometry) const { + ATH_MSG_INFO("Start writing geometry"); // Evoke the converter - Acts::MaterialMapJsonConverter jmConverter(m_cfg); + Acts::MaterialMapJsonConverter jmConverter(m_cfg, Acts::Logging::INFO); auto jout = jmConverter.trackingGeometryToJson(tGeometry); // And write the file std::ofstream ofj(m_filePath); diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.h similarity index 94% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.h index c29a42c5c2ccf21db1c4c86a4c8fb4defd82a2b9..2e3b95faa7c88e80d31e055c243f9c8109c60b2a 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialJsonWriterTool.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialJsonWriterTool.h @@ -2,8 +2,8 @@ Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ -#ifndef ACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H -#define ACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H +#ifndef FASERACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H +#define FASERACTSGEOMETRY_FASERACTSMATERIALJSONWRITERTOOL_H // ATHENA #include "AthenaBaseComps/AthAlgTool.h" diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx index 37031b416dca13ce8755914aa89b14dae9fee3ab..2595b42dc613db98997d4ca5c8ded263e65a9963 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.cxx @@ -1,8 +1,8 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ -#include "FaserActsGeometry/FaserActsMaterialMapping.h" +#include "FaserActsMaterialMapping.h" // ATHENA #include "Acts/Surfaces/PerigeeSurface.hpp" @@ -18,7 +18,7 @@ // PACKAGE #include "FaserActsGeometry/FaserActsGeometryContext.h" -#include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h" +#include "FaserActsGeometryInterfaces/IFaserActsPropStepRootWriterSvc.h" // STL #include <fstream> @@ -33,12 +33,12 @@ #include "Acts/Propagator/StraightLineStepper.hpp" FaserActsMaterialMapping::FaserActsMaterialMapping(const std::string &name, - ISvcLocator *pSvcLocator) - : AthReentrantAlgorithm(name, pSvcLocator), - m_materialTrackWriterSvc("ActsMaterialTrackWriterSvc", name), - m_inputMaterialStepCollection("MaterialStepRecords"), - m_mappingState(m_gctx,m_mctx), - m_mappingStateVol(m_gctx,m_mctx) + ISvcLocator *pSvcLocator) + : AthReentrantAlgorithm(name, pSvcLocator), + m_materialTrackWriterSvc("FaserActsMaterialTrackWriterSvc", name), + m_inputMaterialStepCollection("MaterialStepRecords"), + m_mappingState(m_gctx,m_mctx), + m_mappingStateVol(m_gctx,m_mctx) {} StatusCode FaserActsMaterialMapping::initialize() { @@ -49,7 +49,6 @@ StatusCode FaserActsMaterialMapping::initialize() { return StatusCode::FAILURE; } - ATH_CHECK(m_materialStepConverterTool.retrieve() ); ATH_CHECK(m_materialTrackWriterSvc.retrieve() ); if(m_mapSurfaces){ ATH_CHECK(m_surfaceMappingTool.retrieve() ); @@ -60,7 +59,7 @@ StatusCode FaserActsMaterialMapping::initialize() { m_mappingStateVol = m_volumeMappingTool->mappingState(); } ATH_CHECK(m_materialJsonWriterTool.retrieve() ); - ATH_CHECK( m_inputMaterialStepCollection.initialize() ); + ATH_CHECK(m_inputMaterialStepCollection.initialize() ); return StatusCode::SUCCESS; } @@ -69,16 +68,88 @@ StatusCode FaserActsMaterialMapping::execute(const EventContext &ctx) const { Acts::RecordedMaterialTrack mTrack; SG::ReadHandle<Trk::MaterialStepCollection> materialStepCollection(m_inputMaterialStepCollection, ctx); - mTrack = m_materialStepConverterTool->convertToMaterialTrack(*materialStepCollection); + + //make material track collection + Trk::MaterialStepCollection::const_iterator iter = materialStepCollection->begin(); + Trk::MaterialStepCollection::const_iterator iter_end = materialStepCollection->end(); + Trk::MaterialStepCollection* newmaterialStepCollection= new Trk::MaterialStepCollection; + //remove the material at Z>2500mm + //need further study + for(; iter != iter_end; ++iter){ + const Trk::MaterialStep* mat = *iter; + Trk::MaterialStep* newmat = const_cast<Trk::MaterialStep*>(mat); + //remove the magnets, need to be updated +// if((newmat->hitZ()<-1600&&newmat->hitZ()>-1920)||(newmat->hitZ()>-200&&newmat->hitZ()<100)||(newmat->hitZ()>1000&&newmat->hitZ()<1300)||(newmat->hitZ()>2000&&newmat->hitZ()<2500)) + if(newmat->hitZ()>-1920&&newmat->hitZ()<2500) + newmaterialStepCollection->push_back(newmat); + } + if(newmaterialStepCollection->size()<1) + return StatusCode::SUCCESS; + + /* test */ + std::vector<Acts::MaterialInteraction> nStep; + Acts::RecordedMaterial recorded; + double sum_X0 = 0; + double sum_L0 = 0; + + double x_length = newmaterialStepCollection->back()->hitX() - newmaterialStepCollection->front()->hitX(); + double y_length = newmaterialStepCollection->back()->hitY() - newmaterialStepCollection->front()->hitY(); + double z_length = newmaterialStepCollection->back()->hitZ() - newmaterialStepCollection->front()->hitZ(); + + double norm = 1/(std::sqrt(x_length*x_length + + y_length*y_length + + z_length*z_length)); + //set the initial z position to -4000 + double z_ini=-4000.; + Acts::Vector3 v_pos{newmaterialStepCollection->front()->hitX()-(newmaterialStepCollection->front()->hitZ()-z_ini)*(newmaterialStepCollection->front()->hitX()-newmaterialStepCollection->back()->hitX())/(newmaterialStepCollection->front()->hitZ()-newmaterialStepCollection->back()->hitZ()),newmaterialStepCollection->front()->hitY()-(newmaterialStepCollection->front()->hitZ()-z_ini)*(newmaterialStepCollection->front()->hitY()-newmaterialStepCollection->back()->hitY())/(newmaterialStepCollection->front()->hitZ()-newmaterialStepCollection->back()->hitZ()),z_ini}; + Acts::Vector3 v_imp{x_length*norm, y_length*norm, z_length*norm}; + Acts::Vector3 prev_pos = v_pos; + for(auto const step: *newmaterialStepCollection) { + + Acts::MaterialInteraction interaction; + + Acts::Vector3 pos{step->hitX(), step->hitY(), step->hitZ()}; + Acts::MaterialSlab matProp(Acts::Material::fromMassDensity(step->x0(), step->l0(), step->A(), step->Z(), (step->rho() * Acts::UnitConstants::g) ),step->steplength()); + interaction.position = pos; + + double x_dir = pos.x() - prev_pos.x(); + double y_dir = pos.y() - prev_pos.y(); + double z_dir = pos.z() - prev_pos.z(); + double norm_dir = 1/(std::sqrt(x_dir*x_dir + + y_dir*y_dir + + z_dir*z_dir)); + + Acts::Vector3 dir{x_dir * norm_dir, y_dir * norm_dir, z_dir * norm_dir}; + interaction.direction = dir; + prev_pos = pos; + interaction.materialSlab = matProp; + sum_X0 += step->steplengthInX0(); + sum_L0 += step->steplengthInL0(); + nStep.push_back(interaction); + } + recorded.materialInX0 = sum_X0; + recorded.materialInL0 = sum_L0; + recorded.materialInteractions = nStep; + + mTrack = std::make_pair(std::make_pair(v_pos, v_imp), recorded); if(m_mapSurfaces){ + ATH_MSG_INFO(name() << " start surface mapping"); auto mappingState - = const_cast<Acts::SurfaceMaterialMapper::State *>(&m_mappingState); + = const_cast<Acts::SurfaceMaterialMapper::State *>(&m_mappingState); + auto context = m_surfaceMappingTool->trackingGeometryTool()->getNominalGeometryContext().context(); + std::reference_wrapper<const Acts::GeometryContext> geoContext(context); + mappingState->geoContext = geoContext; + m_surfaceMappingTool->mapper()->mapMaterialTrack(*mappingState, mTrack); } if(m_mapVolumes){ + ATH_MSG_INFO(name() << " start volume mapping"); auto mappingStateVol - = const_cast<Acts::VolumeMaterialMapper::State *>(&m_mappingStateVol); + = const_cast<Acts::VolumeMaterialMapper::State *>(&m_mappingStateVol); + auto context = m_volumeMappingTool->trackingGeometryTool()->getNominalGeometryContext().context(); + std::reference_wrapper<const Acts::GeometryContext> geoContext(context); + mappingStateVol->geoContext = geoContext; m_volumeMappingTool->mapper()->mapMaterialTrack(*mappingStateVol, mTrack); } m_materialTrackWriterSvc->write(mTrack); @@ -108,28 +179,28 @@ StatusCode FaserActsMaterialMapping::finalize() { m_surfaceMappingTool->mapper()->finalizeMaps(m_mappingState); // Loop over the state, and collect the maps for surfaces for (auto& [key, value] : m_mappingState.surfaceMaterial) { - detectorMaterial.first.insert({key, std::move(value)}); + detectorMaterial.first.insert({key, std::move(value)}); } // Loop over the state, and collect the maps for volumes for (auto& [key, value] : m_mappingState.volumeMaterial) { - detectorMaterial.second.insert({key, std::move(value)}); + detectorMaterial.second.insert({key, std::move(value)}); } } if(m_mapVolumes){ m_volumeMappingTool->mapper()->finalizeMaps(m_mappingStateVol); // Loop over the state, and collect the maps for surfaces for (auto& [key, value] : m_mappingStateVol.surfaceMaterial) { - detectorMaterial.first.insert({key, std::move(value)}); + detectorMaterial.first.insert({key, std::move(value)}); } // Loop over the state, and collect the maps for volumes for (auto& [key, value] : m_mappingStateVol.volumeMaterial) { - detectorMaterial.second.insert({key, std::move(value)}); + detectorMaterial.second.insert({key, std::move(value)}); } } } - + m_materialJsonWriterTool->write(detectorMaterial); return StatusCode::SUCCESS; -} \ No newline at end of file +} diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.h similarity index 91% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.h index bdeb9a7b010b652b13ccaf7fd9986755e8dac8eb..8ddd2a38a8cf7426f6f1c03ec1268ce3c48a0637 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsMaterialMapping.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialMapping.h @@ -22,7 +22,6 @@ #include "Acts/Material/VolumeMaterialMapper.hpp" // PACKAGE #include "ActsGeometryInterfaces/IActsMaterialTrackWriterSvc.h" -#include "ActsGeometryInterfaces/IActsMaterialStepConverterTool.h" #include "FaserActsGeometryInterfaces/IFaserActsSurfaceMappingTool.h" #include "FaserActsGeometryInterfaces/IFaserActsVolumeMappingTool.h" #include "FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h" @@ -59,7 +58,6 @@ private: ServiceHandle<IActsMaterialTrackWriterSvc> m_materialTrackWriterSvc; Gaudi::Property<bool> m_mapSurfaces{this, "mapSurfaces", true, "Map the material onto surfaces"}; Gaudi::Property<bool> m_mapVolumes{this, "mapVolumes", true, "Map the material onto volumes"}; - ToolHandle<IActsMaterialStepConverterTool> m_materialStepConverterTool{this, "MaterialStepConverterTool", "ActsMaterialStepConverterTool"}; SG::ReadHandleKey<Trk::MaterialStepCollection> m_inputMaterialStepCollection; ToolHandle<IFaserActsSurfaceMappingTool> m_surfaceMappingTool{this, "SurfaceMappingTool", "FaserActsSurfaceMappingTool"}; ToolHandle<IFaserActsVolumeMappingTool> m_volumeMappingTool{this, "VolumeMappingTool", "FaserActsVolumeMappingTool"}; @@ -71,4 +69,4 @@ private: Acts::VolumeMaterialMapper::State m_mappingStateVol; }; -#endif // ActsGeometry_ActsExtrapolation_h \ No newline at end of file +#endif // ActsGeometry_ActsExtrapolation_h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4be4256806813badf59f9f56a9378f56505fa822 --- /dev/null +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.cxx @@ -0,0 +1,354 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#include "FaserActsMaterialTrackWriterSvc.h" +#include "FaserActsGeometry/FaserActsGeometryContext.h" +#include "GaudiKernel/IInterface.h" + +#include "TTree.h" +#include "TFile.h" + +#include "Acts/Material/MaterialSlab.hpp" +#include <Acts/Geometry/GeometryIdentifier.hpp> +#include <Acts/Surfaces/CylinderBounds.hpp> +#include <Acts/Surfaces/RadialBounds.hpp> +#include <Acts/Utilities/Helpers.hpp> + +using namespace Acts::VectorHelpers; + +#include <vector> +#include <deque> +#include <mutex> +#include <thread> + +FaserActsMaterialTrackWriterSvc::FaserActsMaterialTrackWriterSvc( const std::string& name, ISvcLocator* svc ) + : base_class(name, svc), + m_trackingGeometrySvc("FaserActsTrackingGeometrySvc", name) { + } + + StatusCode +FaserActsMaterialTrackWriterSvc::initialize() +{ + + std::string filePath = m_filePath; + std::string treeName = m_treeName; + p_tFile = TFile::Open(filePath.c_str(), "RECREATE"); + p_tFile->cd(); + p_tree = new TTree(treeName.c_str(), treeName.c_str()); + + p_tree->Branch("v_x", &m_v_x); + p_tree->Branch("v_y", &m_v_y); + p_tree->Branch("v_z", &m_v_z); + p_tree->Branch("v_px", &m_v_px); + p_tree->Branch("v_py", &m_v_py); + p_tree->Branch("v_pz", &m_v_pz); + p_tree->Branch("v_phi", &m_v_phi); + p_tree->Branch("v_eta", &m_v_eta); + + p_tree->Branch("t_X0", &m_tX0); + p_tree->Branch("t_L0", &m_tL0); + + p_tree->Branch("mat_x", &m_step_x); + p_tree->Branch("mat_y", &m_step_y); + p_tree->Branch("mat_z", &m_step_z); + p_tree->Branch("mat_dx", &m_step_dx); + p_tree->Branch("mat_dy", &m_step_dy); + p_tree->Branch("mat_dz", &m_step_dz); + p_tree->Branch("mat_step_length", &m_step_length); + p_tree->Branch("mat_X0", &m_step_X0); + p_tree->Branch("mat_L0", &m_step_L0); + p_tree->Branch("mat_A", &m_step_A); + p_tree->Branch("mat_Z", &m_step_Z); + p_tree->Branch("mat_rho", &m_step_rho); + + if (m_storeSurface) { + p_tree->Branch("sur_id", &m_sur_id); + p_tree->Branch("sur_type", &m_sur_type); + p_tree->Branch("sur_x", &m_sur_x); + p_tree->Branch("sur_y", &m_sur_y); + p_tree->Branch("sur_z", &m_sur_z); + p_tree->Branch("sur_range_min", &m_sur_range_min); + p_tree->Branch("sur_range_max", &m_sur_range_max); + } + if (m_storeVolume) { + p_tree->Branch("vol_id", &m_vol_id); + } + + ATH_MSG_INFO("Starting writer thread"); + ATH_MSG_DEBUG("Maximum queue size is set to:" << m_maxQueueSize); + m_doEnd = false; + m_writeThread = std::thread(&FaserActsMaterialTrackWriterSvc::writerThread, this); + + return StatusCode::SUCCESS; +} + + StatusCode +FaserActsMaterialTrackWriterSvc::finalize() +{ + + ATH_MSG_INFO("Waiting for writer thread to finish."); + m_doEnd = true; + m_writeThread.join(); + ATH_MSG_INFO("Writer thread has terminated."); + + ATH_MSG_INFO("Closing TFile"); + p_tFile->cd(); + p_tree->FlushBaskets(); + p_tree->AutoSave(); + p_tree->Write(); + p_tFile->Write(); + p_tFile->Close(); + + return StatusCode::SUCCESS; +} + + void +FaserActsMaterialTrackWriterSvc::write(const Acts::RecordedMaterialTrack& mTrack) +{ + std::lock_guard<std::mutex> lock(m_writeMutex); + + ATH_MSG_VERBOSE("Appending material track to write queue"); + m_mTracks.push_back(mTrack); +} + + void +FaserActsMaterialTrackWriterSvc::writerThread() +{ + using namespace std::chrono_literals; + // wait until we have events + while(m_mTracks.size() == 0) { + std::this_thread::sleep_for(2s); + if (m_doEnd) return; + } + + ATH_MSG_DEBUG("Begin regular write loop"); + while(true) { + ATH_MSG_VERBOSE("Obtaining write lock"); + std::unique_lock<std::mutex> lock(m_writeMutex); + + if (m_mTracks.empty()) { + lock.unlock(); + if (!m_doEnd) { + ATH_MSG_VERBOSE("Queue was empty, delay next execution"); + std::this_thread::sleep_for(0.1s); + continue; + } else { + ATH_MSG_INFO("Writer thread caught termination signal. Shutting down."); + + return; + } + } + + + if(m_mTracks.size() < m_maxQueueSize) { + // just pop one + ATH_MSG_VERBOSE("Queue at " << m_mTracks.size() << "/" << m_maxQueueSize + << ": Pop entry and write"); + Acts::RecordedMaterialTrack mTrack = std::move(m_mTracks.front()); + m_mTracks.pop_front(); + // writing can now happen without lock + lock.unlock(); + doWrite(std::move(mTrack)); + } + else { + ATH_MSG_DEBUG("Queue at " << m_mTracks.size() << "/" << m_maxQueueSize + << ": Lock and write until empty"); + while(!m_mTracks.empty()) { + ATH_MSG_VERBOSE("Pop entry and write"); + // keep the lock! + Acts::RecordedMaterialTrack mTrack = std::move(m_mTracks.front()); + m_mTracks.pop_front(); + doWrite(std::move(mTrack)); + } + ATH_MSG_DEBUG("Queue is empty, continue"); + + } + } +} + + void +FaserActsMaterialTrackWriterSvc::doWrite(const Acts::RecordedMaterialTrack& mTrack) +{ + ATH_MSG_VERBOSE("Write to tree"); + size_t mints = mTrack.second.materialInteractions.size(); + + // Clearing the vector first + m_step_sx.clear(); + m_step_sy.clear(); + m_step_sz.clear(); + m_step_x.clear(); + m_step_y.clear(); + m_step_z.clear(); + m_step_ex.clear(); + m_step_ey.clear(); + m_step_ez.clear(); + m_step_dx.clear(); + m_step_dy.clear(); + m_step_dz.clear(); + m_step_length.clear(); + m_step_X0.clear(); + m_step_L0.clear(); + m_step_A.clear(); + m_step_Z.clear(); + m_step_rho.clear(); + + if(m_storeSurface){ + m_sur_id.clear(); + m_sur_type.clear(); + m_sur_x.clear(); + m_sur_y.clear(); + m_sur_z.clear(); + m_sur_range_min.clear(); + m_sur_range_max.clear(); + } + + if (m_storeVolume) { + m_vol_id.clear(); + } + // Reserve the vector then + m_step_sx.reserve(mints); + m_step_sy.reserve(mints); + m_step_sz.reserve(mints); + m_step_x.reserve(mints); + m_step_y.reserve(mints); + m_step_ez.reserve(mints); + m_step_ex.reserve(mints); + m_step_ey.reserve(mints); + m_step_ez.reserve(mints); + m_step_dx.reserve(mints); + m_step_dy.reserve(mints); + m_step_dz.reserve(mints); + m_step_length.reserve(mints); + m_step_X0.reserve(mints); + m_step_L0.reserve(mints); + m_step_A.reserve(mints); + m_step_Z.reserve(mints); + m_step_rho.reserve(mints); + + if(m_storeSurface){ + m_sur_id.reserve(mints); + m_sur_type.reserve(mints); + m_sur_x.reserve(mints); + m_sur_y.reserve(mints); + m_sur_z.reserve(mints); + m_sur_range_min.reserve(mints); + m_sur_range_max.reserve(mints); + } + if (m_storeVolume) { + m_vol_id.reserve(mints); + } + + // reset the global counter + m_tX0 = mTrack.second.materialInX0; + m_tL0 = mTrack.second.materialInL0; + + // set the track information at vertex + m_v_x = mTrack.first.first.x(); + m_v_y = mTrack.first.first.y(); + m_v_z = mTrack.first.first.z(); + m_v_px = mTrack.first.second.x(); + m_v_py = mTrack.first.second.y(); + m_v_pz = mTrack.first.second.z(); + m_v_phi = phi(mTrack.first.second); + m_v_eta = eta(mTrack.first.second); + + // an now loop over the material + for (auto& mint : mTrack.second.materialInteractions) { + // The material step position information + m_step_x.push_back(mint.position.x()); + m_step_y.push_back(mint.position.y()); + m_step_z.push_back(mint.position.z()); + m_step_dx.push_back(mint.direction.x()); + m_step_dy.push_back(mint.direction.y()); + m_step_dz.push_back(mint.direction.z()); + + Acts::Vector3 prePos + = mint.position - 0.5 * mint.pathCorrection * mint.direction; + Acts::Vector3 posPos + = mint.position + 0.5 * mint.pathCorrection * mint.direction; + m_step_sx.push_back(prePos.x()); + m_step_sy.push_back(prePos.y()); + m_step_sz.push_back(prePos.z()); + m_step_ex.push_back(posPos.x()); + m_step_ey.push_back(posPos.y()); + m_step_ez.push_back(posPos.z()); + + if (m_storeSurface) { + const Acts::Surface* surface = mint.surface; + Acts::GeometryIdentifier layerID; + if (surface) { + auto gctx = std::make_unique<FaserActsGeometryContext>(); + gctx->alignmentStore = m_trackingGeometrySvc->getNominalAlignmentStore(); + auto sfIntersection = surface->intersect( + gctx->context(), mint.position, mint.direction, true); + layerID = surface->geometryId(); + m_sur_id.push_back(layerID.value()); + m_sur_type.push_back(surface->type()); + m_sur_x.push_back(sfIntersection.intersection.position.x()); + m_sur_y.push_back(sfIntersection.intersection.position.y()); + m_sur_z.push_back(sfIntersection.intersection.position.z()); + + const Acts::SurfaceBounds& surfaceBounds = surface->bounds(); + const Acts::RadialBounds* radialBounds = + dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds); + const Acts::CylinderBounds* cylinderBounds = + dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds); + + if (radialBounds) { + m_sur_range_min.push_back(radialBounds->rMin()); + m_sur_range_max.push_back(radialBounds->rMax()); + } else if (cylinderBounds) { + m_sur_range_min.push_back( + -cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ)); + m_sur_range_max.push_back( + cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ)); + } else { + m_sur_range_min.push_back(0); + m_sur_range_max.push_back(0); + } + } else { + layerID.setVolume(0); + layerID.setBoundary(0); + layerID.setLayer(0); + layerID.setApproach(0); + layerID.setSensitive(0); + m_sur_id.push_back(layerID.value()); + m_sur_type.push_back(-1); + + m_sur_x.push_back(0); + m_sur_y.push_back(0); + m_sur_z.push_back(0); + m_sur_range_min.push_back(0); + m_sur_range_max.push_back(0); + } + } + // store volume information + if (m_storeVolume) { + const Acts::Volume* volume = mint.volume; + Acts::GeometryIdentifier vlayerID; + if (volume) { + vlayerID = volume->geometryId(); + m_vol_id.push_back(vlayerID.value()); + } else { + vlayerID.setVolume(0); + vlayerID.setBoundary(0); + vlayerID.setLayer(0); + vlayerID.setApproach(0); + vlayerID.setSensitive(0); + m_vol_id.push_back(vlayerID.value()); + } + } + // the material information + const auto& mprops = mint.materialSlab; + m_step_length.push_back(mprops.thickness()); + m_step_X0.push_back(mprops.material().X0()); + m_step_L0.push_back(mprops.material().L0()); + m_step_A.push_back(mprops.material().Ar()); + m_step_Z.push_back(mprops.material().Z()); + m_step_rho.push_back(mprops.material().massDensity()); + + } + p_tree->Fill(); + ATH_MSG_VERBOSE("Write complete"); +} diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..962ffbb9c479223e51fd285865832898025ddbcb --- /dev/null +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsMaterialTrackWriterSvc.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ + +#ifndef FASERACTSGEOMETRY_FASERACTSMATERIALTRACKWRITERSVC_H +#define FASERACTSGEOMETRY_FASERACTSMATERIALTRACKWRITERSVC_H + +#include "ActsGeometryInterfaces/IActsMaterialTrackWriterSvc.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometrySvc.h" + +#include "AthenaBaseComps/AthService.h" +#include "StoreGate/StoreGateSvc.h" +//#include "GaudiKernel/IInterface.h" +//#include "Gaudi/Property.h" /*no forward decl: typedef*/ + +#include <vector> +#include <deque> +#include <mutex> +#include <thread> +#include <atomic> + +#include "TTree.h" +#include "TFile.h" + +class FaserActsMaterialTrackWriterSvc : public extends<AthService, IActsMaterialTrackWriterSvc> { + public: + + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + FaserActsMaterialTrackWriterSvc( const std::string& name, ISvcLocator* svc ); + + virtual void + write(const Acts::RecordedMaterialTrack& mTrack) override; + + private: + + std::deque<Acts::RecordedMaterialTrack> m_mTracks; + std::mutex m_writeMutex; + std::thread m_writeThread; + std::atomic<bool> m_doEnd; + TFile* p_tFile; + TTree* p_tree; + + float m_v_x; ///< start global x + float m_v_y; ///< start global y + float m_v_z; ///< start global z + float m_v_px; ///< start global momentum x + float m_v_py; ///< start global momentum y + float m_v_pz; ///< start global momentum z + float m_v_phi; ///< start phi direction + float m_v_eta; ///< start eta direction + float m_tX0; ///< thickness in X0/L0 + float m_tL0; ///< thickness in X0/L0 + + std::vector<float> m_step_sx; ///< step x (start) position (optional) + std::vector<float> m_step_sy; ///< step y (start) position (optional) + std::vector<float> m_step_sz; ///< step z (start) position (optional) + std::vector<float> m_step_x; ///< step x position + std::vector<float> m_step_y; ///< step y position + std::vector<float> m_step_z; ///< step z position + std::vector<float> m_step_ex; ///< step x (end) position (optional) + std::vector<float> m_step_ey; ///< step y (end) position (optional) + std::vector<float> m_step_ez; ///< step z (end) position (optional) + std::vector<float> m_step_dx; ///< step x direction + std::vector<float> m_step_dy; ///< step y direction + std::vector<float> m_step_dz; ///< step z direction + std::vector<float> m_step_length; ///< step length + std::vector<float> m_step_X0; ///< step material x0 + std::vector<float> m_step_L0; ///< step material l0 + std::vector<float> m_step_A; ///< step material A + std::vector<float> m_step_Z; ///< step material Z + std::vector<float> m_step_rho; ///< step material rho + + std::vector<std::uint64_t> + m_sur_id; ///< ID of the suface associated with the step + std::vector<int32_t> + m_sur_type; ///< Type of the suface associated with the step + std::vector<float> m_sur_x; ///< x position of the center of the suface + ///< associated with the step + std::vector<float> m_sur_y; ///< y position of the center of the suface + ///< associated with the step + std::vector<float> m_sur_z; ///< z position of the center of the suface + ///< associated with the step + + std::vector<float> + m_sur_range_min; ///< Min range of the suface associated with the step + std::vector<float> + m_sur_range_max; ///< Max range of the suface associated with the step + + std::vector<std::uint64_t> + m_vol_id; ///< ID of the volume associated with the step + + void writerThread(); + void doWrite(const Acts::RecordedMaterialTrack &mTrack); + + ServiceHandle<IFaserActsTrackingGeometrySvc> m_trackingGeometrySvc; + + // jobOptions properties + Gaudi::Property<std::string> m_filePath{this, "FilePath", "MaterialTracks.root", "Output root file for charged particle"}; + Gaudi::Property<std::string> m_treeName{this, "TreeName", "material-tracks", ""}; + Gaudi::Property<bool> m_storeSurface{this, "StoreSurface", true, "Store the surface info in the root file"}; + Gaudi::Property<bool> m_storeVolume{this, "StoreVolume", true, "Store the volume info in the root file"}; + Gaudi::Property<size_t> m_maxQueueSize{this, "MaxQueueSize", 5000, "Limit the write queue to this size"}; + +}; + + +#endif diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.cxx index 35da191fc41ab08138a469e2abce9756d5886c53..e6ac8720afce50a54321625bfc2cc789b507b7fe 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsObjWriterTool.h" +#include "FaserActsObjWriterTool.h" // std #include <iostream> diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsObjWriterTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsObjWriterTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsObjWriterTool.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.cxx index 6d24eba82942c74fe560ecdb6989daf51a8ce4d1..18b4177289b9e40504350f29ee56dbbfd8d14e37 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsPropStepRootWriterSvc.h" +#include "FaserActsPropStepRootWriterSvc.h" #include "GaudiKernel/IInterface.h" #include "Acts/Propagator/detail/SteppingLogger.hpp" diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsPropStepRootWriterSvc.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.h similarity index 86% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsPropStepRootWriterSvc.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.h index eeca580eb76f82fced49477a8ca1067cbea8d472..2f840479b3580bebdaff2dbf1c4737033559a200 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsPropStepRootWriterSvc.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsPropStepRootWriterSvc.h @@ -9,7 +9,7 @@ #include "GaudiKernel/IInterface.h" #include "Gaudi/Property.h" /*no forward decl: typedef*/ -#include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h" +#include "FaserActsGeometryInterfaces/IFaserActsPropStepRootWriterSvc.h" #include "Acts/EventData/TrackParameters.hpp" @@ -62,10 +62,6 @@ private: // jobOptions properties Gaudi::Property<std::string> m_filePath{this, "FilePath", "propsteps.root", "Output root file for charged particle"}; Gaudi::Property<std::string> m_treeName{this, "TreeName", "propsteps", ""}; - //Gaudi::Property<bool> m_writeBoundary{this, "WriteBoundary", true, ""}; - //Gaudi::Property<bool> m_writeMaterial{this, "WriteMaterial", true, ""}; - //Gaudi::Property<bool> m_writeSensitive{this, "WriteSensitive", true, ""}; - //Gaudi::Property<bool> m_writePassive{this, "WritePassive", true, ""}; // root branch storage TFile* m_outputFile; ///< the output file diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx index ac647013bd177fb74ec5eaa1d26ae74935b3cfb1..eff504bb9063521a41525bc1ff2c4d9a7badd503 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.cxx @@ -2,14 +2,14 @@ Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsSurfaceMappingTool.h" +#include "FaserActsSurfaceMappingTool.h" // ATHENA #include "GaudiKernel/IInterface.h" // PACKAGE #include "ActsInterop/Logger.h" #include "FaserActsGeometry/FaserActsGeometryContext.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" +// #include "FaserActsTrackingGeometryTool.h" #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" // ACTS @@ -64,4 +64,4 @@ FaserActsSurfaceMappingTool::mappingState() const m_geoContext, m_magFieldContext, *m_trackingGeometry); return mappingState; -} \ No newline at end of file +} diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsSurfaceMappingTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsSurfaceMappingTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsSurfaceMappingTool.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx index f32a02990835e96bc0d56bfe887604bf3667a4eb..a45c7c06d37214248a19b189ca40886339c9f1b4 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx @@ -2,13 +2,17 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsTrackingGeometrySvc.h" +#include "FaserActsTrackingGeometrySvc.h" // ATHENA #include "TrackerReadoutGeometry/SCT_DetectorManager.h" #include "StoreGate/StoreGateSvc.h" #include "GaudiKernel/EventContext.h" #include "TrackerIdentifier/FaserSCT_ID.h" +//#include "DipoleGeoModel/DipoleManager.h" +#include "GeoModelKernel/GeoTube.h" +#include "GeoModelKernel/GeoBox.h" +#include "GeoModelFaserUtilities/GeoModelExperiment.h" // ACTS #include "Acts/Geometry/GeometryContext.hpp" @@ -25,6 +29,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" @@ -55,6 +61,13 @@ FaserActsTrackingGeometrySvc::initialize() ATH_CHECK ( m_detStore->retrieve(p_SCTManager, "SCT") ); + //get all the subdetectors + const GeoModelExperiment* theExpt = nullptr; + ATH_CHECK( m_detStore->retrieve( theExpt ,"FASER")); + const GeoVDetectorManager *vetoManager = theExpt->getManager("Veto"); + const GeoVDetectorManager *triggerManager = theExpt->getManager("Trigger"); + const GeoVDetectorManager *dipoleManager = theExpt->getManager("Dipole"); + Acts::LayerArrayCreator::Config lacCfg; auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>( lacCfg, makeActsAthenaLogger(this, "LayArrCrtr", "ActsTGSvc")); @@ -73,14 +86,28 @@ 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([&]( - const auto& gctx, const auto& /*inner*/, const auto&) { - auto tv = makeVolumeBuilder(gctx, p_SCTManager); - return tv->trackingVolume(gctx); - }); - + const auto& gctx, const auto& /*inner*/, const auto&) { + auto tv = makeVolumeBuilder(gctx, p_SCTManager, vetoManager, triggerManager, dipoleManager); + return tv->trackingVolume(gctx); + }); } catch (const std::invalid_argument& e) { ATH_MSG_ERROR(e.what()); @@ -89,8 +116,8 @@ FaserActsTrackingGeometrySvc::initialize() auto trackingGeometryBuilder - = std::make_shared<const Acts::TrackingGeometryBuilder>(tgbConfig, - makeActsAthenaLogger(this, "TrkGeomBldr", "ActsTGSvc")); + = std::make_shared<const Acts::TrackingGeometryBuilder>(tgbConfig, + makeActsAthenaLogger(this, "TrkGeomBldr", "ActsTGSvc")); // default geometry context, this is nominal @@ -102,10 +129,13 @@ FaserActsTrackingGeometrySvc::initialize() ATH_MSG_VERBOSE("Building nominal alignment store"); FaserActsAlignmentStore* nominalAlignmentStore = new FaserActsAlignmentStore(); + ATH_MSG_VERBOSE("finish Building nominal alignment store"); populateAlignmentStore(nominalAlignmentStore); + ATH_MSG_VERBOSE("finish alignment population"); populateIdentifierMap(m_identifierMap.get()); + ATH_MSG_VERBOSE("get alignment store"); // manage ownership m_nominalAlignmentStore = std::unique_ptr<const FaserActsAlignmentStore>(nominalAlignmentStore); @@ -122,7 +152,7 @@ FaserActsTrackingGeometrySvc::trackingGeometry() { } std::shared_ptr<const Acts::ITrackingVolumeBuilder> -FaserActsTrackingGeometrySvc::makeVolumeBuilder(const Acts::GeometryContext& gctx, const TrackerDD::SCT_DetectorManager* manager) +FaserActsTrackingGeometrySvc::makeVolumeBuilder(const Acts::GeometryContext& gctx, const TrackerDD::SCT_DetectorManager* manager, const GeoVDetectorManager* vetoManager, const GeoVDetectorManager* triggerManager, const GeoVDetectorManager* dipoleManager) { std::string managerName = manager->getName(); @@ -131,8 +161,23 @@ FaserActsTrackingGeometrySvc::makeVolumeBuilder(const Acts::GeometryContext& gct FaserActsLayerBuilder::Config cfg; cfg.subdetector = FaserActsDetectorElement::Subdetector::SCT; cfg.mng = static_cast<const TrackerDD::SCT_DetectorManager*>(manager); + //get veto and trigger manager + if(vetoManager!=nullptr) + cfg.vetomng = static_cast<const GeoVDetectorManager*>(vetoManager); + else + ATH_MSG_WARNING(name() << " can not find veto stations"); + if(triggerManager!=nullptr) + cfg.triggermng = static_cast<const GeoVDetectorManager*>(triggerManager); + else + ATH_MSG_WARNING(name() << " can not find trigger stations"); + if(dipoleManager!=nullptr) + cfg.dipolemng = static_cast<const GeoVDetectorManager*>(dipoleManager); + else + ATH_MSG_WARNING(name() << " can not find dipoles"); cfg.elementStore = m_elementStore; cfg.identifierMap = m_identifierMap; + std::vector<size_t> matBins(m_MaterialBins); + cfg.MaterialBins = { matBins.at(0), matBins.at(1) }; gmLayerBuilder = std::make_shared<FaserActsLayerBuilder>(cfg, makeActsAthenaLogger(this, "GMLayBldr", "ActsTGSvc")); auto cvbConfig = gmLayerBuilder->buildVolume(gctx); @@ -146,11 +191,13 @@ FaserActsTrackingGeometrySvc::populateAlignmentStore(FaserActsAlignmentStore *st { // populate the alignment store with all detector elements m_trackingGeometry->visitSurfaces( - [store](const Acts::Surface* srf) { - const Acts::DetectorElementBase* detElem = srf->associatedDetectorElement(); - const auto* gmde = dynamic_cast<const FaserActsDetectorElement*>(detElem); - gmde->storeTransform(store); - }); + [store](const Acts::Surface* srf) { + const Acts::DetectorElementBase* detElem = srf->associatedDetectorElement(); + if(detElem){ + const auto* gmde = dynamic_cast<const FaserActsDetectorElement*>(detElem); + gmde->storeTransform(store); + } + }); } const FaserActsAlignmentStore* @@ -165,8 +212,10 @@ FaserActsTrackingGeometrySvc::populateIdentifierMap(IdentifierMap *map) const m_trackingGeometry->visitSurfaces( [map](const Acts::Surface* srf) { const Acts::DetectorElementBase* detElem = srf->associatedDetectorElement(); + if(detElem){ const auto* faserDetElem = dynamic_cast<const FaserActsDetectorElement*>(detElem); map->insert(std::make_pair(faserDetElem->identify(), srf->geometryId())); + } }); } @@ -174,4 +223,4 @@ std::shared_ptr<IdentifierMap> FaserActsTrackingGeometrySvc::getIdentifierMap() const { return m_identifierMap; -} \ No newline at end of file +} diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsTrackingGeometrySvc.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.h similarity index 86% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsTrackingGeometrySvc.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.h index 65e21a130cc984d2533cf7e122629b18eb2cc4ba..3b191202b5959fc0ee606f7d2a21c4a82155044e 100644 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsTrackingGeometrySvc.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.h @@ -9,6 +9,7 @@ #include "AthenaBaseComps/AthService.h" #include "StoreGate/StoreGateSvc.h" #include "GaudiKernel/EventContext.h" +#include "GeoModelFaserUtilities/GeoModelExperiment.h" // ACTS #include "Acts/Geometry/GeometryContext.hpp" @@ -25,6 +26,7 @@ using namespace Acts::UnitLiterals; namespace TrackerDD { class SCT_DetectorManager; + class DipoleManager; } class FaserActsAlignmentStore; @@ -35,6 +37,7 @@ namespace Acts { class TrackingGeometry; class CylinderVolumeHelper; +class CylinderVolumeBuilder; class ITrackingVolumeBuilder; class GeometryID; @@ -68,7 +71,7 @@ public: private: std::shared_ptr<const Acts::ITrackingVolumeBuilder> - makeVolumeBuilder(const Acts::GeometryContext& gctx, const TrackerDD::SCT_DetectorManager* manager); + makeVolumeBuilder(const Acts::GeometryContext& gctx, const TrackerDD::SCT_DetectorManager* manager, const GeoVDetectorManager* vetoManager, const GeoVDetectorManager* triggerManager, const GeoVDetectorManager* dipoleManager); ServiceHandle<StoreGateSvc> m_detStore; const TrackerDD::SCT_DetectorManager* p_SCTManager; @@ -81,7 +84,7 @@ private: Gaudi::Property<bool> m_useMaterialMap{this, "UseMaterialMap", false, ""}; Gaudi::Property<std::string> m_materialMapInputFile{this, "MaterialMapInputFile", "", ""}; - Gaudi::Property<std::vector<size_t>> m_MaterialBins{this, "BarrelMaterialBins", {10, 10}}; + Gaudi::Property<std::vector<size_t>> m_MaterialBins{this, "MaterialBins", {30, 30}}; }; diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.cxx index aae04e8fae2a775d9dc9a6bb5536ffb5f820c39f..98a0ff23c16f5078e96f0609b5a84f3b9776fc79 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" +#include "FaserActsTrackingGeometryTool.h" // ATHENA #include "GaudiKernel/EventContext.h" diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsTrackingGeometryTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsTrackingGeometryTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometryTool.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx index 796ad74e4878cd72e6eae62cfea7333b94bcdc11..5e893ade237f52e68f8c2bc318579d52febae270 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsVolumeMappingTool.h" +#include "FaserActsVolumeMappingTool.h" // ATHENA #include "GaudiKernel/IInterface.h" @@ -10,9 +10,8 @@ // PACKAGE #include "FaserActsGeometry/FaserActsGeometryContext.h" #include "ActsInterop/Logger.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" //#include "ActsGeometry/ActsGeometryContext.h" -#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +// #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" // ACTS #include "Acts/Propagator/Navigator.hpp" diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsVolumeMappingTool.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsVolumeMappingTool.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsVolumeMappingTool.h diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.cxx index 3e05c12a23433253b0050966f530103aa017c656..0fe031dfc777445e920ecf61f1200d53076c1562 100755 --- a/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.cxx @@ -1,7 +1,7 @@ /* Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsWriteTrackingGeometry.h" +#include "FaserActsWriteTrackingGeometry.h" // ATHENA #include "AthenaKernel/RNGWrapper.h" @@ -11,6 +11,7 @@ // PACKAGE #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometrySvc.h" +#include "FaserActsGeometryInterfaces/IFaserActsMaterialJsonWriterTool.h" #include "FaserActsGeometry/FaserActsGeometryContext.h" #include "ActsInterop/Logger.h" @@ -28,6 +29,7 @@ StatusCode FaserActsWriteTrackingGeometry::initialize() { ATH_CHECK(m_objWriterTool.retrieve()); ATH_CHECK(m_trackingGeometryTool.retrieve()); + ATH_CHECK(m_materialJsonWriterTool.retrieve() ); return StatusCode::SUCCESS; } @@ -40,7 +42,10 @@ StatusCode FaserActsWriteTrackingGeometry::execute(const EventContext& /*ctx*/ ) //const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext(ctx); const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext(); + ATH_MSG_INFO("start to write object"); m_objWriterTool->write(gctx, *trackingGeometry); + ATH_MSG_INFO("start to write geometry"); + m_materialJsonWriterTool->write(*trackingGeometry); return StatusCode::SUCCESS; } diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsWriteTrackingGeometry.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.h similarity index 71% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsWriteTrackingGeometry.h rename to Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.h index 2de2fef9c67193d8b0d52e1352124bbe41e55939..c6dc6fb79e8fe6eb5033f65601978851cabbc2c4 100755 --- a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserActsWriteTrackingGeometry.h +++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsWriteTrackingGeometry.h @@ -13,8 +13,8 @@ #include "GaudiKernel/ISvcLocator.h" // PACKAGE -#include "FaserActsGeometry/FaserActsObjWriterTool.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" +#include "FaserActsObjWriterTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" // STL #include <fstream> @@ -26,6 +26,7 @@ namespace Acts { } class IFaserActsTrackingGeometrySvc; +class IFaserActsMaterialJsonWriterTool; class FaserActsWriteTrackingGeometry : public AthReentrantAlgorithm { public: @@ -36,9 +37,10 @@ public: private: - ToolHandle<FaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; + ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; ToolHandle<FaserActsObjWriterTool> m_objWriterTool{this, "ObjWriterTool", "FaserActsObjWriterTool"}; + ToolHandle<IFaserActsMaterialJsonWriterTool> m_materialJsonWriterTool{this, "MaterialJsonWriterTool", "FaserActsMaterialJsonWriterTool"}; }; diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.cxx index 5edcda8c1acef4f087e1e15c307a32e9560145e3..2068df0eb781e3622a03c54928004892d0bb0c99 100644 --- a/Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.cxx @@ -2,7 +2,7 @@ Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserNominalAlignmentCondAlg.h" +#include "FaserNominalAlignmentCondAlg.h" // ATHENA #include "StoreGate/WriteCondHandle.h" diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserNominalAlignmentCondAlg.h b/Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/FaserNominalAlignmentCondAlg.h rename to Tracking/Acts/FaserActsGeometry/src/FaserNominalAlignmentCondAlg.h diff --git a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx index 9be7649a9397fa25de520848ede7ecad3bcc4cc7..e7b7fb2fe49208911b0d98c2ba4a6d6b960df89f 100755 --- a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx +++ b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx @@ -2,24 +2,20 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsGeometry/FaserActsExtrapolationAlg.h" -#include "FaserActsGeometry/FaserActsWriteTrackingGeometry.h" -#include "FaserActsGeometry/FaserActsTrackingGeometrySvc.h" -#include "FaserActsGeometry/FaserActsExtrapolationTool.h" -#include "FaserActsGeometry/FaserActsObjWriterTool.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" -#include "FaserActsGeometry/FaserActsPropStepRootWriterSvc.h" -#include "FaserActsGeometry/FaserActsAlignmentCondAlg.h" -#include "FaserActsGeometry/FaserNominalAlignmentCondAlg.h" -//#include "FaserActsGeometry/FaserActsKalmanFilterAlg.h" -//#include "FaserActsGeometry/FaserActsExCellWriterSvc.h" -//#include "FaserActsGeometry/FaserActsMaterialTrackWriterSvc.h" -//#include "FaserActsGeometry/GeomShiftCondAlg.h" -//#include "FaserActsGeometry/FaserActsWriteTrackingGeometryTransforms.h" -#include "FaserActsGeometry/FaserActsVolumeMappingTool.h" -#include "FaserActsGeometry/FaserActsMaterialJsonWriterTool.h" -#include "FaserActsGeometry/FaserActsMaterialMapping.h" -#include "FaserActsGeometry/FaserActsSurfaceMappingTool.h" +#include "../FaserActsExtrapolationAlg.h" +#include "../FaserActsWriteTrackingGeometry.h" +#include "../FaserActsTrackingGeometrySvc.h" +#include "../FaserActsExtrapolationTool.h" +#include "../FaserActsObjWriterTool.h" +#include "../FaserActsTrackingGeometryTool.h" +#include "../FaserActsPropStepRootWriterSvc.h" +#include "../FaserActsAlignmentCondAlg.h" +#include "../FaserNominalAlignmentCondAlg.h" +#include "../FaserActsVolumeMappingTool.h" +#include "../FaserActsMaterialJsonWriterTool.h" +#include "../FaserActsMaterialMapping.h" +#include "../FaserActsSurfaceMappingTool.h" +#include "../FaserActsMaterialTrackWriterSvc.h" DECLARE_COMPONENT( FaserActsTrackingGeometrySvc ) DECLARE_COMPONENT( FaserActsTrackingGeometryTool ) @@ -29,13 +25,8 @@ DECLARE_COMPONENT( FaserActsPropStepRootWriterSvc ) DECLARE_COMPONENT( FaserActsObjWriterTool ) DECLARE_COMPONENT( FaserActsWriteTrackingGeometry ) DECLARE_COMPONENT( FaserActsAlignmentCondAlg ) -//DECLARE_COMPONENT( FaserActsKalmanFilterAlg ) -//DECLARE_COMPONENT( FaserNominalAlignmentCondAlg ) -//DECLARE_COMPONENT( FaserActsExCellWriterSvc ) -//DECLARE_COMPONENT( FaserActsMaterialTrackWriterSvc ) -//DECLARE_COMPONENT( FaserActsWriteTrackingGeometryTransforms ) -//DECLARE_COMPONENT( FaserGeomShiftCondAlg ) DECLARE_COMPONENT( FaserActsVolumeMappingTool ) DECLARE_COMPONENT( FaserActsMaterialJsonWriterTool ) +DECLARE_COMPONENT( FaserActsMaterialTrackWriterSvc ) DECLARE_COMPONENT( FaserActsMaterialMapping ) DECLARE_COMPONENT( FaserActsSurfaceMappingTool ) diff --git a/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py b/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py index 61f1e62490ee5d50a9f4d20f0e23a4d5dc55646a..ed998b3b4607cf633e2825b5cb868c08039308d6 100644 --- a/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py +++ b/Tracking/Acts/FaserActsGeometry/test/FaserActsWriteTrackingGeometry.py @@ -17,16 +17,17 @@ log.setLevel(DEBUG) Configurable.configurableRun3Behavior = True # Configure -ConfigFlags.Input.Files = ["/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/esd/100evts10lumiblocks.ESD.root"] +ConfigFlags.Input.Files = ["myevt4.HITS.pool.root"] #ConfigFlags.Output.RDOFileName = "myRDO_sp.pool.root" -ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01" # Always needed; must match FaserVersion -ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Always needed +ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion +ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Always needed +#ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" # Always needed # Workaround for bug/missing flag; unimportant otherwise ConfigFlags.addFlag("Input.InitialTimeStamp", 0) # Workaround to avoid problematic ISF code ConfigFlags.GeoModel.Layout = "Development" ConfigFlags.Detector.GeometryFaserSCT = True -ConfigFlags.GeoModel.AtlasVersion = "ATLAS-R2-2016-01-00-01" # Always needed to fool autoconfig; value ignored +#ConfigFlags.GeoModel.AtlasVersion = "ATLAS-R2-2016-01-00-01" # Always needed to fool autoconfig; value ignored ConfigFlags.GeoModel.Align.Dynamic = False #ConfigFlags.Concurrency.NumThreads = 1 #ConfigFlags.Beam.NumberOfCollisions = 0. @@ -35,7 +36,9 @@ ConfigFlags.lock() # Core components acc = MainServicesCfg(ConfigFlags) acc.merge(PoolReadCfg(ConfigFlags)) -acc.merge(PoolWriteCfg(ConfigFlags)) +#acc.merge(PoolWriteCfg(ConfigFlags)) +from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +acc.merge(FaserGeometryCfg(ConfigFlags)) # Inner Detector acc.merge(FaserActsWriteTrackingGeometryCfg(ConfigFlags)) @@ -61,6 +64,6 @@ acc.getService("ConditionStore").Dump = True acc.printConfig(withDetails=True) ConfigFlags.dump() # Execute and finish -sc = acc.run(maxEvents=-1) +sc = acc.run(maxEvents=1) # Success should be 0 sys.exit(not sc.isSuccess()) 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/FaserActsGeometry/FaserActsGeometry/IFaserActsExCellWriterSvc.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsExCellWriterSvc.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/IFaserActsExCellWriterSvc.h rename to Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsExCellWriterSvc.h diff --git a/Tracking/Acts/FaserActsGeometry/FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h b/Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsPropStepRootWriterSvc.h similarity index 100% rename from Tracking/Acts/FaserActsGeometry/FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h rename to Tracking/Acts/FaserActsGeometryInterfaces/FaserActsGeometryInterfaces/IFaserActsPropStepRootWriterSvc.h diff --git a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt index a59281e363f8fd5dde3136a6b753d0eed8c0d0d6..9377c4716810301c16fe7ca606ba31e6f5ba318c 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,10 +25,86 @@ atlas_add_library( FaserActsKalmanFilterLib ) atlas_add_component(FaserActsKalmanFilter - src/*.cxx - src/components/*.cxx - FaserActsKalmanFilter/*.h - FaserActsKalmanFilter/src/*.cxx + ActsTrackSeedTool.h + CircleFit.h + CircleFitTrackSeedTool.h + CKF2.h + CombinatorialKalmanFilterAlg.h + EffPlotTool.h + FASERSourceLink.h + FaserActsKalmanFilter/FaserActsGeometryContainers.h + FaserActsKalmanFilterAlg.h + FaserActsRecMultiTrajectory.h + GhostBusters.h + MyTrackSeedTool.h + FaserActsKalmanFilter/IdentifierLink.h + FaserActsKalmanFilter/IndexSourceLink.h + FaserActsKalmanFilter/ITrackFinderTool.h + FaserActsKalmanFilter/ITrackSeedTool.h + KalmanFitterTool.h + LinearFit.h +# ClusterTrackSeedTool.h +# TruthTrackFinderTool.h + FaserActsKalmanFilter/Measurement.h +# MultiTrackFinderTool.h + PerformanceWriterTool.h + PlotHelpers.h + ResPlotTool.h + RootTrajectoryStatesWriterTool.h + RootTrajectorySummaryWriterTool.h + SeedingAlg.h +# SegmentFitClusterTrackFinderTool.h +# SegmentFitTrackFinderTool.h + SimWriterTool.h + SPSeedBasedInitialParameterTool.h + SPSimpleInitialParameterTool.h + SummaryPlotTool.h + TrackClassification.h + TrackSeedWriterTool.h + TrackSelection.h + TrajectoryWriterTool.h +# ProtoTrackWriterTool.h + TruthBasedInitialParameterTool.h +# TruthSeededTrackFinderTool.h + ThreeStationTrackSeedTool.h + src/ActsTrackSeedTool.cxx + src/CircleFit.cxx + src/CircleFitTrackSeedTool.cxx + src/CKF2.cxx + src/CreateTrkTrackTool.h + src/CreateTrkTrackTool.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} LINK_LIBRARIES ${CLHEP_LIBRARIES} ${EIGEN_LIBRARIES} @@ -49,6 +128,7 @@ atlas_add_component(FaserActsKalmanFilter TrackerIdentifier TrackerReadoutGeometry Identifier + TrackerSimEvent TrackerSimData TrackerSeedFinderLib ) diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/.__afsCDFD b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/.__afsCDFD deleted file mode 100644 index c066165b27f5fabec539af3ca012c6ab0585c276..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/.__afsCDFD +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef COMBINATORIALKALMANFILTERALG_H -#define COMBINATORIALKALMANFILTERALG_H - -#include "AthenaBaseComps/AthReentrantAlgorithm.h" -#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h" -#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" -#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.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" - -class FaserSCT_ID; - -namespace Trk -{ -class TrackStateOnSurface; -} - -namespace TrackerDD { - class SCT_DetectorManager; -} - -class CombinatorialKalmanFilterAlg : public AthReentrantAlgorithm { - public: - CombinatorialKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); - virtual ~CombinatorialKalmanFilterAlg() = default; - - StatusCode initialize() override; - StatusCode execute(const EventContext& ctx) const 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&)>; - - static TrackFinderFunction makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); - - Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; - - - private: - const FaserSCT_ID* m_idHelper{nullptr}; - const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; - - 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; - - SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "FaserActsCKFTrackCollection", "FaserActsCKFTrackCollection", "Output trackcollectionname" }; - - ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"}; - ToolHandle<SPSeedBaseInitialParameterTool> m_initialParameterTool{this, "InitialParameterTool", "SPSeedBaseInitialParameterTool"}; - //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"}; -}; - -#endif // COMBINATORIALKALMANFILTERALG_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h deleted file mode 100644 index db3f086debf367530d61ba47c58bb6602a84ff3e..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef COMBINATORIALKALMANFILTERALG_H -#define COMBINATORIALKALMANFILTERALG_H - -#include "AthenaBaseComps/AthReentrantAlgorithm.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 "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" - -class FaserSCT_ID; - -namespace Trk -{ -class TrackStateOnSurface; -} - -namespace TrackerDD { - class SCT_DetectorManager; -} - -class CombinatorialKalmanFilterAlg : public AthReentrantAlgorithm { - public: - CombinatorialKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); - virtual ~CombinatorialKalmanFilterAlg() = default; - - StatusCode initialize() override; - StatusCode execute(const EventContext& ctx) const 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&)>; - - static TrackFinderFunction makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry); - - Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const; - - - private: - const FaserSCT_ID* m_idHelper{nullptr}; - const TrackerDD::SCT_DetectorManager* m_detManager{nullptr}; - -// 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; - - SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "FaserActsCKFTrackCollection", "FaserActsCKFTrackCollection", "Output trackcollectionname" }; - - 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; -}; - -#endif // COMBINATORIALKALMANFILTERALG_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h deleted file mode 100755 index 8e90ed858c09efc3d46985a7edb354ea2de6c280..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration -*/ - -#ifndef FASERACTSKALMANFILTER_FASERACTSKALMANFILTERALG_H -#define FASERACTSKALMANFILTER_FASERACTSKALMANFILTERALG_H - -// ATHENA -#include "AthenaBaseComps/AthAlgorithm.h" -#include "AthenaBaseComps/AthReentrantAlgorithm.h" -#include "GaudiKernel/ServiceHandle.h" -#include "GaudiKernel/ITHistSvc.h" -#include "Gaudi/Property.h" /*no forward decl: typedef*/ -#include "GaudiKernel/ISvcLocator.h" -#include "StoreGate/StoreGateSvc.h" -#include "StoreGate/ReadCondHandleKey.h" -#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" -#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" -#include "TrackerSpacePoint/SpacePointForSeedCollection.h" -#include "MagFieldConditions/FaserFieldCacheCondObj.h" -#include "MagFieldElements/FaserFieldCache.h" -#include "TrackerReadoutGeometry/SiDetectorElementCollection.h" -#include "Identifier/Identifier.h" -#include "GeneratorObjects/McEventCollection.h" -#include "TrackerSimData/TrackerSimDataCollection.h" -#include "TrkTrack/TrackCollection.h" - -// ACTS -#include "Acts/MagneticField/ConstantBField.hpp" -#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -#include "Acts/MagneticField/SharedBField.hpp" -#include "Acts/Propagator/EigenStepper.hpp" -#include "Acts/Propagator/Propagator.hpp" -#include "Acts/Propagator/detail/SteppingLogger.hpp" -#include "Acts/TrackFitting/KalmanFitter.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/EventData/TrackParameters.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Utilities/Helpers.hpp" -#include "Acts/Definitions/Common.hpp" - -// PACKAGE -#include "FaserActsGeometry/FASERMagneticFieldWrapper.h" -#include "FaserActsGeometry/FaserActsTrackingGeometryTool.h" -#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" -#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" -#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" -#include "FaserActsKalmanFilter/IndexSourceLink.h" -#include "FaserActsKalmanFilter/Measurement.h" - -// STL -#include <memory> -#include <vector> -#include <fstream> -#include <mutex> - -class EventContext; -class IAthRNGSvc; -class FaserSCT_ID; -class TTree; - -namespace ActsExtrapolationDetail { - class VariantPropagator; -} - -namespace TrackerDD { - class SCT_DetectorManager; -} - -using TrajectoryContainer = std::vector<FaserActsRecMultiTrajectory>; -using BField_t = FASERMagneticFieldWrapper; - -//class FaserActsKalmanFilterAlg : public AthReentrantAlgorithm { -class FaserActsKalmanFilterAlg : public AthAlgorithm { -public: - FaserActsKalmanFilterAlg (const std::string& name, ISvcLocator* pSvcLocator); - StatusCode initialize() 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 BoundVector = Acts::ActsVector<6>; - - // Create the fitter function implementation. - static FitterFunction - makeFitterFunction( - ActsExtrapolationDetail::VariantPropagator* varProp); - - virtual - Acts::MagneticFieldContext - //getMagneticFieldContext(const EventContext& ctx) const; - getMagneticFieldContext() const; - - void initializeTree(); - - void fillFitResult(const Acts::GeometryContext& geoctx, const TrajectoryContainer& trajectories, const Acts::BoundTrackParameters& truthParam); - - // Create a track from the fitter result - std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult,const SpacePointForSeedCollection* seed_spcollection ) 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}}; - - SG::ReadHandleKey<SpacePointForSeedCollection> m_seed_spcollectionKey{this, "FaserSpacePointsSeedsName", "SpacePointForSeedCollection", "SpacePointForSeedCollection"}; - - 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 - -}; - -#endif diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h deleted file mode 100644 index 35baa239600d5f273dd91c2145eecfd8e1c8b52a..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2019 CERN for the benefit of the Acts project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -#pragma once - -#include <unordered_map> -#include <utility> - -// ACTS -#include "Acts/EventData/MultiTrajectory.hpp" -#include "Acts/EventData/TrackParameters.hpp" - -// PACKAGE -#include "FaserActsKalmanFilter/IndexSourceLink.h" - -using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>; - -struct FaserActsRecMultiTrajectory -{ - public: - FaserActsRecMultiTrajectory() = default; - - FaserActsRecMultiTrajectory(const Acts::MultiTrajectory<IndexSourceLink>& 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; - } - - 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; - } - - bool hasTrajectory(const size_t& entryIndex) const { - return std::count(m_trackTips.begin(), m_trackTips.end(), entryIndex) > 0; - } - - bool hasTrackParameters(const size_t& entryIndex) const { - return m_trackParameters.count(entryIndex) > 0; - } - - std::pair<std::vector<size_t>, Acts::MultiTrajectory<IndexSourceLink>> - trajectory() const { - return std::make_pair(m_trackTips, m_multiTrajectory); - } - - const Acts::BoundTrackParameters& trackParameters(const size_t& entryIndex) const { - auto it = m_trackParameters.find(entryIndex); - if (it != m_trackParameters.end()) { - return it->second; - } else { - throw std::runtime_error( - "No fitted track parameters for trajectory with entry index = " + - std::to_string(entryIndex)); - } - } - - private: - Acts::MultiTrajectory<IndexSourceLink> m_multiTrajectory; - std::vector<size_t> m_trackTips = {}; - IndexedParams m_trackParameters = {}; -}; diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..af5eb919cdf3e3b0d36353e4e07aa2d024c11c4d --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackFinderTool.h @@ -0,0 +1,33 @@ +#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" + +namespace Tracker +{ + class FaserSCT_Cluster; + class FaserSCT_SpacePoint; +} + +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..1ef1a7921bdaa55381ee9487c32b7f58bca3e05c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h @@ -0,0 +1,35 @@ +#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" + +namespace Tracker +{ + class FaserSCT_Cluster; + class FaserSCT_SpacePoint; +} + +class ITrackSeedTool : virtual public IAlgTool { +public: + DeclareInterfaceID(ITrackSeedTool, 1, 0); + + virtual StatusCode run(std::vector<int> maskedLayers = {}) = 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..2e6a2a7885be8c3aa8c3ee884ffdc9968360e298 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/IndexSourceLink.h @@ -14,7 +14,13 @@ #include <boost/container/flat_map.hpp> -#include "FaserActsKalmanFilter/FaserActsGeometryContainers.h" +#include "FaserActsGeometryContainers.h" +// #include "TrackerPrepRawData/FaserSCT_Cluster.h" +namespace Tracker +{ + class FaserSCT_Cluster; +} + /// Index type to reference elements in a container. /// @@ -34,10 +40,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 +55,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/python/CKF2Config.py b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py new file mode 100644 index 0000000000000000000000000000000000000000..1035484b832fec4f32ca36400309a36cd250ed91 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py @@ -0,0 +1,111 @@ +""" + 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.pop("noDiagnostics", True) + trajectory_states_writer_tool1 = CompFactory.RootTrajectoryStatesWriterTool() + trajectory_states_writer_tool1.noDiagnostics = kwargs.pop("noDiagnostics", True) + trajectory_states_writer_tool1.FilePath = "track_states_ckf1.root" + + trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool() + trajectory_summary_writer_tool.noDiagnostics = kwargs.pop("noDiagnostics", True) + trajectory_summary_writer_tool1 = CompFactory.RootTrajectorySummaryWriterTool() + trajectory_summary_writer_tool1.FilePath = "track_summary_ckf1.root" + trajectory_summary_writer_tool1.noDiagnostics = kwargs.pop("noDiagnostics", True) + + actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool") + actsExtrapolationTool.MaxSteps = 1000 + actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool") + + trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool") + trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool + trajectory_performance_writer_tool.noDiagnostics = kwargs.pop("noDiagnostics", True) + + ckf = CompFactory.CKF2(**kwargs) + kalman_fitter1 = CompFactory.KalmanFitterTool(name="fitterTool1") + kalman_fitter1.noDiagnostics = kwargs.pop("noDiagnostics", True) + 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 + + 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 + # Use larger chi2 cut until alignment improves + # ckf.chi2Max = 25 + ckf.chi2Max = 100000 + # Protect against running out of memory on busy events + ckf.maxSteps = 5000 + 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..87101612bd15a3c33c670ef3f0d6ccd5c78f4a5c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/python/TI12CKF2Config.py @@ -0,0 +1,114 @@ +# 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 + 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_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool() + 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"] + + 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") + 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 + 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 + 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.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..4161c19eecbc6b30b0436732f76498f71f3f4fa6 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx @@ -0,0 +1,147 @@ +#include "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(std::vector<int> /*maskedLayers*/) { + 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/ActsTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..41aebd49ff0c7caf5f5615a47af1641b804b45fb --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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(std::vector<int> /*maskedLayers*/) 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/src/CKF2.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx new file mode 100644 index 0000000000000000000000000000000000000000..858b97d6b2655859d77f027b31a57ce5782b95ae --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx @@ -0,0 +1,381 @@ +#include "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 "FaserActsRecMultiTrajectory.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "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_createTrkTrackTool.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++; + + SG::WriteHandle 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(m_maskedLayers)); + 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()); + std::unique_ptr<Trk::Track> track = m_createTrkTrackTool->createTrack(gctx, traj); + if (track != nullptr) { + m_numberOfSelectedTracks++; + std::unique_ptr<Trk::Track> track2 = m_kalmanFitterTool1->fit(ctx, gctx, track.get(), Acts::BoundVector::Zero(), m_isMC, origin); + if (track2) { + outputTracks->push_back(std::move(track2)); + } else { + outputTracks->push_back(std::move(track)); + ATH_MSG_WARNING("Re-Fit failed."); + } + } else { + ATH_MSG_WARNING("CKF failed."); + } + } + + // 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); +} + + + +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/CKF2.h b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h new file mode 100644 index 0000000000000000000000000000000000000000..2111afcf6b52d46b45e1e2539d105290b937689e --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h @@ -0,0 +1,153 @@ +#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 "TrajectoryWriterTool.h" +#include "TrkTrack/TrackCollection.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "RootTrajectoryStatesWriterTool.h" +#include "RootTrajectorySummaryWriterTool.h" +#include "PerformanceWriterTool.h" +#include "KalmanFitterTool.h" +#include <boost/dynamic_bitset.hpp> +#include "CreateTrkTrackTool.h" +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}; + Gaudi::Property<std::vector<int>> m_maskedLayers {this, "maskedLayers", {}}; + 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<CreateTrkTrackTool> m_createTrkTrackTool {this, "CreateTrkTrackTool", "CreateTrkTrackTool"}; + Gaudi::Property<bool> m_isMC {this, "isMC", false}; + SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "OutputCollection", "CKFTrackCollection", "Output track collection name" }; +}; + +#endif // FASERACTSKALMANFILTER_CKF2_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx new file mode 100644 index 0000000000000000000000000000000000000000..51048496254f5187a7d105d1e807483de0de1f1c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.cxx @@ -0,0 +1,169 @@ +#include "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/CircleFit.h b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFit.h new file mode 100644 index 0000000000000000000000000000000000000000..780a476a722707f280b427a1678f16fcfb5b1cdf --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/CircleFitTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..066698a478fbea03a6565a056afafd253e449a0d --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx @@ -0,0 +1,319 @@ +#include "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 "CircleFit.h" +#include "LinearFit.h" +#include "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(std::vector<int> maskedLayers) { + 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(); + if (std::find(maskedLayers.begin(), maskedLayers.end(), 3 * m_idHelper->station(id) + m_idHelper->layer(id)) != maskedLayers.end()) { + continue; + } + 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, maskedLayers); + if (s.station != -1) 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 < 10) || ((p.clusterSet & selected.clusterSet).count() > 6); + }); + } + + 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 - 1 : 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); + 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, const std::vector<int> &maskedLayers) : + 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(); + if (std::find(maskedLayers.begin(), maskedLayers.end(), 3 * idHelper->station(id) + idHelper->layer(id)) != maskedLayers.end()) { + continue; + } + 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/CircleFitTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..7866b89fc32fe2ccd8a0391f421b1d203ff1e8e0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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(std::vector<int> maskedLayers = {}) 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, const std::vector<int> &maskedLayers = {}); + int station = -1; + 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/src/ClusterTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0e8265ecee9cae5388526b165b7a0dfc115058a0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.cxx @@ -0,0 +1,129 @@ +#include "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/ClusterTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/ClusterTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..fa869dc1bd7242f5096a16d879b73ab86a9e2173 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/CombinatorialKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ee2a864b51d0cd632322128256666679c4beb490 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx @@ -0,0 +1,359 @@ +#include "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 "FaserActsRecMultiTrajectory.h" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "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/CombinatorialKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..e4549a40ebc9991bba72f4c95e686d41183cb04c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.h @@ -0,0 +1,133 @@ +#ifndef COMBINATORIALKALMANFILTERALG_H +#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 "SPSimpleInitialParameterTool.h" +//#include "SPSeedBasedInitialParameterTool.h" +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" +#include "Acts/TrackFinding/MeasurementSelector.hpp" +#include "FaserActsKalmanFilter/Measurement.h" +#include "MagFieldConditions/FaserFieldCacheCondObj.h" +#include "TrajectoryWriterTool.h" +#include "TrkTrack/TrackCollection.h" +#include "FaserActsKalmanFilter/ITrackSeedTool.h" +#include "RootTrajectoryStatesWriterTool.h" +#include "RootTrajectorySummaryWriterTool.h" +#include "PerformanceWriterTool.h" +#include "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 { +class TrackStateOnSurface; +} + +namespace TrackerDD { +class SCT_DetectorManager; +} + +class CombinatorialKalmanFilterAlg : public AthAlgorithm { +public: + CombinatorialKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~CombinatorialKalmanFilterAlg() = 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 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; + }; + + 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<TrackFinderFunction> makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + bool resolvePassive, bool resolveMaterial, bool resolveSensitive); + 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::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_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}; + + 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"}; + + 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/src/CombinatorialKalmbanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmbanFilterAlg.cxx deleted file mode 100644 index 08e9f2b2283089fbcda678d65234c3cce03c3c7e..0000000000000000000000000000000000000000 --- a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmbanFilterAlg.cxx +++ /dev/null @@ -1,521 +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); - //std::cout<<"n spacepoints in stations : "<<pos1.size()<<" "<<pos2.size()<<" "<<pos3.size()<<std::endl; -// 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::VERBOSE); - - // 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 taotal, "<<m_nevents<<" events, and "<<m_nseeds<<" seeds, and "<<m_ntracks<<" tracks"); - ATH_MSG_INFO("In taotal, "<<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); -} - -/* -void CombinatorialKalmanFilterAlg::makeTrack(Acts::GeometryContext& tgContext, TrajectoryiesContainer trajectories, - const FaserSCT_SpacePointContainer* seed_spcollection, TrackCollection* outputTracks - ) const { - // Loop over the trajectories - int iTraj = 0; - for (const auto& traj : trajectories) { - - // The trajectory entry indices and the multiTrajectory - const auto& [trackTips, mj] = traj.trajectory(); - if (trackTips.empty()) { - ATH_MSG_WARNING("Empty multiTrajectory."); - continue; - } - // 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); - if (traj.hasTrackParameters(trackTip)) - { - 242 mj.visitBackwards(trackTip, [&](const auto &state) { - 243 /// Only fill the track states with non-outlier measurement - 244 auto typeFlags = state.typeFlags(); - 245 if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) - 246 { - 247 return true; - 248 } - 252 /// Get the geometry ID - 253 auto geoID = state.referenceSurface().geometryId(); - 254 m_volumeID.push_back(geoID.volume()); - 255 m_layerID.push_back(geoID.layer()); - 256 m_moduleID.push_back(geoID.sensitive()); - 257 - 258 // expand the local measurements into the full bound space - 259 Acts::BoundVector meas = - 260 state.projector().transpose() * state.calibrated(); - 261 - 262 // extract local and global position - 263 Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); - 264 Acts::Vector3 mom(1, 1, 1); - Acts::Vector3 global = - 266 surface.localToGlobal(geoContext, local, mom); - jjjjj - } -} - -*/ -std::unique_ptr<Trk::Track> -//CombinatorialKalmanFilterAlg::makeTrack(Acts::GeometryContext& tgContext, FitterResult& fitResult, std::vector<Tracker::FaserSCT_Cluster> sps -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.result) - 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(); - // std::cout<<"position "<<psurface.center(tgContext)<<std::endl; - // std::cout<<"position "<<psurface.associatedDetectorElement()->thickness()<<std::endl; - // std::cout<<"geometry "<<psurface.geometryId().volume()<<" "<<psurface.geometryId().layer()<<" "<<psurface.geometryId().sensitive()<<std::endl; - 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; - }); -/* - // Convert the perigee state and add it to the trajectory - const Acts::BoundTrackParameters actsPer = fitOutput.fittedParameters.value(); - const Trk::TrackParameters *per = ConvertActsTrackParameterToATLAS(actsPer, tgContext); - std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; - typePattern.set(Trk::TrackStateOnSurface::Perigee); - const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(nullptr, per, nullptr, nullptr, typePattern); - if (perState) finalTrajectory->insert(finalTrajectory->begin(), perState); - */ - - // 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> (0, 0)); - // 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/CreateTrkTrackTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CreateTrkTrackTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4928fc917e2b0bfe73e38848939690680fc3c19a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CreateTrkTrackTool.cxx @@ -0,0 +1,106 @@ +#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h" +#include "CreateTrkTrackTool.h" + +#include <Acts/EventData/MultiTrajectoryHelpers.hpp> +#include "TrackerIdentifier/FaserSCT_ID.h" + +CreateTrkTrackTool::CreateTrkTrackTool(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool( type, name, parent ) {} + +StatusCode CreateTrkTrackTool::initialize() { + ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID")); + return StatusCode::SUCCESS; +} + +StatusCode CreateTrkTrackTool::finalize() { + return StatusCode::SUCCESS; +} + +std::unique_ptr<Trk::Track> +CreateTrkTrackTool::createTrack(const Acts::GeometryContext &gctx, const FaserActsRecMultiTrajectory &traj) const { + std::unique_ptr<Trk::Track> newtrack = nullptr; + DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{}; + using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>; + auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(traj.multiTrajectory(), traj.tips().front()); + traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) { + auto flag = state.typeFlags(); + if (state.referenceSurface().associatedDetectorElement() != nullptr) { + std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern; + const Trk::TrackParameters *parm; + + if (flag[Acts::TrackStateFlag::HoleFlag]) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.predicted(), state.predictedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, gctx); + typePattern.set(Trk::TrackStateOnSurface::Hole); + } + else if (flag[Acts::TrackStateFlag::OutlierFlag]) { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.filtered(), state.filteredCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, gctx); + typePattern.set(Trk::TrackStateOnSurface::Outlier); + } + else { + const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(), + state.smoothed(), state.smoothedCovariance()); + parm = ConvertActsTrackParameterToATLAS(actsParam, gctx); + typePattern.set(Trk::TrackStateOnSurface::Measurement); + } + Tracker::FaserSCT_ClusterOnTrack* clusterOnTrack = nullptr; + if (state.hasUncalibrated()) { + const Tracker::FaserSCT_Cluster* cluster = state.uncalibrated().hit(); + if (cluster->detectorElement() != nullptr) { + clusterOnTrack = new Tracker::FaserSCT_ClusterOnTrack{ + cluster, + Trk::LocalParameters{ + Trk::DefinedParameter{cluster->localPosition()[0], Trk::loc1}, + Trk::DefinedParameter{cluster->localPosition()[1], Trk::loc2} + }, + cluster->localCovariance(), + m_idHelper->wafer_hash(cluster->detectorElement()->identify()) + }; + } + } + const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(clusterOnTrack, parm); + if (perState) { + finalTrajectory->insert(finalTrajectory->begin(), perState); + } + } + return; + }); + + Trk::FitQuality* q = new Trk::FitQuality {trajState.chi2Sum, static_cast<double>(trajState.nMeasurements - 5)}; + Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon); + std::unique_ptr<DataVector<const Trk::TrackStateOnSurface>> sink(finalTrajectory); + // newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), quality); + Trk::Track* tmpTrack = new Trk::Track(newInfo, std::move(*sink), q); + newtrack = std::unique_ptr<Trk::Track>(tmpTrack); + return newtrack; +} + + +const Trk::TrackParameters* +CreateTrkTrackTool::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)); + double charge = tqOverP > 0. ? 1. : -1.; + const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,charge, cov); + return curv; +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CreateTrkTrackTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/CreateTrkTrackTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d0edfd5cb9aedb78d7fde03104377f3ff9aa5d1f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/CreateTrkTrackTool.h @@ -0,0 +1,27 @@ +#ifndef FASERACTSKALMANFILTER_CREATETRKTRACKTOOL_H +#define FASERACTSKALMANFILTER_CREATETRKTRACKTOOL_H + +#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "TrkTrack/Track.h" +#include "TrkParameters/TrackParameters.h" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "FaserActsRecMultiTrajectory.h" + + +class FaserSCT_ID; + +class CreateTrkTrackTool: public AthAlgTool { +public: + CreateTrkTrackTool(const std::string &type, const std::string &name, const IInterface *parent); + virtual ~CreateTrkTrackTool() = default; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + std::unique_ptr<Trk::Track> createTrack(const Acts::GeometryContext &gctx, const FaserActsRecMultiTrajectory &traj) const; + const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const; +private: + const FaserSCT_ID* m_idHelper {nullptr}; +}; + +#endif //FASERACTSKALMANFILTER_CREATETRKTRACKTOOL_H \ No newline at end of file diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e757c9c8dc248b6c1bb87596771cc0e0914e56a2 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.cxx @@ -0,0 +1,40 @@ +#include "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/EffPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..63b92ad1ac0c2276d4ce2cb7e2c2d1e201bd7d16 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/EffPlotTool.h @@ -0,0 +1,57 @@ +#ifndef FASERACTSKALMANFILTER_EFFPLOTTOOL_H +#define FASERACTSKALMANFILTER_EFFPLOTTOOL_H + +#include "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/src/FASERSourceLink.h b/Tracking/Acts/FaserActsKalmanFilter/src/FASERSourceLink.h new file mode 100644 index 0000000000000000000000000000000000000000..6ec1c46b9ad12ff6822c070a4ea320d6079dd387 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/FaserActsKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx index c9427a0f8f9940f6d181e4f4775bcb9a8e2ae527..f88b4e15f59fc7e7d3a4b434c8328942982a67ba 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx @@ -2,12 +2,12 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#include "FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h" +#include "FaserActsKalmanFilterAlg.h" // 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,15 +37,17 @@ #include "Acts/EventData/TrackParameters.hpp" #include "Acts/EventData/MultiTrajectoryHelpers.hpp" #include "Acts/EventData/Measurement.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" // PACKAGE #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" #include "ActsInterop/Logger.h" #include "FaserActsGeometry/FaserActsGeometryContext.h" -#include "FaserActsGeometry/IFaserActsPropStepRootWriterSvc.h" +#include "FaserActsGeometryInterfaces/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/FaserActsKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.h new file mode 100755 index 0000000000000000000000000000000000000000..a2b4c7295d0d476f34d38bd4e90778e64c6d40da --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.h @@ -0,0 +1,134 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef FASERACTSKALMANFILTER_FASERACTSKALMANFILTERALG_H +#define FASERACTSKALMANFILTER_FASERACTSKALMANFILTERALG_H + +// ATHENA +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/ITHistSvc.h" +#include "Gaudi/Property.h" /*no forward decl: typedef*/ +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" +#include "StoreGate/ReadCondHandleKey.h" +#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h" +#include "TrackerSpacePoint/FaserSCT_SpacePoint.h" +#include "TrackerSpacePoint/SpacePointForSeedCollection.h" +#include "MagFieldConditions/FaserFieldCacheCondObj.h" +#include "MagFieldElements/FaserFieldCache.h" +#include "TrackerReadoutGeometry/SiDetectorElementCollection.h" +#include "Identifier/Identifier.h" +#include "GeneratorObjects/McEventCollection.h" +#include "TrackerSimData/TrackerSimDataCollection.h" +#include "TrkTrack/TrackCollection.h" +#include "TrajectoryWriterTool.h" + +// ACTS +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/MagneticField/SharedBField.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Propagator/detail/SteppingLogger.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "Acts/Definitions/Common.hpp" + +// PACKAGE +#include "FaserActsGeometry/FASERMagneticFieldWrapper.h" +#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h" +#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h" +#include "FaserActsRecMultiTrajectory.h" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include "FaserActsKalmanFilter/Measurement.h" +#include "FaserActsKalmanFilter/ITrackFinderTool.h" +//#include "ProtoTrackWriterTool.h" +#include "RootTrajectoryStatesWriterTool.h" + +// STL +#include <memory> +#include <vector> +#include <fstream> +#include <mutex> + +class EventContext; +class IAthRNGSvc; +class FaserSCT_ID; +class TTree; + +namespace ActsExtrapolationDetail { + class VariantPropagator; +} + +namespace TrackerDD { + class SCT_DetectorManager; +} + +using TrajectoryContainer = std::vector<FaserActsRecMultiTrajectory>; +using BField_t = FASERMagneticFieldWrapper; + +//class FaserActsKalmanFilterAlg : public AthReentrantAlgorithm { +class FaserActsKalmanFilterAlg : public AthAlgorithm { +public: + FaserActsKalmanFilterAlg(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~FaserActsKalmanFilterAlg() = default; + + StatusCode initialize() override; +// StatusCode execute(const EventContext& ctx) const override; + StatusCode execute() override; + StatusCode finalize() override; + + 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 TrackParameters = Acts::CurvilinearTrackParameters; + + 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; + +private: + const FaserSCT_ID* m_idHelper {nullptr}; + std::shared_ptr<TrackFitterFunction> m_fit; + std::unique_ptr<const Acts::Logger> m_logger; + + 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; + + // 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<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<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, "FaserActsKFTrackCollection", "FaserActsKFTrackCollection", "Output track collection" }; +}; + +#endif diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsRecMultiTrajectory.h b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsRecMultiTrajectory.h new file mode 100644 index 0000000000000000000000000000000000000000..06924bed8e4adbe304697a4f71019d9134be72f8 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsRecMultiTrajectory.h @@ -0,0 +1,93 @@ +// Copyright (C) 2019 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#pragma once + +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "FaserActsKalmanFilter/IndexSourceLink.h" +#include <unordered_map> +#include <utility> + +/// 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: + /// (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>; + + /// 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) {} + + /// Return true if there exists no valid trajectory. + bool empty() const { return m_trackTips.empty(); } + + /// Access the underlying multi trajectory. + const MultiTrajectory& multiTrajectory() const { return m_multiTrajectory; } + + /// Access the tip indices that identify valid trajectories. + const std::vector<size_t>& tips() const { return m_trackTips; } + + /// 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)); + } + + /// 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)); + } + + /// 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()) { + throw std::runtime_error( + "No fitted track parameters for trajectory with entry index = " + + std::to_string(entryIndex)); + } + return it->second; + } + +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/src/GhostBusters.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6eab8b1b84f2a745e8d02395f8063306428dbd58 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.cxx @@ -0,0 +1,114 @@ +#include "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/GhostBusters.h b/Tracking/Acts/FaserActsKalmanFilter/src/GhostBusters.h new file mode 100644 index 0000000000000000000000000000000000000000..67b493b46cb018fa3ec0a96d083a863b0e33389b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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 "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/src/KalmanFitterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..051687e21c6d0b1c1874a26ac4ddeb5d55c55124 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx @@ -0,0 +1,244 @@ +#include "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(m_createTrkTrackTool.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, + Trk::Track* inputTrack, 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 = m_createTrkTrackTool->createTrack(gctx, myTrajectories.back()); + } + + 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(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]; + params(4.0) = inputParameters->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); +} diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0894e3ab2139decc1f0950a89f6200dc9ea2930f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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 "FaserActsRecMultiTrajectory.h" +#include "MagFieldConditions/FaserFieldCacheCondObj.h" +#include "RootTrajectoryStatesWriterTool.h" +#include "RootTrajectorySummaryWriterTool.h" +#include "TrkTrack/Track.h" +#include "TrkTrack/TrackCollection.h" +#include "CreateTrkTrackTool.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, + Trk::Track *inputTrack, + 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(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"}; + ToolHandle<CreateTrkTrackTool> m_createTrkTrackTool {this, "CreateTrkTrackTool", "CreateTrkTrackTool"}; +}; + +#endif //FASERACTSKALMANFILTER_KALMANFITTERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/LinearFit.h b/Tracking/Acts/FaserActsKalmanFilter/src/LinearFit.h new file mode 100644 index 0000000000000000000000000000000000000000..f367110a4b7a05cb9bc610628995cfa6df53ddb0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/MultiTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8b5b0e584441bb17a66584e38359acd004a85514 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.cxx @@ -0,0 +1,120 @@ +#include "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/MultiTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/MultiTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..988c50bdf880ababa5cc22bb77552a625f5c6a15 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/MyAmbiguitySolver.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.cxx new file mode 100644 index 0000000000000000000000000000000000000000..eed78995ba97878ec24d984e3f6d8e2462c12be6 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.cxx @@ -0,0 +1,3 @@ +#include "MyAmbiguitySolver.h" + + diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.h b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.h new file mode 100644 index 0000000000000000000000000000000000000000..bcb5a909882e4558a2d8d2d8c135cefdef199886 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyAmbiguitySolver.h @@ -0,0 +1,80 @@ +#ifndef FASERACTSKALMANFILTER_AMBIGUITYSOLVER_H +#define FASERACTSKALMANFILTER_AMBIGUITYSOLVER_H + +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" +#include "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/src/MyTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b5a5e04895ed443cb4e868c4ce722ac45fe65f2f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx @@ -0,0 +1,143 @@ +#include "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(std::vector<int> /*maskedLayers*/) { + + // 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/MyTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..df545c34abfd37e8b778a0c0be5b23852dbb7b7b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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(std::vector<int> /*maskedLayers*/) 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/src/PerformanceWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6565ef13ff1cdcd53fc545e0d9f40f866bd378de --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx @@ -0,0 +1,183 @@ +#include "PerformanceWriterTool.h" +#include "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/PerformanceWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..88d3372c97644b401c040a163e8d0d9261ddcd3b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.h @@ -0,0 +1,51 @@ +#ifndef FASERACTSKALMANFILTER_PERFORMANCEWRITER_H +#define FASERACTSKALMANFILTER_PERFORMANCEWRITER_H + +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "ResPlotTool.h" +#include "EffPlotTool.h" +#include "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/src/PlotHelpers.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a5696dbaf01c1ff95c1071a292e656f891858aad --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.cxx @@ -0,0 +1,92 @@ +#include "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/PlotHelpers.h b/Tracking/Acts/FaserActsKalmanFilter/src/PlotHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..c3e8a1caf22d1debbea709c8fbbfe3c8a1b695c2 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/ProtoTrackWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a8cad0d5704e9a20892f24881de4c46e623813e8 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.cxx @@ -0,0 +1,108 @@ +#include "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/ProtoTrackWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/ProtoTrackWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..a71ddb56ab7b70af4930fc5cd1369010a5e7446b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/ResPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..78c29b9ea08b22da5f01c2b65416011bc0f25c97 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.cxx @@ -0,0 +1,201 @@ +#include "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/ResPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..9b27be2b0df2250e4c103fc3e133f34a14df40a4 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ResPlotTool.h @@ -0,0 +1,87 @@ +#ifndef FASERACTSKALMANFILTER_RESPLOTTOOL_H +#define FASERACTSKALMANFILTER_RESPLOTTOOL_H + +#include "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/src/RootTrajectoryStatesWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c46c1a0b9a08d6afb821c08cbadb0fda69d9b160 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx @@ -0,0 +1,726 @@ +#include "RootTrajectoryStatesWriterTool.h" + +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "Acts/EventData/detail/TransformationBoundToFree.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "FaserActsRecMultiTrajectory.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "TrackerReadoutGeometry/SCT_DetectorManager.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "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/RootTrajectoryStatesWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..266de4bd060756668c4c0c806bda4a6336835fce --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.h @@ -0,0 +1,131 @@ +#ifndef FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H +#define FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H + +#include "GeoPrimitives/GeoPrimitives.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/src/RootTrajectorySummaryWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ef476a0bba43d30df89ae7b5df8f1d6ed1b1235c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx @@ -0,0 +1,468 @@ +#include "RootTrajectorySummaryWriterTool.h" + +// #include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "Acts/EventData/detail/TransformationBoundToFree.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "FaserActsRecMultiTrajectory.h" +#include "TrackerIdentifier/FaserSCT_ID.h" +#include "GeoPrimitives/CLHEPtoEigenConverter.h" +#include "TrackerReadoutGeometry/SiDetectorElement.h" +#include "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(); + Acts::Vector3 v; + t_p = truthParameters->momentum().norm(); + 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/RootTrajectorySummaryWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..90cf6cf84ca8a95b41397bd00dea30d85135967f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/SPSeedBasedInitialParameterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SPSeedBasedInitialParameterTool.cxx index f29ce6e80e65a9ca759f931174318fd1c1a68b68..bc8c89d86d947b7d4d40096b129877d3967b1261 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/SPSeedBasedInitialParameterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SPSeedBasedInitialParameterTool.cxx @@ -1,4 +1,4 @@ -#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h" +#include "SPSeedBasedInitialParameterTool.h" #include "StoreGate/ReadHandle.h" #include "HepMC/GenVertex.h" diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SPSeedBasedInitialParameterTool.h similarity index 100% rename from Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h rename to Tracking/Acts/FaserActsKalmanFilter/src/SPSeedBasedInitialParameterTool.h diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.cxx index f3d227dcb6e81085b28a12d6e68a5161d171dba3..99549262760c403e8c7f34d1bc3dbdd76b430197 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.cxx @@ -1,4 +1,4 @@ -#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h" +#include "SPSimpleInitialParameterTool.h" #include "StoreGate/ReadHandle.h" #include "HepMC/GenVertex.h" diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SPSimpleInitialParameterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.h similarity index 100% rename from Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SPSimpleInitialParameterTool.h rename to Tracking/Acts/FaserActsKalmanFilter/src/SPSimpleInitialParameterTool.h diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bc9bfab6d64aee5d3f07818efa496cd57bfa4d9f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.cxx @@ -0,0 +1,22 @@ +#include "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/SeedingAlg.h b/Tracking/Acts/FaserActsKalmanFilter/src/SeedingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..49fd1c901ab2f0159cd033401ddde589b61262e6 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/SegmentFitClusterTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c0a0512179aea73eb45f852c4317fa1140a67b83 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.cxx @@ -0,0 +1,151 @@ +#include "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/SegmentFitClusterTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitClusterTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d42ab5a241e51700351399b2dd196030bcde1d0b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/SegmentFitTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d1db42f936959115970b3133e772a2a0d47cae00 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.cxx @@ -0,0 +1,152 @@ +#include "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/SegmentFitTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SegmentFitTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..fa34f94c67def0746214cd84b4467d7391707e3b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/SimWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SimWriterTool.cxx index 0e9a39a11391c8d2a67a487151b60ee6a075b9ef..2b21fcbae96b23d99c67656a187f68ed6a4198d7 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/SimWriterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SimWriterTool.cxx @@ -1,4 +1,4 @@ -#include "FaserActsKalmanFilter/SimWriterTool.h" +#include "SimWriterTool.h" #include "TFile.h" #include "TTree.h" diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SimWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SimWriterTool.h similarity index 100% rename from Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/SimWriterTool.h rename to Tracking/Acts/FaserActsKalmanFilter/src/SimWriterTool.h diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2ddb76108814e1cc746e39b4b5f2bbbd0e385ccd --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.cxx @@ -0,0 +1,86 @@ +#include "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/SummaryPlotTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0bb6c326ed215219677f1b1be77b2c515ef0e6bb --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/SummaryPlotTool.h @@ -0,0 +1,67 @@ +#ifndef FASERACTSKALMANFILTER_SUMMARYPLOTTOOL_H +#define FASERACTSKALMANFILTER_SUMMARYPLOTTOOL_H + +#include "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/src/ThreeStationTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..15db300108f9090ba35c6b09ddc66a9b6cf7513a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx @@ -0,0 +1,144 @@ +#include "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(std::vector<int> /*maskedLayers*/) { + // 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/ThreeStationTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.h new file mode 100644 index 0000000000000000000000000000000000000000..deab07bb12c5b061376975ba5d984f95b15da71e --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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(std::vector<int> /*maskedLayers*/) 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/src/TrackClassification.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ed9682702a71145f9a4772cb7e49bda33ee8e8e0 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx @@ -0,0 +1,93 @@ +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "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/TrackClassification.h b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.h new file mode 100644 index 0000000000000000000000000000000000000000..da59b9badded276e508d5c57ccca6636ebf607e9 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.h @@ -0,0 +1,23 @@ +#ifndef FASERACTSKALMANFILTER_TRACKCLASSIFICATION_H +#define FASERACTSKALMANFILTER_TRACKCLASSIFICATION_H + +#include "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/src/TrackFindingAlgorithmFunction.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx index 954906a0f4263c6e17f17143b23d4639c5d1107a..1a434fa8131e3964dc5f47fafee330c5e8b8187a 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFindingAlgorithmFunction.cxx @@ -1,4 +1,4 @@ -#include "FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h" +#include "CombinatorialKalmanFilterAlg.h" #include "FaserActsGeometry/FASERMagneticFieldWrapper.h" #include "Acts/Propagator/EigenStepper.hpp" @@ -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..460300bac782f14a09fb22df387e5ba3ab89b135 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackFittingFunction.cxx @@ -0,0 +1,118 @@ +#include "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..4ec607686a6d88e8f8be08bdd06d77665ee78cdd --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx @@ -0,0 +1,121 @@ +#include "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/TrackSeedWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e078acc19edd584ce2f514a4a3985bbaf7cc326c --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/TrackSelection.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b06019cf06fa2caae6816657233b213d9f9dd07f --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.cxx @@ -0,0 +1,42 @@ +#include "TrackSelection.h" + +// #include "TrackerPrepRawData/FaserSCT_Cluster.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/TrackSelection.h b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.h new file mode 100644 index 0000000000000000000000000000000000000000..aeebd0ff1c0de3ce997e59578726609bdbbb02b7 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSelection.h @@ -0,0 +1,20 @@ +#ifndef FASERACTSKALMANFILTER_TRACKSELECTION_H +#define FASERACTSKALMANFILTER_TRACKSELECTION_H + +#include "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/src/TrajectoryWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx index f742348b0197db4f89a164acee6067aecf9dfe07..fc98f2959933dab1e70b2de892ef020c425dcf74 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.cxx @@ -1,5 +1,6 @@ -#include "FaserActsKalmanFilter/TrajectoryWriterTool.h" -#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include "TrackerPrepRawData/FaserSCT_Cluster.h" +#include "TrajectoryWriterTool.h" +#include "FaserActsRecMultiTrajectory.h" #include "Acts/EventData/MultiTrajectoryHelpers.hpp" #include "TFile.h" #include "TTree.h" @@ -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; @@ -237,7 +250,6 @@ void TrajectoryWriterTool::writeout(TrajectoriesContainer trajectories, // 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 = @@ -250,12 +262,7 @@ void TrajectoryWriterTool::writeout(TrajectoriesContainer trajectories, 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)) { @@ -311,18 +318,19 @@ void TrajectoryWriterTool::writeout(TrajectoriesContainer trajectories, // expand the local measurements into the full bound space Acts::BoundVector meas = state.projector().transpose() * state.calibrated(); - std::cout<<state.projector()<<std::endl; - std::cout<<state.projector().transpose()<<std::endl; - std::cout<<state.calibrated()<<std::endl; - std::cout<<meas<<std::endl; // 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]); @@ -350,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]); @@ -439,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]); @@ -530,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]); @@ -648,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/FaserActsKalmanFilter/TrajectoryWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.h similarity index 95% rename from Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h rename to Tracking/Acts/FaserActsKalmanFilter/src/TrajectoryWriterTool.h index 659cea7fa08321bb43a38fcc598a7054b119262c..0643ad9ce973f65453e72063701befaa3b2789ec 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrajectoryWriterTool.h +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/TruthBasedInitialParameterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx index 85b1036e415fb3f28f9f6b8ee37679afb60304bd..8be51c43441b128cee437068af940bf8a13b1abf 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.cxx @@ -1,4 +1,4 @@ -#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.h" +#include "TruthBasedInitialParameterTool.h" #include "StoreGate/ReadHandle.h" #include "HepMC/GenVertex.h" @@ -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/FaserActsKalmanFilter/TruthBasedInitialParameterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.h similarity index 95% rename from Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthBasedInitialParameterTool.h rename to Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.h index 6b94890f311f2661ba90fd69498330adb1573ee4..f22a904ce029edbe0131109dd973d864caa82fbb 100644 --- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TruthBasedInitialParameterTool.h +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthBasedInitialParameterTool.h @@ -3,7 +3,7 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "TrackerSimData/TrackerSimDataCollection.h" -#include "FaserActsKalmanFilter/SimWriterTool.h" +#include "SimWriterTool.h" namespace Acts { diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f0d9796f1a16ce52aee2bf52dbc11ec28c96a7a5 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx @@ -0,0 +1,252 @@ +#include "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/TruthSeededTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d07fcde1431a7651c10de46a38bba96553a5d25b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/TruthTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bfd5e9b740bbeb53529fc2c6e1048656187e1d5a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx @@ -0,0 +1,191 @@ +#include "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/TruthTrackFinderTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.h new file mode 100644 index 0000000000000000000000000000000000000000..37ac68be771dc60cafd45ccfd6af38723f59470b --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/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/src/components/FaserActsKalmanFilter_entries.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx index bb963dd1927d09d03fa2661efb5913f1c33e4dd4..967f80641f7846d303be4632c252ca30eaab6436 100755 --- a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx +++ b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx @@ -2,19 +2,58 @@ Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration */ -#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 "../FaserActsKalmanFilterAlg.h" +#include "../CombinatorialKalmanFilterAlg.h" +//#include "../MultiTrackFinderTool.h" +//#include "../TruthBasedInitialParameterTool.h" +//#include "../TruthTrackFinderTool.h" +//#include "../SPSeedBasedInitialParameterTool.h" +//#include "../SPSimpleInitialParameterTool.h" +//#include "../TrajectoryWriterTool.h" +//#include "../SimWriterTool.h" +//#include "../TruthSeededTrackFinderTool.h" +//#include "../ProtoTrackWriterTool.h" +#include "../RootTrajectoryStatesWriterTool.h" +#include "../RootTrajectorySummaryWriterTool.h" +//#include "../SegmentFitClusterTrackFinderTool.h" +//#include "../SegmentFitTrackFinderTool.h" +//#include "../ClusterTrackSeedTool.h" +#include "../ThreeStationTrackSeedTool.h" +#include "../PerformanceWriterTool.h" +#include "../TrackSeedWriterTool.h" +#include "../ActsTrackSeedTool.h" +#include "../CKF2.h" +#include "../KalmanFitterTool.h" +#include "../MyTrackSeedTool.h" +#include "../SeedingAlg.h" +#include "../CircleFitTrackSeedTool.h" +#include "../GhostBusters.h" +#include "../CreateTrkTrackTool.h" 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) +DECLARE_COMPONENT(CreateTrkTrackTool) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py new file mode 100644 index 0000000000000000000000000000000000000000..27c50d9a8b397776ccf19e810ff981afa47a6b67 --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py @@ -0,0 +1,73 @@ +#!/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 FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +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 +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("file", nargs="+", help="full path to input file") +parser.add_argument("--nevents", "-n", default=-1, type=int, help="Number of events to process") +args = parser.parse_args() + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = args.file +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 = "geometry-maps.json" +ConfigFlags.Input.isMC = True +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(FaserGeometryCfg(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)) +# 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)) + +acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M" + +sc = acc.run(maxEvents=args.nevents) +sys.exit(not sc.isSuccess()) diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py index ab47c4719fcb7ed6b420ddcd691965a82570b600..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,17 +31,17 @@ acc.merge(PoolReadCfg(ConfigFlags)) acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags)) acc.merge(TrackerSpacePointFinderCfg(ConfigFlags)) -acc.merge(TrackerSeedFinderCfg(ConfigFlags)) -acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags)) - -logging.getLogger('forcomps').setLevel(INFO) -acc.foreach_component("*").OutputLevel = INFO -acc.foreach_component("*ClassID*").OutputLevel = INFO -acc.getService("StoreGateSvc").Dump = True -acc.getService("ConditionStore").Dump = True -acc.printConfig(withDetails=True) -ConfigFlags.dump() +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 +# 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) - 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..cf63c3e400de073ad330df6498129996863b6c3a --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/test/TI12CKF2.py @@ -0,0 +1,72 @@ +#!/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 FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg +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 + +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("file", nargs="+", help="full path to input file") +parser.add_argument("--nevents", "-n", default=-1, type=int, help="Number of events to process") +args = parser.parse_args() + +log.setLevel(DEBUG) +Configurable.configurableRun3Behavior = True + +ConfigFlags.Input.Files = args.file +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 = "FASERNU-03" +ConfigFlags.Common.isOnline = False +ConfigFlags.GeoModel.Align.Dynamic = False +ConfigFlags.Beam.NumberOfCollisions = 0. +ConfigFlags.Detector.GeometryFaserSCT = True +ConfigFlags.TrackingGeometry.MaterialSource = "geometry-maps.json" +ConfigFlags.lock() + +acc = MainServicesCfg(ConfigFlags) +acc.merge(FaserGeometryCfg(ConfigFlags)) +acc.merge(PoolWriteCfg(ConfigFlags)) +acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags, OccupancyCut=0.015)) +acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_EDGEMODE_RDOs", ClusterToolTimingPattern="01X")) +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=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() + +# 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=args.nevents) +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 new file mode 100644 index 0000000000000000000000000000000000000000..d7e9fd857b273c764dad780aceebd0d3f58acc3a --- /dev/null +++ b/Waveform/WaveDigiTools/CMakeLists.txt @@ -0,0 +1,24 @@ +################################################################################ +# Package: WaveDigiTools +################################################################################ + +# Declare the package name: +atlas_subdir( WaveDigiTools ) + +# External dependencies: +find_package( ROOT ) + +# Component(s) in the package: +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 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) + diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h new file mode 100644 index 0000000000000000000000000000000000000000..c30351902a1b79e9a58ad33d5f58a5d04ed13faa --- /dev/null +++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** + * @file IWaveformDigitisationTool.h + * Header file for the IWaveformDigitisationTool class + * @author Carl Gwilliam, 2021 + */ + + +#ifndef WAVEDIGITOOLS_IWAVEFORMDIGITISATIONTOOL_H +#define WAVEDIGITOOLS_IWAVEFORMDIGITISATIONTOOL_H + +// Base class +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/ToolHandle.h" + +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/IMessageSvc.h" +#include "GaudiKernel/MsgStream.h" + +#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 +{ +public: + + // InterfaceID + DeclareInterfaceID(IWaveformDigitisationTool, 1, 0); + + IWaveformDigitisationTool(): + m_msgSvc ( "MessageSvc", "ITrkEventCnvTool" ) + {} + + virtual ~IWaveformDigitisationTool() = default; + + /// 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" + + +#endif //WAVEDIGITOOLS_IWAVEFORMDIGITISATIONTOOL_H diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc new file mode 100644 index 0000000000000000000000000000000000000000..41b8c2650319a448df63d11e098fc8d0784dc056 --- /dev/null +++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc @@ -0,0 +1,17 @@ +#include "Identifier/Identifier.h" +#include "Identifier/ExpandedIdentifier.h" + +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; + + 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); + } + + return waveforms; +} diff --git a/Waveform/WaveDigiTools/share/WaveformDigiAndRecoExample_jobOptions.py b/Waveform/WaveDigiTools/share/WaveformDigiAndRecoExample_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..779031828c9c5736f9403e403514e19285029499 --- /dev/null +++ b/Waveform/WaveDigiTools/share/WaveformDigiAndRecoExample_jobOptions.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import sys + +if __name__ == "__main__": + + fileroot = "output" + if len(sys.argv) > 1: + filename = sys.argv[1] + + doRDO = False + if len(sys.argv) > 2: + filename = sys.argv[2] + + from AthenaCommon.Logging import log, logging + from AthenaCommon.Constants import DEBUG, VERBOSE, INFO + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + from AthenaCommon.Configurable import Configurable + + Configurable.configurableRun3Behavior = True + + log.setLevel(VERBOSE) + + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02" # Always needed; must match FaserVersion + ConfigFlags.IOVDb.DatabaseInstance = "OFLP200" # Use MC conditions for now + ConfigFlags.Input.ProjectName = "mc21" # Needed to bypass autoconfig + ConfigFlags.Input.isMC = True # Needed to bypass autoconfig + ConfigFlags.GeoModel.FaserVersion = "FASER-TB00" # FASER geometry + ConfigFlags.Common.isOnline = False + ConfigFlags.GeoModel.Align.Dynamic = False + + ConfigFlags.Input.Files = [ + "/eos/project-f/faser-commissioning/Simulation/Test/TB.Elec.200GeV.SIM.root" + ] + + if doRDO: + ConfigFlags.Output.RDOFileName = f"{fileroot}.RDO.root" + else: + ConfigFlags.addFlag("Output.xAODFileName", f"{fileroot}.xAOD.root") + ConfigFlags.Output.ESDFileName = f"{fileroot}.ESD.root" + + ConfigFlags.lock() + + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + acc = MainServicesCfg(ConfigFlags) + + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg + + acc.merge(PoolReadCfg(ConfigFlags)) + acc.merge(PoolWriteCfg(ConfigFlags)) + + if doRDO: + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + itemList = [ + "RawWaveformContainer#*" + ] + acc.merge(OutputStreamCfg(ConfigFlags, "RDO", itemList,disableEventTag=True)) + + + else: + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + itemList = [ + "xAOD::EventInfo#*", + "xAOD::WaveformHitContainer#*", + "xAOD::WaveformHitAuxContainer#*", + ] + + acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList, disableEventTag=True)) + + from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg + acc.merge(ScintWaveformDigitizationCfg(ConfigFlags)) + + from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg + acc.merge(CaloWaveformDigitizationCfg(ConfigFlags)) + + if not doRDO: + from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg + acc.merge(WaveformReconstructionCfg(ConfigFlags)) + + #acc.foreach_component("*").OutputLevel = VERBOSE + + # Execute and finish + sc = acc.run(maxEvents=100) + + # Success should be 0 + sys.exit(not sc.isSuccess()) diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c62d7f8a753490907bd1e8a513cad5341a2a46be --- /dev/null +++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx @@ -0,0 +1,47 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** + * @file WaveformDigitisationTool.cxx + * Implementation file for the WaveformDigitisationTool class + * @ author C. Gwilliam, 2021 + **/ + +#include "WaveformDigitisationTool.h" + +// Constructor +WaveformDigitisationTool::WaveformDigitisationTool(const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +// Initialization +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 new file mode 100644 index 0000000000000000000000000000000000000000..e2dd5169152845824927baeeae7ce8fc36ab46f8 --- /dev/null +++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2021 CERN for the benefit of the FASER collaboration +*/ + +/** @file WaveformDigitisationTool.h + * Header file for WaveformDigitisationTool.h + * + */ +#ifndef WAVEDIGITOOLS_WAVEFORMDIGITISATIONTOOL_H +#define WAVEDIGITOOLS_WAVEFORMDIGITISATIONTOOL_H + +//Athena +#include "AthenaBaseComps/AthAlgTool.h" +#include "WaveDigiTools/IWaveformDigitisationTool.h" + +//Gaudi +#include "GaudiKernel/ToolHandle.h" + +//STL + +class WaveformDigitisationTool: public extends<AthAlgTool, IWaveformDigitisationTool> { + public: + + /// Normal constructor for an AlgTool; 'properties' are also declared here + WaveformDigitisationTool(const std::string& type, + const std::string& name, const IInterface* parent); + + /// 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 + +}; + +#endif // WAVEDIGITOOLS_WAVEFORMDIGITISATIONTOOL_H diff --git a/Waveform/WaveDigiTools/src/components/WaveDigiTools_entries.cxx b/Waveform/WaveDigiTools/src/components/WaveDigiTools_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..169476d905bb3e3a56de0d15aac7b7d13c3bdeb1 --- /dev/null +++ b/Waveform/WaveDigiTools/src/components/WaveDigiTools_entries.cxx @@ -0,0 +1,3 @@ +#include "../WaveformDigitisationTool.h" + +DECLARE_COMPONENT( WaveformDigitisationTool ) diff --git a/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt b/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt index bdf35c03e86b0fbac4807da3f4ace952b81e2dc1..36d369589cbf7967e5616ebbc7c230b95ff572d8 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt +++ b/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt @@ -4,16 +4,10 @@ atlas_subdir( WaveByteStream ) # Component(s) in the package: -#atlas_add_library( WaveByteStreamLib -# WaveByteStream/*.h -# PUBLIC_HEADERS WaveByteStream -# LINK_LIBRARIES StoreGateLib -# ) - atlas_add_component( WaveByteStream src/*.cxx src/components/*.cxx - LINK_LIBRARIES Identifier ScintIdentifier FaserCaloIdentifier AthenaKernel GaudiKernel FaserByteStreamCnvSvcBaseLib FaserEventStorageLib WaveRawEvent + LINK_LIBRARIES AthenaKernel GaudiKernel FaserByteStreamCnvSvcBaseLib FaserEventStorageLib WaveRawEvent WaveformConditionsToolsLib PRIVATE_LINK_LIBRARIES AthenaBaseComps ) atlas_install_python_modules( python/*.py ) diff --git a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py index cc13137d8e59eef7801d0ffa8fa60230721b372f..ad6bfcd1519674674ff7d101e320bc47176198ed 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py +++ b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py @@ -1,43 +1,12 @@ # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -from AthenaConfiguration.ComponentFactory import CompFactory from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from WaveformConditionsTools.WaveformCableMappingConfig import WaveformCableMappingCfg +from WaveformConditionsTools.WaveformRangeConfig import WaveformRangeCfg def WaveByteStreamCfg(configFlags, **kwargs): - acc = ComponentAccumulator() - - # Decide which waveform mapping to instantiate from Geo tag - - if configFlags.Input.isMC: - # Nothing to do for MC - print("WaveByteStreamConfig.WaveByteStreamCfg - Called for isMC True, nothing to do...") - return acc - - print("WaveByteStreamConfig.WaveByteStreamCfg - Found FaserVersion: ", configFlags.GeoModel.FaserVersion,) - - # Channels are ordered front->back, bottom->top, right->left - if configFlags.GeoModel.FaserVersion == "FASER-TB00": - print(" - setting up testbeam detector") - - waveform_tool = CompFactory.RawWaveformDecoderTool("RawWaveformDecoderTool") - waveform_tool.CaloChannels = [5, 3, 1, 4, 2, 0] - waveform_tool.VetoChannels = [] - waveform_tool.TriggerChannels = [8, 9] - waveform_tool.PreshowerChannels = [6, 7] - acc.addPublicTool(waveform_tool) - - elif configFlags.GeoModel.FaserVersion == "FASER-01": - print(" - setting up TI12 detector") - - waveform_tool = CompFactory.RawWaveformDecoderTool("RawWaveformDecoderTool") - waveform_tool.CaloChannels = [1, 0, 3, 2] - waveform_tool.VetoChannels = [4, 5, 6, 7] - waveform_tool.TriggerChannels = [9, 8, 11, 10] - waveform_tool.PreshowerChannels = [12, 13] - acc.addPublicTool(waveform_tool) - - else: - print(" - unknown version: user must set up Waveform channel mapping by hand!") - + 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 ec7a6641e3df94a8ac0b3b989e5c99303e3b62d7..852ae084edac08380e302ec3026548d667da70c2 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx +++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx @@ -19,20 +19,6 @@ RawWaveformDecoderTool::RawWaveformDecoderTool(const std::string& type, : AthAlgTool(type, name, parent) { declareInterface<RawWaveformDecoderTool>(this); - - // These must be configured by job options - declareProperty("CaloChannels", m_caloChannels); - declareProperty("VetoChannels", m_vetoChannels); - declareProperty("TriggerChannels", m_triggerChannels); - declareProperty("PreshowerChannels", m_preshowerChannels); - - // Test channels is provided for conveniene, not normally used - declareProperty("TestChannels", m_testChannels); - - // Clock should always be in channel 15 - declareProperty("ClockChannels", m_clockChannels); - m_clockChannels.push_back(15); - } RawWaveformDecoderTool::~RawWaveformDecoderTool() @@ -43,82 +29,6 @@ StatusCode RawWaveformDecoderTool::initialize() { ATH_MSG_DEBUG("RawWaveformDecoderTool::initialize()"); - - // Set up helpers - ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID")); - ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID")); - ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID")); - ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID")); - - // Take each channel list and create identifiers - - // Loop through digitizer channel lists creating Identifiers - m_identifierMap.clear(); - - // First, calorimeter. Can either be 4 or 6 channels - // Bottom row first from left to right, then top row - int index=0; - int module=0; - int row=0; - int pmt=0; - - int max_modules = m_caloChannels.size() / 2; - for (auto const& chan : m_caloChannels) { - row = index / max_modules; - module = index % max_modules; - index++; - // Only store in map if digitizer channel is valid - if (chan < 0) continue; - m_identifierMap[chan] = m_ecalID->pmt_id(row, module, pmt); - ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to calo ID: " << m_identifierMap[chan]); - } - - // Next, veto detector. Have station and plate here. - int station=0; - int plate=0; - pmt=0; - index=0; - - int max_stations=m_vetoChannels.size() / 2; - for (auto const& chan : m_vetoChannels) { - station = index / max_stations; - plate = index % max_stations; - index++; - // Only store in map if digitizer channel is valid - if (chan < 0) continue; - m_identifierMap[chan] = m_vetoID->pmt_id(station, plate, pmt); - ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to veto ID: " << m_identifierMap[chan]); - } - - // Next, trigger detector. Have pmt and plate. - pmt=0; - station=0; - index=0; - int max_plates=m_triggerChannels.size() / 2; - for (auto const& chan : m_triggerChannels) { - plate = index / max_plates; - pmt = index % max_plates; - index++; - // Only store in map if digitizer channel is valid - if (chan < 0) continue; - m_identifierMap[chan] = m_triggerID->pmt_id(station, plate, pmt); - ATH_MSG_DEBUG("Mapped dititizer channel " << chan << " to trigger ID: " << m_identifierMap[chan]); - } - - // Finally, preshower detector. - pmt=0; - station=0; - plate=0; - index=0; - for (auto const& chan : m_preshowerChannels) { - plate = index; - index++; - // Only store in map if digitizer channel is valid - if (chan < 0) continue; - m_identifierMap[chan] = m_preshowerID->pmt_id(station, plate, pmt); - ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to preshower ID: " << m_identifierMap[chan]); - } - return StatusCode::SUCCESS; } @@ -131,8 +41,11 @@ RawWaveformDecoderTool::finalize() StatusCode RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, - RawWaveformContainer* container, - const std::string key) + RawWaveformContainer* container, + const std::string key, + WaveformCableMap cable_map, + WaveformRangeMap range_map +) { ATH_MSG_DEBUG("RawWaveformDecoderTool::convert("+key+")"); @@ -172,26 +85,34 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, ATH_MSG_DEBUG("Found valid digitizer fragment"); } - std::vector<int>* channelList; - + // Detector type to match in first element of cable map + std::string det_type; if (key == std::string("CaloWaveforms")) { - channelList = &m_caloChannels; + det_type = std::string("calo"); } else if (key == std::string("VetoWaveforms")) { - channelList = &m_vetoChannels; + det_type = std::string("veto"); + } else if (key == std::string("VetoNuWaveforms")) { + det_type = std::string("vetonu"); } else if (key == std::string("TriggerWaveforms")) { - channelList = &m_triggerChannels; + det_type = std::string("trigger"); } else if (key == std::string("PreshowerWaveforms")) { - channelList = &m_preshowerChannels; - } else if (key == std::string("TestWaveforms")) { - channelList = &m_testChannels; + det_type = std::string("preshower"); } else if (key == std::string("ClockWaveforms")) { - channelList = &m_clockChannels; + det_type = std::string("clock"); } else { ATH_MSG_ERROR("Unknown key " << key); return StatusCode::FAILURE; } - for (int channel: *channelList) { + // Loop over 16 digitizer channels + std::vector<int> channelList(16); + std::iota (std::begin(channelList), std::end(channelList), 0); + + for (int channel: channelList) { + + // Only look at channels we care about + if (det_type != cable_map[channel].first) continue; + ATH_MSG_DEBUG("Converting channel "+std::to_string(channel)+" for "+key); // Check if this has data @@ -223,10 +144,13 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, } // Set ID if one exists (clock, for instance, doesn't have an identifier) - if (m_identifierMap.count(channel) == 1) { - wfm->setIdentifier(m_identifierMap[channel]); + 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 e2852f13772113d8e52a62c9655a18365cb80f61..5d3ff24600e76a6d37c7e5bb60e0729e36bb71ac 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h +++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h @@ -13,11 +13,8 @@ #include "EventFormats/DAQFormats.hpp" #include "WaveRawEvent/RawWaveformContainer.h" -#include "Identifier/Identifier.h" -#include "FaserCaloIdentifier/EcalID.h" -#include "ScintIdentifier/VetoID.h" -#include "ScintIdentifier/TriggerID.h" -#include "ScintIdentifier/PreshowerID.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" +#include "WaveformConditionsTools/IWaveformRangeTool.h" // This class provides conversion between bytestream and Waveform objects @@ -34,53 +31,9 @@ class RawWaveformDecoderTool : public AthAlgTool { virtual StatusCode initialize(); virtual StatusCode finalize(); - StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key); + StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key, WaveformCableMap cable_map, WaveformRangeMap range_map); private: - // List of channels to include in each container - // List order must correspond to offline channel order - // All L/R designations refer to looking at the detector from - // the beam direction. - // - // In general, the ordering is layer (longitudinal), row (vertical), module (horizontal) - // Layers increase with longitudianl position downstream - // Rows increase from bottom to top - // Modules increase from right to left - // - // For all lists, use invalid channel (-1) to indicate detectors - // missing in sequence (i.e. 3 of 4 veto counters) - // - // TI12 detector: - // Calorimeter order: - // bottom right, bottom left, top right, top left - // Veto - // front to back. - // Trigger - // bottom right PMT, bottom left PMT, top right PMT, top left PMT - // Preshower - // front to back - // - // 2021 Testbeam detector: - // Calo order: - // bottom right, bottom center, bottom left, top R, top C, top L - // All others are just in order front to back - - std::vector<int> m_caloChannels; - std::vector<int> m_vetoChannels; - std::vector<int> m_triggerChannels; - std::vector<int> m_preshowerChannels; - std::vector<int> m_testChannels; - std::vector<int> m_clockChannels; - - // Identifiers keyed by digitizer channel - std::map<unsigned int, Identifier> m_identifierMap; - - // ID helpers - const EcalID* m_ecalID{nullptr}; - const VetoID* m_vetoID{nullptr}; - const TriggerID* m_triggerID{nullptr}; - const PreshowerID* m_preshowerID{nullptr}; - }; #endif /* WAVEBYTESTREAM_FASERTRIGGERDECODERTOOL_H */ diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx index 189d94c5fcc2bc966135fdda74f2e23e5a5b2a50..38d1cc20c5240277d6a985c2ba8e57d064baa49f 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx +++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx @@ -26,6 +26,8 @@ WaveByteStreamCnv::WaveByteStreamCnv(ISvcLocator* svcloc) , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "WaveByteStreamCnv") , m_name("WaveByteStreamCnv") , m_tool("RawWaveformDecoderTool") + , m_mappingTool("WaveformCableMappingTool") + , m_rangeTool("WaveformRangeTool") , m_rdpSvc("FaserROBDataProviderSvc", m_name) { ATH_MSG_DEBUG(m_name+"::initialize() called"); @@ -47,7 +49,8 @@ StatusCode WaveByteStreamCnv::initialize() CHECK(Converter::initialize()); CHECK(m_rdpSvc.retrieve()); CHECK(m_tool.retrieve()); - + CHECK(m_mappingTool.retrieve()); + CHECK(m_rangeTool.retrieve()); return StatusCode::SUCCESS; } @@ -90,9 +93,15 @@ StatusCode WaveByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj RawWaveformContainer* wfmCont = new RawWaveformContainer; - // Convert selected channels + // Get mapping tool + auto mapping = m_mappingTool->getCableMapping(); + ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries"); - CHECK( m_tool->convert(re, wfmCont, key) ); + auto range = m_rangeTool->getRangeMapping(); + ATH_MSG_DEBUG("Range contains " << range.size() << " entries"); + + // Convert selected channels + 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 043ebef563e383143955f0312e684b716ac61839..960b8759e2f72633eae58efb882d67848cdfee07 100644 --- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h +++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h @@ -14,6 +14,8 @@ #include "AthenaBaseComps/AthMessaging.h" #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" +#include "WaveformConditionsTools/IWaveformRangeTool.h" class RawWaveformDecoderTool; class IFaserROBDataProviderSvc; @@ -39,8 +41,9 @@ public: private: std::string m_name; ToolHandle<RawWaveformDecoderTool> m_tool; + ToolHandle<IWaveformCableMappingTool> m_mappingTool; + ToolHandle<IWaveformRangeTool> m_rangeTool; ServiceHandle<IFaserROBDataProviderSvc> m_rdpSvc; - }; #endif /* WAVEBYTESTREAM_WAVEBYTESTREAMCNV_H */ 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 39a99ed0c39d01e08c5f555e4e3efd98e0bc70a1..527c4e289eb1533e130301ee3a9c916d48d8e129 100644 --- a/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py +++ b/Waveform/WaveRecAlgs/python/WaveRecAlgsConfig.py @@ -6,29 +6,41 @@ 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 = True): +def WaveformReconstructionCfg(flags): """ Return all algorithms and tools for Waveform reconstruction """ acc = ComponentAccumulator() - if flags.Input.isMC and naive: - if not "TB" in flags.GeoModel.FaserVersion: - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoTimingHitWaveformRecAlg", "Trigger")) - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoVetoHitToWaveformRecAlg", "Veto")) - acc.merge(PseudoScintHitToWaveformRecCfg(flags, "PseudoPresehowerHitWaveformRecAlg", "Preshower")) - acc.merge(PseudoCaloHitToWaveformRecCfg(flags, "PseudoCaloHitWaveformRecAlg")) - return acc + if not flags.Input.isMC: + acc.merge(WaveformClockRecCfg(flags, "ClockRecAlg")) - acc.merge(WaveformClockRecCfg(flags, "ClockRecAlg")) + if "TB" in flags.GeoModel.FaserVersion: + acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo")) - acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto")) - acc.merge(WaveformHitRecCfg(flags, "TimingWaveformRecAlg", "Trigger")) - acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower")) + # Make preshower/veto window 200 ns wide (100 digitizer clock ticks) + acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto", FitWindowWidth=100 )) + acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100 )) + + else: + acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo")) + + acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto", FitWindowWidth=100 )) + acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100 )) + acc.merge(WaveformHitRecCfg(flags, "TriggerWaveformRecAlg", "Trigger", FitWindowWidth=100)) + acc.merge(WaveformHitRecCfg(flags, "VetoNuWaveformRecAlg", "VetoNu", FitWindowWidth=100)) + + acc.merge(WaveformHitRecCfg(flags, "VetoWaveformRecAlg", "Veto", FitWindowWidth=100 )) + # Make preshower window 200 ns wide (value in digitizer clock ticks) + acc.merge(WaveformHitRecCfg(flags, "PreshowerWaveformRecAlg", "Preshower", FitWindowWidth=100 )) acc.merge(WaveformHitRecCfg(flags, "CaloWaveformRecAlg", "Calo")) + + acc.merge(WaveformTimingCfg(flags)) + return acc # Return configured WaveformClock reconstruction algorithm @@ -47,12 +59,21 @@ 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) + + tool = WaveformReconstructionTool(name=source+"WaveformRecTool", **kwargs) + + # Remove arguments intended for WaveRecTool + if "PeakThreshold" in kwargs: kwargs.pop("PeakThreshold") + if "FitWindowWidth" in kwargs: kwargs.pop("FitWindowWidth") + kwargs.setdefault("WaveformContainerKey", source+"Waveforms") kwargs.setdefault("WaveformHitContainerKey", source+"WaveformHits") kwargs.setdefault("WaveformReconstructionTool", tool) diff --git a/Waveform/WaveRecAlgs/src/PseudoCaloHitToWaveformRecAlg.cxx b/Waveform/WaveRecAlgs/src/PseudoCaloHitToWaveformRecAlg.cxx index 5ead65452727c36307d8b4c038812ca9c3683f47..2074b566e044e8bc647237fa7ff5c127f9a94ffe 100644 --- a/Waveform/WaveRecAlgs/src/PseudoCaloHitToWaveformRecAlg.cxx +++ b/Waveform/WaveRecAlgs/src/PseudoCaloHitToWaveformRecAlg.cxx @@ -42,12 +42,6 @@ PseudoCaloHitToWaveformRecAlg::execute(const EventContext& ctx) const { ATH_CHECK( caloHitHandle.isValid() ); ATH_MSG_DEBUG("Found ReadHandle for CaloHitCollection " << m_caloHitContainerKey); - if (caloHitHandle->size() == 0) { - ATH_MSG_DEBUG("CaloHitCollection found with zero length!"); - return StatusCode::SUCCESS; - } - - // Find the output waveform container SG::WriteHandle<xAOD::WaveformHitContainer> waveformHitContainerHandle(m_waveformHitContainerKey, ctx); ATH_CHECK( waveformHitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(), @@ -55,6 +49,10 @@ PseudoCaloHitToWaveformRecAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("WaveformsHitContainer '" << waveformHitContainerHandle.name() << "' initialized"); + if (caloHitHandle->size() == 0) { + ATH_MSG_DEBUG("CaloHitCollection found with zero length!"); + return StatusCode::SUCCESS; + } // "Reconstruct" the hits CHECK( m_recoTool->reconstruct<CaloHitCollection>(caloHitHandle.ptr(), diff --git a/Waveform/WaveRecAlgs/src/PseudoScintHitToWaveformRecAlg.cxx b/Waveform/WaveRecAlgs/src/PseudoScintHitToWaveformRecAlg.cxx index 2b896e63c8a67b845072b74489ffe5a39b162751..4b8b719781f95a8881391738f076acf8e5c9204b 100644 --- a/Waveform/WaveRecAlgs/src/PseudoScintHitToWaveformRecAlg.cxx +++ b/Waveform/WaveRecAlgs/src/PseudoScintHitToWaveformRecAlg.cxx @@ -42,12 +42,6 @@ PseudoScintHitToWaveformRecAlg::execute(const EventContext& ctx) const { ATH_CHECK( scintHitHandle.isValid() ); ATH_MSG_DEBUG("Found ReadHandle for ScintHitCollection " << m_scintHitContainerKey); - if (scintHitHandle->size() == 0) { - ATH_MSG_DEBUG("ScintHitCollection found with zero length!"); - return StatusCode::SUCCESS; - } - - // Find the output waveform container SG::WriteHandle<xAOD::WaveformHitContainer> waveformHitContainerHandle(m_waveformHitContainerKey, ctx); ATH_CHECK( waveformHitContainerHandle.record( std::make_unique<xAOD::WaveformHitContainer>(), @@ -55,6 +49,10 @@ PseudoScintHitToWaveformRecAlg::execute(const EventContext& ctx) const { ATH_MSG_DEBUG("WaveformsHitContainer '" << waveformHitContainerHandle.name() << "' initialized"); + if (scintHitHandle->size() == 0) { + ATH_MSG_DEBUG("ScintHitCollection found with zero length!"); + return StatusCode::SUCCESS; + } // "Reconstruct" the hits CHECK( m_recoTool->reconstruct<ScintHitCollection>(scintHitHandle.ptr(), diff --git a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx index f1320c41e7dc75f5c9c8cd701dc06a92c3bab1c3..8f8ac480969aea1f424021e3985e695d21318783 100644 --- a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx +++ b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.cxx @@ -29,6 +29,14 @@ StatusCode RawWaveformRecAlg::finalize() { ATH_MSG_INFO(name() << "::finalize()"); + ATH_MSG_INFO( m_numberOfEvents << " events processed" ); + if ( m_numberOfEvents > 0) { + 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; } @@ -36,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()); @@ -45,35 +56,63 @@ 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 + 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)) { + m_numberOfFitErrors++; + } + } + return StatusCode::SUCCESS; } diff --git a/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h b/Waveform/WaveRecAlgs/src/RawWaveformRecAlg.h index a7120b83598b7b32476f86f1b890014452bf70f4..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 */ @@ -81,6 +85,20 @@ class RawWaveformRecAlg : public AthReentrantAlgorithm { {this, "WaveformHitContainerKey", ""}; //@} + /** + * @name Counters + * Use mutable to be updated in const methods. + * AthReentrantAlgorithm is const during event processing. + * Use std::atomic to be multi-thread safe. + */ + //@{ + 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}; + //@} + }; #endif // WAVERECALGS_RAWWAVEFORMRECALG_H diff --git a/Waveform/WaveRecAlgs/src/WaveClockRecAlg.cxx b/Waveform/WaveRecAlgs/src/WaveClockRecAlg.cxx index 36891e70dd09cf8180753711209c526da90e04e4..4dc4014234e61ffcc24a5396397518ae102ac0e3 100644 --- a/Waveform/WaveRecAlgs/src/WaveClockRecAlg.cxx +++ b/Waveform/WaveRecAlgs/src/WaveClockRecAlg.cxx @@ -24,7 +24,7 @@ WaveClockRecAlg::initialize() { StatusCode WaveClockRecAlg::finalize() { ATH_MSG_INFO(name() << "::finalize()"); - + ATH_MSG_INFO( m_numberOfEvents << " events processed" ); return StatusCode::SUCCESS; } @@ -83,6 +83,9 @@ WaveClockRecAlg::execute(const EventContext& ctx) const { // Reconstruct the hits CHECK( m_recoTool->reconstruct(*wave, clock) ); + // Keep track of how many we reconstructed + m_numberOfEvents++; + // Only do one if there happen to be more break; } diff --git a/Waveform/WaveRecAlgs/src/WaveClockRecAlg.h b/Waveform/WaveRecAlgs/src/WaveClockRecAlg.h index e6e61cfd29e219200c64bfcdb1752be0055e983a..771b0e86873b73890e110075a36d1ec4f34c2750 100644 --- a/Waveform/WaveRecAlgs/src/WaveClockRecAlg.h +++ b/Waveform/WaveRecAlgs/src/WaveClockRecAlg.h @@ -67,6 +67,16 @@ class WaveClockRecAlg : public AthReentrantAlgorithm { {this, "WaveformClockKey", "WaveformClock"}; //@} + /** + * @name Counters + * Use mutable to be updated in const methods. + * AthReentrantAlgorithm is const during event processing. + * Use std::atomic to be multi-thread safe. + */ + //@{ + mutable std::atomic<int> m_numberOfEvents{0}; + //@} + }; #endif // WAVERECALGS_WAVECLOCKRECALG_H 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 aaae0861b6fab59b7144afedb72797ad9da91f86..825cc755862200c0dd008eaf3c273cb23b37f83a 100644 --- a/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx +++ b/Waveform/WaveRecTools/src/ClockReconstructionTool.cxx @@ -79,8 +79,8 @@ ClockReconstructionTool::reconstruct(const RawWaveform& raw_wave, // Get the coefficients std::vector<double> re_full(N); std::vector<double> im_full(N); - std::vector<double> magnitude(N/2); - fftr2c->GetPointsComplex(&re_full[0],&im_full[0]); + std::vector<double> magnitude(N/2+1); // From fftw manual, output array is N/2+1 long + fftr2c->GetPointsComplex(&re_full[0], &im_full[0]); // Normalize the magnitude (just using the positive complex frequencies) unsigned int i=0; @@ -102,11 +102,11 @@ 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])); + clockdata->set_phase(atan2(im_full[imax], re_full[imax])); // Not a bug, atan2(y,x)! ATH_MSG_DEBUG("Before correcting for finite resolution:"); ATH_MSG_DEBUG(*clockdata); @@ -125,14 +125,15 @@ ClockReconstructionTool::reconstruct(const RawWaveform& raw_wave, // Improved values + // Not a bug, atan2(y,x)! double phase = atan2(im_full[imax], re_full[imax]) - dm * M_PI; - // Fix any overflows - if (phase < M_PI) phase += (2*M_PI); - if (phase > M_PI) phase -= (2*M_PI); + // Fix any overflows caused by adding dm + if (phase < -M_PI) phase += (2*M_PI); + if (phase > +M_PI) phase -= (2*M_PI); 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 7e564dae08c401bf51130dfb0813046e62cb4251..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); @@ -646,6 +680,7 @@ WaveformReconstructionTool::findRawHitValues(const std::vector<float> time, cons double sum = 0.; double sum2 = 0.; for (unsigned int i=0; i<time.size(); i++) { + //ATH_MSG_DEBUG("findRawHitValues Time: " << time[i] << " Wave: " << wave[i]); tot += wave[i]; sum += time[i] * wave[i]; sum2 += time[i] * time[i] * wave[i]; @@ -702,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 @@ -755,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 @@ -770,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 @@ -785,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..3a6224b1f70ea1909da79431f6c54383c4177984 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,41 @@ 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_windowWidth{this, "FitWindowWidth", 60}; + // Make this longer by default, from 120 to 150 ns + IntegerProperty m_windowStart{this, "FitWindowStart", -20}; + IntegerProperty m_windowWidth{this, "FitWindowWidth", 75}; // // 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 +130,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 +145,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 +153,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..57c3390c087b7f41850716d6ec24aa7d7e7044f6 --- /dev/null +++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeTimingDB.py @@ -0,0 +1,237 @@ +#!/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' +filename = 'ALLP200.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 +from CoolConvUtilities.AtlCoolLib import indirectOpen + +dbSvc = cool.DatabaseSvcFactory.databaseService() +connectString = f'sqlite://;schema={filename};dbname=CONDBR3' + +print('Opening database') + +# Try to open existing, but if not create new +try: + db = indirectOpen(connectString, readOnly=False) +except Exception as e: + print(e) + print("Couldn't open, try creating new") + #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' + +print('Opening database') + +# Try to open existing, but if not create new +try: + db = indirectOpen(connectString, readOnly=False) +except Exception as e: + print(e) + print("Couldn't open, try creating new") + #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/CMakeLists.txt b/Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1d7bbb423533ed16401f9e6913bd1f2dcc2fadf --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt @@ -0,0 +1,27 @@ +############################################################################### +# Package: WaveformConditionsTools +################################################################################ + +# Declare the package name: +atlas_subdir( WaveformConditionsTools ) + +# External dependencies: +find_package( CLHEP ) +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) + +# Component(s) in the package: +atlas_add_component ( WaveformConditionsTools + src/components/*.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel WaveformConditionsToolsLib Identifier ScintIdentifier FaserCaloIdentifier GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo ) + + +atlas_add_library( WaveformConditionsToolsLib + src/*.cxx + PUBLIC_HEADERS WaveformConditionsTools + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel Identifier ScintIdentifier FaserCaloIdentifier GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo ) + +# Install files from the package: +atlas_install_python_modules( python/*.py ) + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY new file mode 100644 index 0000000000000000000000000000000000000000..f80fa38aff6543815742cd2b6ae4a9c3742cd1ca --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY @@ -0,0 +1 @@ +Waveform/WaveformConditions/WaveformConditionsTools diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..461c087e0fb3957e90c1a1e50723e87a2baff996 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations +*/ + +/** @file IWaveformCableMappingTool.h Interface file for WaveformCableMappingTool. + */ + +// Multiple inclusion protection +#ifndef IWAVEFORMCABLEMAPPINGTOOL +#define IWAVEFORMCABLEMAPPINGTOOL + +//STL includes +#include <map> + +//Gaudi Includes +#include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" + +#include "Identifier/Identifier.h" + +// Cable map indexed by digitizer channel number +// Contains detector type "calo", "trigger", "veto", "preshower" and identifier +typedef std::map<int, std::pair<std::string, Identifier> > WaveformCableMap; + +class IWaveformCableMappingTool: virtual public IAlgTool { + + public: + + //----------Public Member Functions----------// + // Structors + virtual ~IWaveformCableMappingTool() = default; //!< Destructor + + /// Creates the InterfaceID and interfaceID() method + DeclareInterfaceID(IWaveformCableMappingTool, 1, 0); + + // Methods to return cable-mapping data + // Key is digitizer channel, pair is <type, identifier> + 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; + + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORMCABLEMAPPINGTOOL 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/WaveformCableMappingConfig.py b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..bf90fb5d37c4ece6bb7f81e497fe4f0f1e37442e --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py @@ -0,0 +1,27 @@ +""" Define methods to configure WaveformCableMapping + +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 +WaveformCableMappingTool=CompFactory.WaveformCableMappingTool + +def WaveformCableMappingToolCfg(flags, name="WaveformCableMappingTool", **kwargs): + """ Return a configured WaveformCableMappingTool""" + return WaveformCableMappingTool(name, **kwargs) + +def WaveformCableMappingCfg(flags, **kwargs): + """ Return configured ComponentAccumulator and tool for Waveform CableMapping + + WaveformCableMappingTool may be provided in kwargs + """ + + acc = ComponentAccumulator() + # tool = kwargs.get("WaveformCableMappingTool", WaveformCableMappingTool(flags)) + # Probably need to figure this out! + dbInstance = kwargs.get("dbInstance", "TDAQ_OFL") + dbFolder = kwargs.get("dbFolder", "/WAVE/DAQ/CableMapping") + acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection")) + return acc + 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..dec0c3858667fc6dee844f96f82afcf6d5427e47 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformTimingConfig.py @@ -0,0 +1,35 @@ +""" 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") + # This is now set up globally, don't need this here + #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)) + acc.merge(addFolders(flags, "/WAVE/DAQ/Timing", dbInstance, className="AthenaAttributeList")) + acc.merge(addFolders(flags, "/WAVE/DAQ/TimingOffset", dbInstance, className="CondAttrListCollection")) + return acc + diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3922d0605339fce204cff01c9dbd69d3c6f21a97 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx @@ -0,0 +1,242 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations +*/ + +/** @file WaveformCableMappingTool.cxx Implementation file for WaveformCableMappingTool. + @author Eric Torrence (05/02/22) + Based on FaserSCT_CableMappingTool +*/ + +#include "WaveformCableMappingTool.h" + +//---------------------------------------------------------------------- +WaveformCableMappingTool::WaveformCableMappingTool (const std::string& type, const std::string& name, const IInterface* parent) : + base_class(type, name, parent) +{ +} + +//---------------------------------------------------------------------- +StatusCode +WaveformCableMappingTool::initialize() { + // Read Cond Handle Key + + ATH_MSG_DEBUG("WaveformCableMappingTool::initialize()"); + + ATH_CHECK(m_readKey.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")); + + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +StatusCode +WaveformCableMappingTool::finalize() { + // Print where you are + return StatusCode::SUCCESS; +} + +//---------------------------------------------------------------------- +WaveformCableMap +WaveformCableMappingTool::getCableMapping(const EventContext& ctx) const { + // Print where you are + ATH_MSG_DEBUG("in getCableMapping()"); + WaveformCableMap 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 mapping info + /* + std::string typeParam{"type"}; + std::string stationParam{"station"}; + std::string plateParam{"plate"}; + std::string rowParam{"row"}; + std::string moduleParam{"module"}; + std::string pmtParam{"pmt"}; + */ + 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("Mapped digitizer channel " << channelNumber << " to " << det_type<< " ID: " << identifier); + + mappingData.emplace(std::make_pair(channelNumber, std::make_pair(det_type, identifier))); + + } + + } // End of loop over attributes + + + return mappingData; +} + +WaveformCableMap +WaveformCableMappingTool::getCableMapping(void) const { + const EventContext& ctx{Gaudi::Hive::currentContext()}; + 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 new file mode 100644 index 0000000000000000000000000000000000000000..8443cb1815e4db7a9c0181515b5fd405cd27d48c --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h @@ -0,0 +1,82 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations +*/ + +/** @file WaveformCableMappingTool.h Header file for WaveformCableMappingTool. + @author Eric Torrence, 05/02/22 + Based on FaserSCT_CableMappingTool +*/ + +// Multiple inclusion protection +#ifndef WAVEFORM_CABLE_MAPPING_TOOL +#define WAVEFORM_CABLE_MAPPING_TOOL + +// Include interface class +#include "AthenaBaseComps/AthAlgTool.h" +#include "WaveformConditionsTools/IWaveformCableMappingTool.h" + +// Identifiers +#include "Identifier/Identifier.h" +#include "FaserCaloIdentifier/EcalID.h" +#include "ScintIdentifier/VetoID.h" +#include "ScintIdentifier/VetoNuID.h" +#include "ScintIdentifier/TriggerID.h" +#include "ScintIdentifier/PreshowerID.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 cable mapping data and makes it available to + other algorithms. The current implementation reads the data from a COOL database. +*/ + +class WaveformCableMappingTool: public extends<AthAlgTool, IWaveformCableMappingTool> { + + public: + //----------Public Member Functions----------// + // Structors + WaveformCableMappingTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor + virtual ~WaveformCableMappingTool() = 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 detector type "calo", "trigger", "veto", "preshower" and identifier + 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"}; + + ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"}; + + // 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}; + + +}; + +//---------------------------------------------------------------------- +#endif // WAVEFORM_CABLE_MAPPING_TOOL 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 new file mode 100644 index 0000000000000000000000000000000000000000..f694fef647428802bfb98ab393e4f784180ae2b0 --- /dev/null +++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx @@ -0,0 +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 e7a3a145593c7bbda73b64a7106ffe3e43f8ff94..89ce6a07128eb2ebc367b6b68f29c9c88220e3e6 160000 --- a/faser-common +++ b/faser-common @@ -1 +1 @@ -Subproject commit e7a3a145593c7bbda73b64a7106ffe3e43f8ff94 +Subproject commit 89ce6a07128eb2ebc367b6b68f29c9c88220e3e6 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/VTI12TrackSystems/TrackHandleBase.h b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/TrackHandleBase.h index af1985583ddd4ead227901aca0586270e8b20c83..0dcde264b470b19dc82f306d4eacb3b5542f98af 100644 --- a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/TrackHandleBase.h +++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/VTI12TrackSystems/TrackHandleBase.h @@ -29,6 +29,7 @@ #include <QTreeWidgetItem> #include <vector> #include <set> +#include <optional> #include <QList> #include <QFlags> 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/VTI12TrackSystems/src/TrackPropagationHelper.cxx b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackPropagationHelper.cxx index f5545c729ec9007f9f2823ec2f5e968ceac35b17..49444e861d8ffa69c07a6b6857447cb4e93b8c9b 100644 --- a/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackPropagationHelper.cxx +++ b/graphics/VTI12/VTI12Systems/VTI12TrackSystems/src/TrackPropagationHelper.cxx @@ -303,7 +303,9 @@ bool TrackPropagationHelper::makePointsCharged( std::vector<Amg::Vector3D >& poi //get individual surfaces //TODO - optimise this! - const std::vector< const Trk::Surface * > * bsurfs = volume->volumeBounds ().decomposeToSurfaces (volume->transform ()); + const std::vector<const Trk::Surface*>* bsurfs = + const_cast<Trk::VolumeBounds&>(volume->volumeBounds()) + .decomposeToSurfaces(volume->transform()); if (bsurfs){ messageVerbose("Has this many surfaces:"+str(bsurfs->size())); 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/version.txt b/version.txt index cdbc15874e55b47fb45012cbf75daefe3196299b..140125644054770fe54c322164c33e7cd9395b79 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -22.0.40 +22.0.49 diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx index 2cd4ffcf6859a6af5341683af8333e1ba57be1ed..be0f22b1090559419c3523707359c2f2efa6c946 100644 --- a/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx +++ b/xAOD/xAODFaserWaveform/Root/WaveformHitAuxContainer_v1.cxx @@ -11,7 +11,7 @@ namespace xAOD { : AuxContainerBase() { AUX_VARIABLE(channel); - AUX_VARIABLE(id); + AUX_VARIABLE(id32); AUX_VARIABLE(localtime); AUX_VARIABLE(peak); AUX_VARIABLE(width); @@ -23,7 +23,7 @@ namespace xAOD { AUX_VARIABLE(baseline_mean); AUX_VARIABLE(baseline_rms); - AUX_VARIABLE(status); + AUX_VARIABLE(hit_status); AUX_VARIABLE(mean); AUX_VARIABLE(alpha); AUX_VARIABLE(nval); diff --git a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx index df91c67cf77ef79b749934687ee910146ee3e309..41f406612fc63f04b8a705c5177b8ba792c22625 100644 --- a/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx +++ b/xAOD/xAODFaserWaveform/Root/WaveformHit_v1.cxx @@ -15,7 +15,7 @@ namespace xAOD { AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, channel, set_channel ) - AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, id, set_id ) + AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, id32, set_id32 ) AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, localtime, set_localtime ) @@ -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 ) @@ -35,7 +37,7 @@ namespace xAOD { AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, baseline_rms, set_baseline_rms ) - AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, status, set_status ) + AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, unsigned int, hit_status, set_hit_status ) AUXSTORE_PRIMITIVE_SETTER_AND_GETTER( WaveformHit_v1, float, mean, set_mean ) diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h index c272fcd2c8d8ce8323b819ea8ca02ceeb02b45f9..86dce49eb0e329c06ec9650d31feb1a0616e1e25 100644 --- a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h +++ b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHitAuxContainer_v1.h @@ -29,7 +29,7 @@ namespace xAOD { /// @name Basic variables ///@ { std::vector<unsigned int> channel; - std::vector<unsigned int> id; + std::vector<unsigned int> id32; std::vector<float> localtime; std::vector<float> peak; std::vector<float> width; @@ -42,7 +42,7 @@ namespace xAOD { std::vector<float> baseline_mean; std::vector<float> baseline_rms; - std::vector<unsigned int> status; + std::vector<unsigned int> hit_status; std::vector<float> mean; std::vector<float> alpha; diff --git a/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h b/xAOD/xAODFaserWaveform/xAODFaserWaveform/versions/WaveformHit_v1.h index 9ea7b6dc573d53a533df44d02ff3edbf92c8a9ce..4f15e8152fa7ea2d00ae6eed970d9341ffc6fba4 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 - unsigned int id() const; - void set_id(unsigned int value); + /// From Identifier::get_identifier32()::get_compact() + unsigned int id32() const; + void set_id32(unsigned int value); + /// Interface for proper identifier Identifier identify() const { - return Identifier(this->id()); + return Identifier(this->id32()); } + void set_identifier(const Identifier& id) { + set_id32(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); @@ -88,8 +99,8 @@ namespace xAOD { void set_baseline_rms(float value); /// Status word - unsigned int status() const; - void set_status(unsigned int value); + unsigned int hit_status() const; + void set_hit_status(unsigned int value); /// Other fit results float mean() const; @@ -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); @@ -111,10 +122,10 @@ namespace xAOD { /// Status bit access functions void set_status_bit(WaveformStatus bit) { - this->set_status(this->status() | (1<<bit)); + this->set_hit_status(this->hit_status() | (1<<bit)); } bool status_bit(WaveformStatus bit) const { - return (this->status() & (1<<bit)); + return (this->hit_status() & (1<<bit)); } bool threshold() const {