From abd03700cbe3d8d2b25d07427765864a60c22de1 Mon Sep 17 00:00:00 2001 From: Veronica Verkest Date: Thu, 11 Aug 2022 17:31:41 -0400 Subject: [PATCH 001/468] implement Dave's jet pt ordering changes --- simulation/g4simulation/g4jets/Jet.h | 11 +++++++++ simulation/g4simulation/g4jets/JetMap.h | 7 ++++++ simulation/g4simulation/g4jets/JetMapv1.cc | 28 ++++++++++++++++++++++ simulation/g4simulation/g4jets/JetMapv1.h | 2 ++ 4 files changed, 48 insertions(+) diff --git a/simulation/g4simulation/g4jets/Jet.h b/simulation/g4simulation/g4jets/Jet.h index 0bbc063452..ed29f98413 100644 --- a/simulation/g4simulation/g4jets/Jet.h +++ b/simulation/g4simulation/g4jets/Jet.h @@ -50,6 +50,17 @@ class Jet : public PHObject EEMC_CLUSTER = 24, }; + + enum SORT // used as criteria for sorting output in JetMap + { + NO_SORT = 0, // a blank input to not sort input + PT = 1, // PT descending order + E = 2, // E descending order + P = 3, // P descending order + MASS = 4, // Mass descending order + AREA = 5, // AREA descending order --> maybe used in future, as jets don't have area for now... + }; + enum PROPERTY { diff --git a/simulation/g4simulation/g4jets/JetMap.h b/simulation/g4simulation/g4jets/JetMap.h index 8384779fbd..9607f14b46 100644 --- a/simulation/g4simulation/g4jets/JetMap.h +++ b/simulation/g4simulation/g4jets/JetMap.h @@ -9,6 +9,7 @@ #include // for size_t #include #include +#include #include class JetMap : public PHObject @@ -19,6 +20,8 @@ class JetMap : public PHObject typedef typ_JetMap::const_iterator ConstIter; typedef typ_JetMap::iterator Iter; + typedef std::vector vec_JetMap; // to be used when sorting typ_JetMap to iterate over + // source identifier iterators typedef std::set::const_iterator ConstSrcIter; typedef std::set::iterator SrcIter; @@ -51,6 +54,7 @@ class JetMap : public PHObject virtual SrcIter find_src(Jet::SRC src); virtual SrcIter end_src(); + // map access to jets -------------------------------------------------------- virtual bool empty() const { return true; } @@ -64,6 +68,7 @@ class JetMap : public PHObject virtual Jet* insert(Jet* /*jet*/) { return nullptr; } virtual size_t erase(unsigned int /*idkey*/) { return 0; } + virtual ConstIter begin() const; virtual ConstIter find(unsigned int idkey) const; virtual ConstIter end() const; @@ -72,6 +77,8 @@ class JetMap : public PHObject virtual Iter find(unsigned int idkey); virtual Iter end(); + virtual std::vector vec(Jet::SORT=Jet::SORT::PT)=0; + private: ClassDefOverride(JetMap, 1); }; diff --git a/simulation/g4simulation/g4jets/JetMapv1.cc b/simulation/g4simulation/g4jets/JetMapv1.cc index 93e9b46090..a277bf0536 100644 --- a/simulation/g4simulation/g4jets/JetMapv1.cc +++ b/simulation/g4simulation/g4jets/JetMapv1.cc @@ -9,6 +9,7 @@ #include // for reverse_iterator #include // for operator<<, endl, ostream, basic_ostream::operat... #include // for pair, make_pair +#include using namespace std; @@ -129,3 +130,30 @@ Jet* JetMapv1::insert(Jet* jet) _map[index]->set_id(index); return (_map[index]); } + +std::vector JetMapv1::vec(Jet::SORT sort_criteria) { + vector v_data; + for (auto& _ : _map) { v_data.push_back(_.second); } + switch (sort_criteria) + { + case Jet::SORT::PT: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_pt() > b->get_pt(); }); + break; + case Jet::SORT::E: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_e() > b->get_e(); }); + break; + case Jet::SORT::P: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_p() > b->get_p(); }); + break; + case Jet::SORT::MASS: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_mass() > b->get_mass(); }); + break; + case Jet::SORT::NO_SORT: + // do nothing + break; + default: + std::cout << "Fatal error: option to JetMap::vec( option ) was not recognized." << std::endl; + exit(1); + } + return v_data; +} diff --git a/simulation/g4simulation/g4jets/JetMapv1.h b/simulation/g4simulation/g4jets/JetMapv1.h index c128933639..995fb877e8 100644 --- a/simulation/g4simulation/g4jets/JetMapv1.h +++ b/simulation/g4simulation/g4jets/JetMapv1.h @@ -67,6 +67,8 @@ class JetMapv1 : public JetMap Iter find(unsigned int idkey) override { return _map.find(idkey); } Iter end() override { return _map.end(); } + std::vector vec(Jet::SORT sort=Jet::SORT::PT) override; // defaulted to PT in JetMap.h + private: Jet::ALGO _algo; //< algorithm used to reconstruct jets float _par; //< algorithm parameter setting (e.g. radius) From f6edcfcc2fae981d8715fc677e854fc812797b02 Mon Sep 17 00:00:00 2001 From: VVerkest Date: Wed, 14 Sep 2022 20:20:32 -0400 Subject: [PATCH 002/468] fix these deleted files --- simulation/g4simulation/g4jets/JetMap.h | 88 ++++++++++++ simulation/g4simulation/g4jets/JetMapv1.cc | 159 +++++++++++++++++++++ simulation/g4simulation/g4jets/JetMapv1.h | 51 +++++++ 3 files changed, 298 insertions(+) create mode 100644 simulation/g4simulation/g4jets/JetMap.h create mode 100644 simulation/g4simulation/g4jets/JetMapv1.cc create mode 100644 simulation/g4simulation/g4jets/JetMapv1.h diff --git a/simulation/g4simulation/g4jets/JetMap.h b/simulation/g4simulation/g4jets/JetMap.h new file mode 100644 index 0000000000..0f39863667 --- /dev/null +++ b/simulation/g4simulation/g4jets/JetMap.h @@ -0,0 +1,88 @@ +#ifndef G4JET_JETMAP_H +#define G4JET_JETMAP_H + +#include "Jet.h" + +#include + +#include +#include // for size_t +#include +#include +#include +#include +#include + +class JetMap : public PHObject +{ + public: + // jet object iterators + typedef std::map typ_JetMap; + typedef typ_JetMap::const_iterator ConstIter; + typedef typ_JetMap::iterator Iter; + + typedef std::vector vec_JetMap; // to be used when sorting typ_JetMap to iterate over + + // source identifier iterators + typedef std::set::const_iterator ConstSrcIter; + typedef std::set::iterator SrcIter; + + JetMap() {} + ~JetMap() override {} + + void identify(std::ostream& os = std::cout) const override; + int isValid() const override { return 0; } + PHObject* CloneMe() const override { return nullptr; } + + // map content info ---------------------------------------------------------- + + virtual void set_algo(Jet::ALGO /*algo*/) { return; } + virtual Jet::ALGO get_algo() const { return Jet::NONE; } + + virtual void set_par(float) { return; } + virtual float get_par() const { return NAN; } + + // set access to list of source identifiers ---------------------------------- + + virtual bool empty_src() const { return true; } + virtual void insert_src(Jet::SRC /*src*/) { return; } + + virtual ConstSrcIter begin_src() const; + virtual ConstSrcIter find_src(Jet::SRC src) const; + virtual ConstSrcIter end_src() const; + + virtual SrcIter begin_src(); + virtual SrcIter find_src(Jet::SRC src); + virtual SrcIter end_src(); + + + // map access to jets -------------------------------------------------------- + + virtual bool empty() const { return true; } + virtual size_t size() const { return 0; } + virtual size_t count(unsigned int /*idkey*/) const { return 0; } + virtual void clear() { return; } + + virtual const Jet* get(unsigned int /*idkey*/) const { return nullptr; } + virtual Jet* get(unsigned int /*idkey*/) { return nullptr; } + + virtual Jet* insert(Jet* /*jet*/) { return nullptr; } + virtual size_t erase(unsigned int /*idkey*/) { return 0; } + + + virtual ConstIter begin() const; + virtual ConstIter find(unsigned int idkey) const; + virtual ConstIter end() const; + + virtual Iter begin(); + virtual Iter find(unsigned int idkey); + virtual Iter end(); + + virtual std::vector vec(Jet::SORT=Jet::SORT::PT)=0; + virtual std::vector vec(std::function custom_sort)=0; + + private: + ClassDefOverride(JetMap, 1); +}; + +#endif diff --git a/simulation/g4simulation/g4jets/JetMapv1.cc b/simulation/g4simulation/g4jets/JetMapv1.cc new file mode 100644 index 0000000000..a6e75768fa --- /dev/null +++ b/simulation/g4simulation/g4jets/JetMapv1.cc @@ -0,0 +1,159 @@ +#include "JetMapv1.h" + +#include "Jet.h" + +#include // for PHObject + +#include +#include +#include +#include // for reverse_iterator +#include // for operator<<, endl, ostream, basic_ostream::operat... +#include // for pair, make_pair +#include + +JetMapv1::JetMapv1(const JetMap* jets) + : _algo(jets->get_algo()) + , _par(jets->get_par()) +{ + for (ConstSrcIter iter = jets->begin_src(); + iter != jets->end_src(); + ++iter) + { + _src.insert(*iter); + } + + for (auto iter : *jets) + { + Jet* jet = dynamic_cast((iter.second)->CloneMe()); + assert(jet); + _map.insert(std::make_pair(jet->get_id(), jet)); + } +} + +JetMapv1& JetMapv1::operator=(const JetMapv1& jets) +{ + Reset(); + + _algo = jets.get_algo(); + _par = jets.get_par(); + + for (ConstSrcIter iter = jets.begin_src(); + iter != jets.end_src(); + ++iter) + { + _src.insert(*iter); + } + + for (auto iter : jets) + { + Jet* jet = dynamic_cast((iter.second)->CloneMe()); + assert(jet); + _map.insert(std::make_pair(jet->get_id(), jet)); + } + + return *this; +} + +JetMapv1::~JetMapv1() +{ + JetMapv1::Reset(); +} + +void JetMapv1::Reset() +{ + _algo = Jet::NONE; + _par = NAN; + _src.clear(); + + while (_map.begin() != _map.end()) + { + delete _map.begin()->second; + _map.erase(_map.begin()); + } +} + +PHObject* JetMapv1::CloneMe() const +{ + JetMap* map = new JetMapv1(*this); + return map; +} + +void JetMapv1::identify(std::ostream& os) const +{ + os << "JetMapv1: size = " << _map.size() << std::endl; + os << " par = " << _par << std::endl; + os << " source = "; + for (ConstSrcIter i = begin_src(); i != end_src(); ++i) + { + os << (*i) << ","; + } + os << std::endl; + + return; +} + +const Jet* JetMapv1::get(unsigned int id) const +{ + ConstIter iter = _map.find(id); + if (iter == _map.end()) return nullptr; + return iter->second; +} + +Jet* JetMapv1::get(unsigned int id) +{ + Iter iter = _map.find(id); + if (iter == _map.end()) return nullptr; + return iter->second; +} + +Jet* JetMapv1::insert(Jet* jet) +{ + unsigned int index = 0; + if (!_map.empty()) index = _map.rbegin()->first + 1; + _map.insert(std::make_pair(index, jet)); + _map[index]->set_id(index); + return (_map[index]); +} + +std::vector JetMapv1::vec(Jet::SORT sort_criteria) +{ + std::vector v_data; + for (auto& _ : _map) + { + v_data.push_back(_.second); + } + switch (sort_criteria) + { + case Jet::SORT::PT: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_pt() > b->get_pt(); }); + break; + case Jet::SORT::E: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_e() > b->get_e(); }); + break; + case Jet::SORT::P: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_p() > b->get_p(); }); + break; + case Jet::SORT::MASS: + std::sort(v_data.begin(), v_data.end(), [](Jet* a, Jet* b) { return a->get_mass() > b->get_mass(); }); + break; + case Jet::SORT::NO_SORT: + // do nothing + break; + default: + std::cout << "Fatal error: option to JetMap::vec( option ) was not recognized." << std::endl; + exit(1); + } + return v_data; +} + +std::vector JetMapv1::vec(std::function custom_sort) +{ + std::vector v_data; + for (auto& _ : _map) + { + v_data.push_back(_.second); + } + std::sort(v_data.begin(), v_data.end(), custom_sort); + return v_data; +} diff --git a/simulation/g4simulation/g4jets/JetMapv1.h b/simulation/g4simulation/g4jets/JetMapv1.h new file mode 100644 index 0000000000..8eae27f359 --- /dev/null +++ b/simulation/g4simulation/g4jets/JetMapv1.h @@ -0,0 +1,51 @@ +#ifndef G4JET_JETMAP_H +#define G4JET_JETMAP_H + +#include "Jet.h" + +#include + +#include +#include // for size_t +#include +#include +#include +#include +#include + +class JetMap : public PHObject +{ + public: + // jet object iterators + typedef std::map typ_JetMap; + typedef typ_JetMap::const_iterator ConstIter; + typedef typ_JetMap::iterator Iter; + + typedef std::vector vec_JetMap; // to be used when sorting typ_JetMap to iterate over + + // source identifier iterators + typedef std::set::const_iterator ConstSrcIter; + typedef std::set::iterator SrcIter; + + JetMap() {} + ~JetMap() override {} + + void identify(std::ostream& os = std::cout) const override; + int isValid() const override { return 0; } + PHObject* CloneMe() const override { return nullptr; } + + // map content info ---------------------------------------------------------- + + virtual void set_algo(Jet::ALGO /*algo*/) { return; } + virtual Jet::ALGO get_algo() const { return Jet::NONE; } + + virtual void set_par(float) { return; } + virtual float get_par() const { return NAN; } + + // set access to list of source identifiers ---------------------------------- + + virtual bool empty_src() const { return true; } + virtual void insert_src(Jet::SRC /*src*/) { return; } + + virtual ConstSrcIter begin_src() const; + From 62d2eef38a77eee072ad1ab27f7104819c30cb91 Mon Sep 17 00:00:00 2001 From: Veronica Verkest Date: Wed, 14 Sep 2022 20:39:36 -0400 Subject: [PATCH 003/468] Update JetMapv1.h --- simulation/g4simulation/g4jets/JetMapv1.h | 93 +++++++++++++++-------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/simulation/g4simulation/g4jets/JetMapv1.h b/simulation/g4simulation/g4jets/JetMapv1.h index 8eae27f359..9ea10d34b3 100644 --- a/simulation/g4simulation/g4jets/JetMapv1.h +++ b/simulation/g4simulation/g4jets/JetMapv1.h @@ -1,51 +1,82 @@ -#ifndef G4JET_JETMAP_H -#define G4JET_JETMAP_H +#ifndef G4JET_JETMAPV1_H +#define G4JET_JETMAPV1_H -#include "Jet.h" +#include "JetMap.h" -#include +#include "Jet.h" -#include #include // for size_t #include -#include -#include -#include #include -class JetMap : public PHObject +class PHObject; + +class JetMapv1 : public JetMap { public: - // jet object iterators - typedef std::map typ_JetMap; - typedef typ_JetMap::const_iterator ConstIter; - typedef typ_JetMap::iterator Iter; + JetMapv1() {} + JetMapv1(const JetMap* jets); + JetMapv1& operator=(const JetMapv1& jets); + ~JetMapv1() override; - typedef std::vector vec_JetMap; // to be used when sorting typ_JetMap to iterate over + void identify(std::ostream& os = std::cout) const override; + void Reset() override; + int isValid() const override { return 1; } + PHObject* CloneMe() const override; - // source identifier iterators - typedef std::set::const_iterator ConstSrcIter; - typedef std::set::iterator SrcIter; + // map content info ---------------------------------------------------------- - JetMap() {} - ~JetMap() override {} + void set_algo(Jet::ALGO algo) override { _algo = algo; } + Jet::ALGO get_algo() const override { return _algo; } - void identify(std::ostream& os = std::cout) const override; - int isValid() const override { return 0; } - PHObject* CloneMe() const override { return nullptr; } + void set_par(float par) override { _par = par; } + float get_par() const override { return _par; } - // map content info ---------------------------------------------------------- + // set access to source identifiers ------------------------------------------ + + bool empty_src() const override { return _src.empty(); } + void insert_src(Jet::SRC src) override { _src.insert(src); } + + ConstSrcIter begin_src() const override { return _src.begin(); } + ConstSrcIter find_src(Jet::SRC src) const override { return _src.find(src); } + ConstSrcIter end_src() const override { return _src.end(); } + + SrcIter begin_src() override { return _src.begin(); } + SrcIter find_src(Jet::SRC src) override { return _src.find(src); } + SrcIter end_src() override { return _src.end(); } + + // map access to jets -------------------------------------------------------- + + bool empty() const override { return _map.empty(); } + size_t size() const override { return _map.size(); } + size_t count(unsigned int idkey) const override { return _map.count(idkey); } + void clear() override { Reset(); } + + const Jet* get(unsigned int idkey) const override; + Jet* get(unsigned int idkey) override; + + /// insert Jet to the map. Once inserted, the JetMap owns the Jet memory + Jet* insert(Jet* jet) override; + size_t erase(unsigned int idkey) override { return _map.erase(idkey); } - virtual void set_algo(Jet::ALGO /*algo*/) { return; } - virtual Jet::ALGO get_algo() const { return Jet::NONE; } + ConstIter begin() const override { return _map.begin(); } + ConstIter find(unsigned int idkey) const override { return _map.find(idkey); } + ConstIter end() const override { return _map.end(); } - virtual void set_par(float) { return; } - virtual float get_par() const { return NAN; } + Iter begin() override { return _map.begin(); } + Iter find(unsigned int idkey) override { return _map.find(idkey); } + Iter end() override { return _map.end(); } - // set access to list of source identifiers ---------------------------------- + std::vector vec(Jet::SORT sort=Jet::SORT::PT) override; // defaulted to PT in JetMap.h + std::vector vec(std::function custom_sort) override; // defaulted to PT in JetMap.h - virtual bool empty_src() const { return true; } - virtual void insert_src(Jet::SRC /*src*/) { return; } + private: + Jet::ALGO _algo = Jet::NONE; //< algorithm used to reconstruct jets + float _par = NAN; //< algorithm parameter setting (e.g. radius) + std::set _src; //< list of sources (clusters, towers, etc) + typ_JetMap _map; //< jet algorithm output storage - virtual ConstSrcIter begin_src() const; + ClassDefOverride(JetMapv1, 1); +}; +#endif From 3de3ffec1d0f821160b4fd7c6f7010f5412f3fe5 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 28 Dec 2022 14:00:23 -0500 Subject: [PATCH 004/468] The latest the greatest --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 8 ++++++++ simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index d58bcea917..6ded96e5c8 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -170,6 +170,11 @@ int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, return 0; } +double PHG4TpcPadPlaneReadout::GetGainWeight(double x,double y, int side){ + // This function get weights for gain uniformity in the TPC readout + int binXY = h_Gain[side]->FindBin(x,y); + return h_Gain[side]->GetBinContent(binXY); +} double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() { @@ -182,6 +187,7 @@ double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() // for the single electron gain distribution - // and yes, the parameter you're looking for is of course the slope, which is the inverse gain. double nelec = gsl_ran_exponential(RandomGenerator, averageGEMGain); + //Put gain reading here return nelec; } @@ -275,6 +281,8 @@ TpcClusterBuilder PHG4TpcPadPlaneReadout::MapToPadPlane( //=============================== double nelec = getSingleEGEMAmplification(); + nelec = nelec * GetGainWeight(x_gem,y_gem, side); + pass_data.neff_electrons = nelec; // Distribute the charge between the pads in phi diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index 57b54fa77d..247e38c0b3 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -104,6 +104,9 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array< std::array< std::vector, NRSectors >, NSides > sector_min_Phi_sectors; std::array< std::array< std::vector, NRSectors >, NSides > sector_max_Phi_sectors; + // Return gain weight + double GetGainWeight(double x,double y, int side) + // return random distribution of number of electrons after amplification of GEM for each initial ionizing electron double getSingleEGEMAmplification(); gsl_rng *RandomGenerator; From f79c4cd30369b1b056199b1222d1aeb6005b1330 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 28 Dec 2022 15:15:43 -0500 Subject: [PATCH 005/468] The latest the greatest --- .../g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 12 ++++++------ .../g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 6ded96e5c8..445c7fe654 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -170,11 +170,11 @@ int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, return 0; } -double PHG4TpcPadPlaneReadout::GetGainWeight(double x,double y, int side){ - // This function get weights for gain uniformity in the TPC readout - int binXY = h_Gain[side]->FindBin(x,y); - return h_Gain[side]->GetBinContent(binXY); -} +//double PHG4TpcPadPlaneReadout::GetGainWeight(double x,double y, int side){ +// // This function get weights for gain uniformity in the TPC readout +// int binXY = h_Gain[side]->FindBin(x,y); +// return h_Gain[side]->GetBinContent(binXY); +//} double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() { @@ -281,7 +281,7 @@ TpcClusterBuilder PHG4TpcPadPlaneReadout::MapToPadPlane( //=============================== double nelec = getSingleEGEMAmplification(); - nelec = nelec * GetGainWeight(x_gem,y_gem, side); + //nelec = nelec * GetGainWeight(x_gem,y_gem, side); pass_data.neff_electrons = nelec; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index 247e38c0b3..11a7916685 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -105,7 +105,7 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array< std::array< std::vector, NRSectors >, NSides > sector_max_Phi_sectors; // Return gain weight - double GetGainWeight(double x,double y, int side) + //double GetGainWeight(double x,double y, int side) // return random distribution of number of electrons after amplification of GEM for each initial ionizing electron double getSingleEGEMAmplification(); From 1c227ddffe1b6ca5523f3f475ee4c6456cf575de Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 18 Jan 2023 11:31:31 -0500 Subject: [PATCH 006/468] latest changes --- .../tpc/fillSpaceChargeMaps/Makefile.am | 1 + .../fillSpaceChargeMaps.cc | 21 ++++++++++++++----- .../fillSpaceChargeMaps/fillSpaceChargeMaps.h | 7 +++++++ .../macros/run_files_300evts_AA_MDC2.sh | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/calibrations/tpc/fillSpaceChargeMaps/Makefile.am b/calibrations/tpc/fillSpaceChargeMaps/Makefile.am index 1d25e8cc1b..5590f57386 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/Makefile.am +++ b/calibrations/tpc/fillSpaceChargeMaps/Makefile.am @@ -26,6 +26,7 @@ libfillSpaceChargeMaps_la_LIBADD = \ -lphg4hit \ -lg4detectors \ -lg4testbench \ + -lg4tpc \ -lSubsysReco BUILT_SOURCES = testexternals.cc diff --git a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc index c208f52a01..09aee4578d 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc +++ b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc @@ -10,6 +10,10 @@ #include // for SubsysReco #include +#include + +#include +#include #include // for TAxis #include @@ -92,18 +96,20 @@ int fillSpaceChargeMaps::Init(PHCompositeNode * /*topNode*/) z_bins[z] = -z_rdo + z_rdo / nz * z; } - _h_R = new TH1F("_h_R", "_h_R;R, [m]", r_bins_N+2, r_bins_edges); + _h_R = new TH1F("_h_R", "_h_R;R, [mm]", r_bins_N+2, r_bins_edges); _h_hits = new TH1F("_h_hits", "_h_hits;N, [hit]", 1000, 0, 1e6); _h_DC_E = new TH2F("_h_DC_E", "_h_DC_E;SC;E#times10^{6}", 2000, -100, 2e5 - 100, 1000, -50, 1e3 - 50); + _h_SC_XY = new TH2F("_h_SC_XY" ,"_h_SC_XY;X, [mm];Y, [mm];ADC;" ,4*159,-1*78*cm,78*cm,4*159,-1*78*cm,78*cm); + char name[100]; char name_ax[100]; for (int iz = 0; iz < 30; iz++) { sprintf(name, "_h_SC_ibf_%d", iz); - sprintf(name_ax, "_h_SC_ibf_%d;#phi, [rad];R, [m];Z, [m]", iz); + sprintf(name_ax, "_h_SC_ibf_%d;#phi, [rad];R, [mm];Z, [mm]", iz); _h_SC_ibf[iz] = new TH3F(name, name_ax, nphi, phi_bins, r_bins_N, r_bins, 2 * nz, z_bins); sprintf(name, "_h_SC_prim_%d", iz); - sprintf(name_ax, "_h_SC_prim_%d;#phi, [rad];R, [m];Z, [m]", iz); + sprintf(name_ax, "_h_SC_prim_%d;#phi, [rad];R, [mm];Z, [mm]", iz); _h_SC_prim[iz] = new TH3F(name, name_ax, nphi, phi_bins, r_bins_N, r_bins, 2 * nz, z_bins); hm->registerHisto(_h_SC_prim[iz]); @@ -112,7 +118,7 @@ int fillSpaceChargeMaps::Init(PHCompositeNode * /*topNode*/) hm->registerHisto(_h_hits); hm->registerHisto(_h_R); hm->registerHisto(_h_DC_E); - + hm->registerHisto(_h_SC_XY); //_event_timestamp = 0; _hit_eion = 0; _hit_r = 0; @@ -134,6 +140,8 @@ int fillSpaceChargeMaps::Init(PHCompositeNode * /*topNode*/) _rawHits->Branch("event_timestamp", &_event_timestamp); _rawHits->Branch("event_bunchXing", &_event_bunchXing); } + padplane = new PHG4TpcPadPlaneReadout; + seggeo = new PHG4TpcCylinderGeomContainer(); return 0; } @@ -192,7 +200,7 @@ int fillSpaceChargeMaps::InitRun(PHCompositeNode * /*topNode*/) _mbRate = _freqKhz * kHz; _xingRate = 9.383 * MHz; _mean = mbRate / xingRate; - + padplane->CreateReadoutGeometry( PHCompositeNode *, seggeo); return 0; } @@ -407,11 +415,13 @@ int fillSpaceChargeMaps::process_event(PHCompositeNode *topNode) _ibf_vol = N_electrons * w_gain_tmp * _ampGain * w_ibf_tmp * _ampIBFfrac; _h_SC_ibf[iz]->Fill(_hit_phi, _hit_r, z_ibf[iz], _ibf_vol); + if(iz==0)_h_SC_XY->Fill(_hit_r * cos(_hit_phi),_hit_r * sin(_hit_phi));//,_ibf_vol); } else { _h_SC_ibf[iz]->Fill(new_phi, new_r, z_ibf[iz], _ibf_vol); + if(iz==0)_h_SC_XY->Fill(new_r * cos(new_phi),new_r * sin(new_phi));//,_ibf_vol); } } } @@ -447,6 +457,7 @@ int fillSpaceChargeMaps::End(PHCompositeNode * /*topNode*/) _h_SC_ibf[iz]->Sumw2(false); } + _h_SC_XY->Sumw2(false); _h_hits->Sumw2(false); _h_DC_E->Sumw2(false); _h_R->Sumw2(false); diff --git a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h index 93d4f55acd..4783bf9018 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h +++ b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h @@ -5,6 +5,9 @@ #include +#include +#include + #include #include #include @@ -102,9 +105,13 @@ class fillSpaceChargeMaps : public SubsysReco TH1 *_h_hits = nullptr; TH1 *_h_R = nullptr; TH2 *_h_DC_E = nullptr; + TH2 *_h_SC_XY = nullptr; static const int nFrames = 30; TH3 *_h_SC_prim[nFrames] = {nullptr}; TH3 *_h_SC_ibf[nFrames] = {nullptr}; + + PHG4TpcPadPlaneReadout *padplane = nullptr; + PHG4TpcCylinderGeomContainer *seggeo = nullptr; float f = 0.5; //for now, just pick the middle of the hit. Do better later. float ns = 1e-9, s = 1.0; // us=1e-6,ms=1e-3, diff --git a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh index 1413fe0460..39eb54951b 100755 --- a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh +++ b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh @@ -12,7 +12,7 @@ do A=$( printf '%05d' $Xstart ) #B=$( printf '%06d' $Xend ) #fname="G4Hits_sHijing_0_20fm-0000000002-"$A".root" ; - fname="G4Hits_sHijing_0_20fm-0000000040-"$A".root" ; + fname="G4Hits_sHijing_0_20fm-0000000062-"$A".root" ; foutputname="./Files/mdc2_ADCBins_UseFieldMaps_hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A".root" ; #foutputname="./Files/mdc2_ADCBins_NoFieldMaps_hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A".root" ; echo $fname ; From b4ee841a415ed6ce26e99f7bd58494139fc1653b Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 8 Mar 2023 10:18:14 -0500 Subject: [PATCH 007/468] Modified TpcCMClusterizer to add boolean to remove one sector of clusters. Also modified CMMatcher to identify gaps in phi from histograms and apply global rotation to correct for any global distortion. --- .../PHTpcCentralMembraneClusterizer.cc | 2 + .../PHTpcCentralMembraneClusterizer.h | 4 +- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 185 +++++++++++++++++- .../tpccalib/PHTpcCentralMembraneMatcher.h | 15 ++ 4 files changed, 204 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index 1aa2351963..e740be7591 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -121,6 +121,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(cluster->getAdc() < _min_adc_value) continue; if( std::abs(z) < _min_z_value) continue; + + if(removeSector && TpcDefs::getSide(cluskey) > 0 && TpcDefs::getSectorId(cluskey) == 1) continue; ++m_accepted_clusters; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h index b78e9b5b87..e962a4f0b7 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h @@ -45,6 +45,8 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco void set_min_z_value(const double val) {_min_z_value = val;} void set_stripe_dr_values(const double dr1, const double dr2, const double dr3){ _cmclus_dr_inner = dr1; _cmclus_dr_mid = dr2; _cmclus_dr_outer = dr3;} + void set_removeSector(bool a_removeSector){ removeSector = a_removeSector; } + //! run initialization int InitRun(PHCompositeNode *topNode); @@ -99,7 +101,7 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco double _cmclus_dr_mid = 0.95; //cm double _cmclus_dr_outer = 1.025; //cm - + bool removeSector = false; }; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 639980862a..65a3867da0 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -139,6 +139,81 @@ void PHTpcCentralMembraneMatcher::set_grid_dimensions( int phibins, int rbins ) m_rbins = rbins; } +std::vector> PHTpcCentralMembraneMatcher::getPhiGaps( TH2F *r_phi ){ + + std::cout << "r_phi entries: " << r_phi->GetEntries() << std::endl; + + int bin0 = r_phi->GetYaxis()->FindBin(0.0); + int bin40 = r_phi->GetYaxis()->FindBin(40.0); + int bin58 = r_phi->GetYaxis()->FindBin(58.0); + int bin100 = r_phi->GetYaxis()->FindBin(99.99); + + std::cout << "bin0: " << bin0 << " bin40: " << bin40 << " bin58: " << bin58 << " bin100: " << bin100 << std::endl; + + TH1D *phiHist[3]; + phiHist[0] = r_phi->ProjectionX("phiHist_R1",bin0,bin40); + std::cout << "R1 entries " << phiHist[0]->GetEntries() << std::endl; + phiHist[1] = r_phi->ProjectionX("phiHist_R2",bin40,bin58); + std::cout << "R2 entries " << phiHist[1]->GetEntries() << std::endl; + phiHist[2] = r_phi->ProjectionX("phiHist_R3",bin58,bin100); + std::cout << "R3 entries " << phiHist[2]->GetEntries() << std::endl; + + std::vector> phiGaps; + + for(int R=0; R<3; R++){ + std::vector phiGaps_R; + for(int i=2; i<=phiHist[R]->GetNbinsX(); i++){ + if(phiHist[R]->GetBinContent(i) > 0 && phiHist[R]->GetBinContent(i-1) == 0){ + if(phiGaps_R.size() == 0) phiGaps_R.push_back(phiHist[R]->GetBinCenter(i)); + else if(phiHist[R]->GetBinCenter(i) - phiGaps_R[phiGaps_R.size()-1] > (M_PI/36.)) phiGaps_R.push_back(phiHist[R]->GetBinCenter(i)); + } + } + + phiGaps.push_back(phiGaps_R); + } + + return phiGaps; + +} + +std::vector PHTpcCentralMembraneMatcher::getAverageRotation(std::vector> hit, std::vector> clust){ + + std::vector avgAngle; + + for(int R=0; R<3; R++){ + + double di = 0.0; + double dj = 0.0; + + for(int i=0; i<(int)hit[R].size() - 1; i++){ + di += hit[R][i+1] - hit[R][i]; + } + di = di/(hit[R].size()-1); + + for(int j=0; j<(int)clust[R].size() - 1; j++){ + dj += clust[R][j+1] - clust[R][j]; + } + dj = dj/(clust[R].size()-1); + + double sum = 0.0; + int nMatch = 0; + for(int i=0; i<(int)hit[R].size(); i++){ + for(int j=0; j<(int)clust[R].size(); j++){ + if(fabs(clust[R][j] - hit[R][i]) > (di+dj)/4.0) continue; + if(j!=0 && clust[R][j] - clust[R][j] > 1.5*M_PI/9.0) continue; + sum += clust[R][j] - hit[R][i]; + nMatch++; + } + } + + avgAngle.push_back(sum/nMatch); + + } + + return avgAngle; + +} + //____________________________________________________________________________.. int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) { @@ -176,6 +251,16 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) hdrphi = new TH1F("hdrphi","r * dphi", 200, -0.05, 0.05); hnclus = new TH1F("hnclus", " nclusters ", 3, 0., 3.); } + + fout2.reset( new TFile(m_outputfile2.c_str(),"RECREATE") ); + + hit_r_phi = new TH2F("hit_r_phi","hit r vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + hit_r_phi_pos = new TH2F("hit_r_phi_pos","hit R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + hit_r_phi_neg = new TH2F("hit_r_phi_neg","hit R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + + clust_r_phi = new TH2F("clust_r_phi","clust R vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); // Get truth cluster positions //===================== @@ -192,9 +277,15 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) { source.SetZ( +1 ); m_truth_pos.push_back( source ); + + hit_r_phi->Fill(source.Phi(), source.Perp()); + hit_r_phi_pos->Fill(source.Phi(), source.Perp()); source.SetZ( -1 ); m_truth_pos.push_back( source ); + + hit_r_phi->Fill(source.Phi(), source.Perp()); + hit_r_phi_neg->Fill(source.Phi(), source.Perp()); }; // inner region extended is the 8 layers inside 30 cm @@ -272,6 +363,10 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) // reset output distortion correction container histograms for( const auto& harray:{m_dcc_out->m_hDRint, m_dcc_out->m_hDPint, m_dcc_out->m_hDZint, m_dcc_out->m_hentries} ) { for( const auto& h:harray ) { h->Reset(); } } + + clust_r_phi->Reset(); + clust_r_phi_pos->Reset(); + clust_r_phi_neg->Reset(); // read the reconstructed CM clusters auto clusrange = m_corrected_CMcluster_map->getClusters(); @@ -290,6 +385,10 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) reco_pos.push_back(tmp_pos); reco_nclusters.push_back(nclus); + clust_r_phi->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + if(tmp_pos.Z() > 0) clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + else if(tmp_pos.Z() < 0) clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + if(Verbosity()) { double raw_rad = sqrt( cmclus->getX()*cmclus->getX() + cmclus->getY()*cmclus->getY() ); @@ -303,6 +402,65 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) hxy_reco->Fill(tmp_pos.X(), tmp_pos.Y()); } } + + std::cout << "hit_r_phi entries: " << hit_r_phi->GetEntries() << std::endl; + std::vector> hit_phiGaps = getPhiGaps(hit_r_phi); + for(int R=0; R<3; R++){ + std::cout << Form("hit R%d gap size: ",R+1) << hit_phiGaps[R].size() << std::endl; + for(int i=0; i<(int)hit_phiGaps[R].size(); i++){ + std::cout << Form("hit R%d gap ",R+1) << i << ": " << hit_phiGaps[R][i] << std::endl; + } + } + std::cout << "clust_r_phi entries: " << clust_r_phi->GetEntries() << std::endl; + std::vector> clust_phiGaps = getPhiGaps(clust_r_phi); + for(int R=0; R<3; R++){ + std::cout << Form("clust R%d gap size: ",R+1) << clust_phiGaps[R].size() << std::endl; + for(int i=0; i<(int)clust_phiGaps[R].size(); i++){ + std::cout << Form("clust R%d gap ",R+1) << i << ": " << clust_phiGaps[R][i] << std::endl; + } + } + std::vector angleDiff = getAverageRotation(hit_phiGaps, clust_phiGaps); + + + std::cout << "hit_r_phi_pos entries: " << hit_r_phi_pos->GetEntries() << std::endl; + std::vector> hit_phiGaps_pos = getPhiGaps(hit_r_phi_pos); + for(int R=0; R<3; R++){ + std::cout << Form("pos hit R%d gap size: ",R+1) << hit_phiGaps_pos[R].size() << std::endl; + for(int i=0; i<(int)hit_phiGaps_pos[R].size(); i++){ + std::cout << Form("pos hit R%d gap ",R+1) << i << ": " << hit_phiGaps_pos[R][i] << std::endl; + } + } + std::cout << "clust_r_phi_pos entries: " << clust_r_phi_pos->GetEntries() << std::endl; + std::vector> clust_phiGaps_pos = getPhiGaps(clust_r_phi_pos); + for(int R=0; R<3; R++){ + std::cout << Form("pos clust R%d gap size: ",R+1) << clust_phiGaps_pos[R].size() << std::endl; + for(int i=0; i<(int)clust_phiGaps_pos[R].size(); i++){ + std::cout << Form("pos clust R%d gap ",R+1) << i << ": " << clust_phiGaps_pos[R][i] << std::endl; + } + } + std::vector angleDiff_pos = getAverageRotation(hit_phiGaps_pos, clust_phiGaps_pos); + + std::cout << "hit_r_phi_neg entries: " << hit_r_phi_neg->GetEntries() << std::endl; + std::vector> hit_phiGaps_neg = getPhiGaps(hit_r_phi_neg); + for(int R=0; R<3; R++){ + std::cout << Form("neg hit R%d gap size: ",R+1) << hit_phiGaps_neg[R].size() << std::endl; + for(int i=0; i<(int)hit_phiGaps_neg[R].size(); i++){ + std::cout << Form("neg hit R%d gap ",R+1) << i << ": " << hit_phiGaps_neg[R][i] << std::endl; + } + } + std::cout << "clust_r_phi_neg entries: " << clust_r_phi_neg->GetEntries() << std::endl; + std::vector> clust_phiGaps_neg = getPhiGaps(clust_r_phi_neg); + for(int R=0; R<3; R++){ + std::cout << Form("neg clust R%d gap size: ",R+1) << clust_phiGaps_neg[R].size() << std::endl; + for(int i=0; i<(int)clust_phiGaps_neg[R].size(); i++){ + std::cout << Form("neg clust R%d gap ",R+1) << i << ": " << clust_phiGaps_neg[R][i] << std::endl; + } + } + std::vector angleDiff_neg = getAverageRotation(hit_phiGaps_neg, clust_phiGaps_neg); + + for(int R=0; R<3; R++){ + std::cout << "angle diff: " << angleDiff[R] << " pos: " << angleDiff_pos[R] << " neg: " << angleDiff_neg[R] << std::endl; + } // Match reco and truth positions //std::map matched_pair; @@ -320,6 +478,18 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) for(unsigned int j = 0; j < reco_pos.size(); ++j) { + int angleR = -1; + + if(reco_pos[j].Perp() < 40) angleR = 0; + else if(reco_pos[j].Perp() >= 40 && reco_pos[j].Perp() <58) angleR = 1; + if(reco_pos[j].Perp() >= 58) angleR = 2; + + + if(angleR != -1) reco_pos[j].RotateZ(-1.0*angleDiff[angleR]); + const double phi2_rot = reco_pos[j].Phi(); + if(angleR != -1) reco_pos[j].RotateZ(angleDiff[angleR]); + + const auto& nclus = reco_nclusters[j]; const double z2 = reco_pos[j].Z(); const double rad2=get_r(reco_pos[j].X(), reco_pos[j].Y()); @@ -333,7 +503,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) const bool accepted_r = std::abs(dr) < m_rad_cut; const auto dphi = delta_phi(phi1-phi2); - const bool accepted_phi = std::abs(dphi) < m_phi_cut; + const auto dphi_rot = delta_phi(phi1-phi2_rot); + const bool accepted_phi = std::abs(dphi_rot) < m_phi_cut; if(m_savehistograms) { @@ -502,6 +673,18 @@ int PHTpcCentralMembraneMatcher::End(PHCompositeNode * /*topNode*/ ) } } + fout2->cd(); + + hit_r_phi->Write(); + hit_r_phi_pos->Write(); + hit_r_phi_neg->Write(); + + clust_r_phi->Write(); + clust_r_phi_pos->Write(); + clust_r_phi_neg->Write(); + + fout2->Close(); + // write evaluation histograms if(m_savehistograms && fout) { diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 6f3bdd000a..6ac1a5381a 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -110,6 +110,17 @@ class PHTpcCentralMembraneMatcher : public SubsysReco std::unique_ptr fout; + TH2F *hit_r_phi; + TH2F *hit_r_phi_pos; + TH2F *hit_r_phi_neg; + + TH2F *clust_r_phi; + TH2F *clust_r_phi_pos; + TH2F *clust_r_phi_neg; + + std::string m_outputfile2 = "CM_r_phi_maps.root"; + std::unique_ptr fout2; + //@} /// radius cut for matching clusters to pad, for size 2 clusters @@ -208,6 +219,10 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@} + std::vector> getPhiGaps(TH2F *r_phi); + + std::vector getAverageRotation(std::vector> hit, std::vector> clust); + }; #endif // PHTPCCENTRALMEMBRANEMATCHER_H From f1b075414467f8a1afd481b0230439918d45b4cd Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 10 Mar 2023 10:25:53 -0500 Subject: [PATCH 008/468] Added toggles to PHG4TpcCentralMembrane to turn on/off certain modules (used for testing distortion mapping). Radial distortion matching improved and uses gap between middle and outer to identify global radial shifts --- .../PHTpcCentralMembraneClusterizer.cc | 6 +- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 322 ++++++++++++------ .../tpccalib/PHTpcCentralMembraneMatcher.h | 7 +- .../g4tpc/PHG4TpcCentralMembrane.cc | 5 + .../g4tpc/PHG4TpcCentralMembrane.h | 10 + .../g4tpc/PHG4TpcElectronDrift.cc | 44 ++- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 108 ++++++ 7 files changed, 399 insertions(+), 103 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index e740be7591..1af516bffd 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -122,7 +122,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(cluster->getAdc() < _min_adc_value) continue; if( std::abs(z) < _min_z_value) continue; - if(removeSector && TpcDefs::getSide(cluskey) > 0 && TpcDefs::getSectorId(cluskey) == 1) continue; + // if(removeSector && TpcDefs::getSide(cluskey) > 0 && TpcDefs::getSectorId(cluskey) == 1 && TrkrDefs::getLayer(cluskey) < 38) continue; + if(removeSector && TpcDefs::getSide(cluskey) > 0 && TrkrDefs::getLayer(cluskey) < 38) continue; ++m_accepted_clusters; @@ -183,6 +184,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) // must match clusters that are on the same side if( side[i] != side[j] ) continue; + //must match clusters that are close to each other in Z + if(std::abs(pos[i].Z() - pos[j].Z()) > 0.5) continue; + const float newphidist=std::abs(pos[i].DeltaPhi(pos[j])); if (newphidist> PHTpcCentralMembraneMatcher::getPhiGaps( TH2F *r_phi ){ +/* +std::vector PHTpcCentralMembraneMatcher::getRGaps( TH2F *r_phi ){ - std::cout << "r_phi entries: " << r_phi->GetEntries() << std::endl; + TH1D *proj = r_phi->ProjectionY("R_proj",1,360); + + std::vector pass1; + + for(int i=2; iGetNbinsX(); i++){ + if(proj->GetBinContent(i) > 0.15*proj->GetMaximum() && proj->GetBinContent(i) >= proj->GetBinContent(i-1) && proj->GetBinContent(i) >= proj->GetBinContent(i+1)) pass1.push_back(proj->GetBinCenter(i)); + } + for(int i=0; i<(int)pass1.size()-1; i++){ + if(pass1[i+1]-pass1[i] > 0.75) continue; + + if(proj->GetBinContent(proj->FindBin(pass1[i])) > proj->GetBinContent(proj->FindBin(pass1[i+1]))) pass1.erase(std::next(pass1.begin(), i+1)); + else pass1.erase(std::next(pass1.begin(), i)); + + i--; + } + + return pass1; + +} +*/ + +std::vector> PHTpcCentralMembraneMatcher::getPhiGaps( TH2F *r_phi ){ + int bin0 = r_phi->GetYaxis()->FindBin(0.0); int bin40 = r_phi->GetYaxis()->FindBin(40.0); int bin58 = r_phi->GetYaxis()->FindBin(58.0); int bin100 = r_phi->GetYaxis()->FindBin(99.99); - std::cout << "bin0: " << bin0 << " bin40: " << bin40 << " bin58: " << bin58 << " bin100: " << bin100 << std::endl; - TH1D *phiHist[3]; phiHist[0] = r_phi->ProjectionX("phiHist_R1",bin0,bin40); - std::cout << "R1 entries " << phiHist[0]->GetEntries() << std::endl; phiHist[1] = r_phi->ProjectionX("phiHist_R2",bin40,bin58); - std::cout << "R2 entries " << phiHist[1]->GetEntries() << std::endl; phiHist[2] = r_phi->ProjectionX("phiHist_R3",bin58,bin100); - std::cout << "R3 entries " << phiHist[2]->GetEntries() << std::endl; std::vector> phiGaps; @@ -214,13 +232,74 @@ std::vector PHTpcCentralMembraneMatcher::getAverageRotation(std::vector< } +std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ + + TH1D *proj = r_phi->ProjectionY("R_proj",1,360); + + std::vector rPeaks; + + for(int i=2; iGetNbinsX(); i++){ + if(proj->GetBinContent(i) > 0.15*proj->GetMaximum() && proj->GetBinContent(i) >= proj->GetBinContent(i-1) && proj->GetBinContent(i) >= proj->GetBinContent(i+1)) rPeaks.push_back(proj->GetBinCenter(i)); + } + + for(int i=0; i<(int)rPeaks.size()-1; i++){ + if(rPeaks[i+1]-rPeaks[i] > 0.75) continue; + if(proj->GetBinContent(proj->FindBin(rPeaks[i])) > proj->GetBinContent(proj->FindBin(rPeaks[i+1]))) rPeaks.erase(std::next(rPeaks.begin(), i+1)); + else rPeaks.erase(std::next(rPeaks.begin(), i)); + i--; + } + return rPeaks; +} + +int PHTpcCentralMembraneMatcher::getClusterRMatch( std::vector hitMatches, std::vector clusterPeaks, double clusterR){ + + int closest_clusterR = -1; + + for(int i=0; i<(int)hitMatches.size(); i++){ + + double lowGap = 0.0; + double highGap = 0.0; + + if(hitMatches[i] <= 14){ + lowGap = 0.565985; + highGap = 0.565985; + }else if(hitMatches[i] == 15){ + lowGap = 0.565985; + highGap = 1.2409686; + }else if(hitMatches[i] == 16){ + lowGap = 1.2409686; + highGap = 1.020695; + }else if(hitMatches[i] >= 17 && hitMatches[i] <= 22){ + lowGap = 1.020695; + highGap = 1.020695; + }else if(hitMatches[i] == 23){ + lowGap = 1.020695; + highGap = 1.5001502; + }else if(hitMatches[i] == 24){ + lowGap = 1.5001502; + highGap = 1.09705; + }else if(hitMatches[i] >= 25){ + lowGap = 1.09705; + highGap = 1.09705; + } + + if( clusterR > (clusterPeaks[i] - lowGap) && clusterR <= (clusterPeaks[i] + highGap) ){ + closest_clusterR = hitMatches[i]; + break; + } + } + + return closest_clusterR; + +} + //____________________________________________________________________________.. int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) { if( m_savehistograms ) { - static constexpr float max_dr = 1.0; + static constexpr float max_dr = 5.0; static constexpr float max_dphi = 0.05; fout.reset( new TFile(m_histogramfilename.c_str(),"RECREATE") ); @@ -402,81 +481,99 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) hxy_reco->Fill(tmp_pos.X(), tmp_pos.Y()); } } + - std::cout << "hit_r_phi entries: " << hit_r_phi->GetEntries() << std::endl; std::vector> hit_phiGaps = getPhiGaps(hit_r_phi); - for(int R=0; R<3; R++){ - std::cout << Form("hit R%d gap size: ",R+1) << hit_phiGaps[R].size() << std::endl; - for(int i=0; i<(int)hit_phiGaps[R].size(); i++){ - std::cout << Form("hit R%d gap ",R+1) << i << ": " << hit_phiGaps[R][i] << std::endl; - } - } - std::cout << "clust_r_phi entries: " << clust_r_phi->GetEntries() << std::endl; std::vector> clust_phiGaps = getPhiGaps(clust_r_phi); - for(int R=0; R<3; R++){ - std::cout << Form("clust R%d gap size: ",R+1) << clust_phiGaps[R].size() << std::endl; - for(int i=0; i<(int)clust_phiGaps[R].size(); i++){ - std::cout << Form("clust R%d gap ",R+1) << i << ": " << clust_phiGaps[R][i] << std::endl; - } - } std::vector angleDiff = getAverageRotation(hit_phiGaps, clust_phiGaps); - std::cout << "hit_r_phi_pos entries: " << hit_r_phi_pos->GetEntries() << std::endl; std::vector> hit_phiGaps_pos = getPhiGaps(hit_r_phi_pos); - for(int R=0; R<3; R++){ - std::cout << Form("pos hit R%d gap size: ",R+1) << hit_phiGaps_pos[R].size() << std::endl; - for(int i=0; i<(int)hit_phiGaps_pos[R].size(); i++){ - std::cout << Form("pos hit R%d gap ",R+1) << i << ": " << hit_phiGaps_pos[R][i] << std::endl; - } - } - std::cout << "clust_r_phi_pos entries: " << clust_r_phi_pos->GetEntries() << std::endl; std::vector> clust_phiGaps_pos = getPhiGaps(clust_r_phi_pos); - for(int R=0; R<3; R++){ - std::cout << Form("pos clust R%d gap size: ",R+1) << clust_phiGaps_pos[R].size() << std::endl; - for(int i=0; i<(int)clust_phiGaps_pos[R].size(); i++){ - std::cout << Form("pos clust R%d gap ",R+1) << i << ": " << clust_phiGaps_pos[R][i] << std::endl; - } - } std::vector angleDiff_pos = getAverageRotation(hit_phiGaps_pos, clust_phiGaps_pos); - std::cout << "hit_r_phi_neg entries: " << hit_r_phi_neg->GetEntries() << std::endl; std::vector> hit_phiGaps_neg = getPhiGaps(hit_r_phi_neg); - for(int R=0; R<3; R++){ - std::cout << Form("neg hit R%d gap size: ",R+1) << hit_phiGaps_neg[R].size() << std::endl; - for(int i=0; i<(int)hit_phiGaps_neg[R].size(); i++){ - std::cout << Form("neg hit R%d gap ",R+1) << i << ": " << hit_phiGaps_neg[R][i] << std::endl; - } - } - std::cout << "clust_r_phi_neg entries: " << clust_r_phi_neg->GetEntries() << std::endl; std::vector> clust_phiGaps_neg = getPhiGaps(clust_r_phi_neg); - for(int R=0; R<3; R++){ - std::cout << Form("neg clust R%d gap size: ",R+1) << clust_phiGaps_neg[R].size() << std::endl; - for(int i=0; i<(int)clust_phiGaps_neg[R].size(); i++){ - std::cout << Form("neg clust R%d gap ",R+1) << i << ": " << clust_phiGaps_neg[R][i] << std::endl; - } - } std::vector angleDiff_neg = getAverageRotation(hit_phiGaps_neg, clust_phiGaps_neg); - for(int R=0; R<3; R++){ - std::cout << "angle diff: " << angleDiff[R] << " pos: " << angleDiff_pos[R] << " neg: " << angleDiff_neg[R] << std::endl; + std::cout << "rotation R1: " << angleDiff[0] << " R2: " << angleDiff[1] << " R3: " << angleDiff[2] << std::endl; + std::cout << "pos rotation R1: " << angleDiff_pos[0] << " R2: " << angleDiff_pos[1] << " R3: " << angleDiff_pos[2] << std::endl; + std::cout << "neg rotation R1: " << angleDiff_neg[0] << " R2: " << angleDiff_neg[1] << " R3: " << angleDiff_neg[2] << std::endl; + + std::vector hit_RPeaks = getRPeaks(hit_r_phi); + std::vector clust_RPeaks_pos = getRPeaks(clust_r_phi_pos); + std::vector clust_RPeaks_neg = getRPeaks(clust_r_phi_neg); + + std::vector clust_RGaps_pos; + int R23Gap_pos = -1; + for(int i=0; i<(int)clust_RPeaks_pos.size()-1; i++){ + clust_RGaps_pos.push_back(clust_RPeaks_pos[i+1] - clust_RPeaks_pos[i]); + if(clust_RGaps_pos[i] >= 2.5) R23Gap_pos = i; + } + std::cout << "R23Gap_pos: " << R23Gap_pos << std::endl; + + std::vector clust_RGaps_neg; + int R23Gap_neg = -1; + for(int i=0; i<(int)clust_RPeaks_neg.size()-1; i++){ + clust_RGaps_neg.push_back(clust_RPeaks_neg[i+1] - clust_RPeaks_neg[i]); + if(clust_RGaps_neg[i] >= 2.5) R23Gap_neg = i; + } + std::cout << "R23Gap_neg: " << R23Gap_neg << std::endl; + + std::cout << "hit matches pos = {"; + std::vector hitMatches_pos; + for(int i=0; i<(int)clust_RPeaks_pos.size(); i++){ + hitMatches_pos.push_back(i + 23 - R23Gap_pos); + if(i<(int)clust_RPeaks_pos.size()-1) std::cout << " " << i + 23 - R23Gap_pos << ","; + else std::cout << " " << i + 23 - R23Gap_pos << "}" << std::endl; + } + + std::cout << "hit matches neg = {"; + std::vector hitMatches_neg; + for(int i=0; i<(int)clust_RPeaks_neg.size(); i++){ + hitMatches_neg.push_back(i + 23 - R23Gap_neg); + if(i<(int)clust_RPeaks_neg.size()-1) std::cout << " " << i + 23 - R23Gap_neg << ","; + else std::cout << " " << i + 23 - R23Gap_neg << "}" << std::endl; } + // Match reco and truth positions //std::map matched_pair; std::vector> matched_pair; std::vector matched_nclus; - + + std::vector hits_matched(m_truth_pos.size()); + std::vector clusts_matched(reco_pos.size()); + + for(int matchIt=0; matchIt<2; matchIt++){ // loop over truth positions for(unsigned int i=0; i 0) clustRMatchIndex = getClusterRMatch(hitMatches_pos, clust_RPeaks_pos, rad2); + else clustRMatchIndex = getClusterRMatch(hitMatches_neg, clust_RPeaks_neg, rad2); + + + if(clustRMatchIndex == -1) continue; + + //const double phi2 = reco_pos[j].Phi(); // only match pairs that are on the same side of the TPC const bool accepted_z = ((z1>0)==(z2>0)); if( !accepted_z ) continue; - - const auto dr = rad1-rad2; - const bool accepted_r = std::abs(dr) < m_rad_cut; + - const auto dphi = delta_phi(phi1-phi2); + + const bool accepted_r = (hitRadIndex == clustRMatchIndex); + + // const auto dphi = delta_phi(phi1-phi2); const auto dphi_rot = delta_phi(phi1-phi2_rot); const bool accepted_phi = std::abs(dphi_rot) < m_phi_cut; + + if(!accepted_r || !accepted_phi) continue; - if(m_savehistograms) - { - - hnclus->Fill( (float) nclus); - - double r = rad2; - - if( accepted_r ) - { - hdrphi->Fill(r * dphi); - hdphi->Fill(dphi); - hrdphi->Fill(r,dphi); - } + // std::cout << "matching cluster " << j << " rad: " << rad2 << " clustRMatchIndex: " << clustRMatchIndex << " hitRadIndex: " << hitRadIndex << " hitMatchedR: " << (clustRMatchIndex != -1 ? hit_RPeaks[clustRMatchIndex] : -1) << std::endl; - if( accepted_r && accepted_phi) - { hdrdphi->Fill(dr, dphi); } - if( accepted_phi ) - { - hrdr->Fill(r,dr); - if(nclus==1) - { - if(r < 40.0) hdr1_single->Fill(dr); - if(r >= 40.0 && r < 58.0) hdr2_single->Fill(dr); - if(r >= 58.0) hdr3_single->Fill(dr); - } - else - { - if(r < 40.0) hdr1_double->Fill(dr); - if(r >= 40.0 && r < 58.0) hdr2_double->Fill(dr); - if(r >= 58.0) hdr3_double->Fill(dr); - } - } - } - - if( accepted_r && accepted_phi ) - { - matched_pair.emplace_back(i,j); - matched_nclus.push_back(nclus); - break; + if(fabs(dphi_rot)Fill( (float) nclus); + + double r = rad2; + + //if( accepted_r ) + // { + hdrphi->Fill(r * dphi); + hdphi->Fill(dphi); + hrdphi->Fill(r,dphi); + // } + + // if( accepted_r && accepted_phi) + hdrdphi->Fill(dr, dphi); + + // if( accepted_phi ) + // { + hrdr->Fill(r,dr); + if(nclus==1) + { + if(r < 40.0) hdr1_single->Fill(dr); + if(r >= 40.0 && r < 58.0) hdr2_single->Fill(dr); + if(r >= 58.0) hdr3_single->Fill(dr); + } + else + { + if(r < 40.0) hdr1_double->Fill(dr); + if(r >= 40.0 && r < 58.0) hdr2_double->Fill(dr); + if(r >= 58.0) hdr3_double->Fill(dr); + } + // } + }//end save histos + }//end if match was found + }//end loop over truth pos + }//end loop over matching iterations // print some statistics: if( Verbosity() ) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 6ac1a5381a..d987b3a70e 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -134,13 +134,13 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@{ /// distortion correction grid size along phi - int m_phibins = 36; + int m_phibins = 40; static constexpr float m_phiMin = 0; static constexpr float m_phiMax = 2.*M_PI; /// distortion correction grid size along r - int m_rbins = 16; + int m_rbins = 26; static constexpr float m_rMin = 20; // cm static constexpr float m_rMax = 78; // cm @@ -223,6 +223,9 @@ class PHTpcCentralMembraneMatcher : public SubsysReco std::vector getAverageRotation(std::vector> hit, std::vector> clust); + std::vector getRPeaks(TH2F *r_phi); + + int getClusterRMatch( std::vector hitMatches, std::vector clusterPeaks, double clusterR); }; #endif // PHTPCCENTRALMEMBRANEMATCHER_H diff --git a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc index 55e8491f0a..9d88cae1d4 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc @@ -126,24 +126,28 @@ int PHG4TpcCentralMembrane::InitRun(PHCompositeNode* /* topNode */) // loop over stripeID for (int k = 0; k < nGoodStripes_R1_e[j]; k++) { + if(skip_R1_e) continue; adjust_hits(GetPHG4HitFromStripe(i, 0, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R1[j]; k++) { + if(skip_R1) continue; adjust_hits(GetPHG4HitFromStripe(i, 1, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R2[j]; k++) { + if(skip_R2) continue; adjust_hits(GetPHG4HitFromStripe(i, 2, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R3[j]; k++) { + if(skip_R3) continue; adjust_hits(GetPHG4HitFromStripe(i, 3, j, k, electrons_per_stripe)); } } @@ -167,6 +171,7 @@ int PHG4TpcCentralMembrane::process_event(PHCompositeNode* topNode) // load g4hit container auto g4hitcontainer = findNode::getClass(topNode, hitnodename.c_str()); + std::cout << PHWHERE << "hitnodename: " << hitnodename.c_str() << std::endl; if (!g4hitcontainer) { std::cout << PHWHERE << "Could not locate g4 hit node " << hitnodename << std::endl; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h index f8532284cb..3ac1e7fe0a 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h @@ -52,6 +52,11 @@ class PHG4TpcCentralMembrane : public SubsysReco, public PHParameterInterface /// set modulo for events in which to generate CM hits void setCentralMembraneEventModulo(int mod) { m_eventModulo = mod; }; + void setSkipR1_e( bool a_skip ) { skip_R1_e = a_skip; }; + void setSkipR1( bool a_skip ) { skip_R1 = a_skip; }; + void setSkipR2( bool a_skip ) { skip_R2 = a_skip; }; + void setSkipR3( bool a_skip ) { skip_R3 = a_skip; }; + private: /// detector name std::string detector = "TPC"; @@ -63,6 +68,11 @@ class PHG4TpcCentralMembrane : public SubsysReco, public PHParameterInterface int m_eventModulo = 10; int m_eventNum = 0; + bool skip_R1_e = false; + bool skip_R1 = false; + bool skip_R2 = false; + bool skip_R3 = false; + static constexpr double mm = 1.0; static constexpr double cm = 10.0; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 1526e7f73e..eee6eae301 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -80,6 +80,10 @@ namespace } } // namespace +genElecs::genElecs(){} + +g4HitClass::g4HitClass(){} + PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) : SubsysReco(name) , PHParameterInterface(name) @@ -319,7 +323,12 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } std::cout << std::endl; } - + + m_outfile = new TFile("/sphenix/user/bkimelman/gen1_CM_on_Feb8_v2/PHG4TpcElectronDrift_Ben.root","RECREATE"); + m_g4Hits = new g4HitClass(); + m_hitTree = new TTree("m_hitTree",""); + m_hitTree->Branch("g4Hits",&m_g4Hits); + return Fun4AllReturnCodes::EVENT_OK; } @@ -451,6 +460,18 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) pow(hiter->second->get_y(1), 2)) << std::endl; } + m_g4Hits->set_g4xStart(hiter->second->get_x(0)); + m_g4Hits->set_g4yStart(hiter->second->get_y(0)); + m_g4Hits->set_g4zStart(hiter->second->get_z(0)); + m_g4Hits->set_g4tStart(hiter->second->get_t(0)); + + m_g4Hits->set_g4xEnd(hiter->second->get_x(1)); + m_g4Hits->set_g4yEnd(hiter->second->get_y(1)); + m_g4Hits->set_g4zEnd(hiter->second->get_z(1)); + m_g4Hits->set_g4yEnd(hiter->second->get_t(1)); + + m_g4Hits->set_g4E(eion); + for (unsigned int i = 0; i < n_electrons; i++) { // We choose the electron starting position at random from a flat @@ -464,6 +485,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) const double z_start = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); const double t_start = hiter->second->get_t(0) + f * (hiter->second->get_t(1) - hiter->second->get_t(0)); + genElecs *tmp_elec = new genElecs(); + + tmp_elec->set_xStart(x_start); + tmp_elec->set_yStart(y_start); + tmp_elec->set_zStart(z_start); + tmp_elec->set_tStart(t_start); + unsigned int side = 0; if (z_start > 0) side = 1; @@ -539,6 +567,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } } + tmp_elec->set_xEnd(x_final); + tmp_elec->set_yEnd(y_final); + tmp_elec->set_zEnd(z_final); + tmp_elec->set_tEnd(t_final); + + m_g4Hits->addElectron(tmp_elec); + // remove electrons outside of our acceptance. Careful though, electrons from just inside 30 cm can contribute in the 1st active layer readout, so leave a little margin if (rad_final < min_active_radius - 2.0 || rad_final > max_active_radius + 1.0) { continue; } @@ -675,6 +710,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) single_hitsetcontainer->Reset(); + m_hitTree->Fill(); + m_g4Hits->reset_g4_electrons(); + } // end loop over g4hits truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ true); @@ -771,6 +809,10 @@ int PHG4TpcElectronDrift::End(PHCompositeNode * /*topNode*/) z_startmap->Write(); EDrift_outf->Close(); } + + m_outfile->cd(); + m_hitTree->Write(); + m_outfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index d1aff1f2aa..22a03dfbe4 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -13,6 +13,9 @@ #include +#include +#include + #include #include #include @@ -35,6 +38,104 @@ class DistortedTrackContainer; class TpcClusterBuilder; class PHG4TpcCylinderGeomContainer; +class genElecs{ + public: + genElecs(); + ~genElecs(); + + void set_xStart(double a_x){ m_xStart = a_x; }; + void set_yStart(double a_y){ m_yStart = a_y; }; + void set_zStart(double a_z){ m_zStart = a_z; }; + void set_tStart(double a_t){ m_yStart = a_t; }; + + void set_xEnd(double a_x){ m_xEnd = a_x; }; + void set_yEnd(double a_y){ m_yEnd = a_y; }; + void set_zEnd(double a_z){ m_zEnd = a_z; }; + void set_tEnd(double a_t){ m_tEnd = a_t; }; + + double get_xStart(){ return m_xStart; }; + double get_yStart(){ return m_yStart; }; + double get_zStart(){ return m_zStart; }; + double get_tStart(){ return m_tStart; }; + + double get_xEnd(){ return m_xEnd; }; + double get_yEnd(){ return m_yEnd; }; + double get_zEnd(){ return m_zEnd; }; + double get_tEnd(){ return m_tEnd; }; + + //void resetElec(){ m_xStart=0.0; m_yStart=0.0; m_zStart=0.0; m_tStart=0.0; m_xEnd=0.0; m_yEnd=0.0; m_zEnd=0.0; m_tEnd=0.0; }; + + private: + double m_xStart; + double m_yStart; + double m_zStart; + double m_tStart; + + double m_xEnd; + double m_yEnd; + double m_zEnd; + double m_tEnd; + +}; + +class g4HitClass{ + public: + g4HitClass(); + ~g4HitClass(); + + void set_g4xStart(double a_x){ m_g4xStart = a_x; }; + void set_g4yStart(double a_y){ m_g4yStart = a_y; }; + void set_g4zStart(double a_z){ m_g4zStart = a_z; }; + void set_g4tStart(double a_t){ m_g4tStart = a_t; }; + + void set_g4xEnd(double a_x){ m_g4xEnd = a_x; }; + void set_g4yEnd(double a_y){ m_g4yEnd = a_y; }; + void set_g4zEnd(double a_z){ m_g4zEnd = a_z; }; + void set_g4tEnd(double a_t){ m_g4tEnd = a_t; }; + + void set_g4E(double a_E){ m_g4E = a_E; }; + + void addElectron(genElecs *a_elec){ m_elecs.push_back(a_elec); }; + + double get_g4xStart(){ return m_g4xStart; }; + double get_g4yStart(){ return m_g4yStart; }; + double get_g4zStart(){ return m_g4zStart; }; + double get_g4tStart(){ return m_g4tStart; }; + + double get_g4xEnd(){ return m_g4xEnd; }; + double get_g4yEnd(){ return m_g4yEnd; }; + double get_g4zEnd(){ return m_g4zEnd; }; + double get_g4tEnd(){ return m_g4tEnd; }; + + double get_g4E(){ return m_g4E; }; + int get_nElec(){ return (int)m_elecs.size(); }; + + genElecs* getElectron(int elecIndex){ return m_elecs[elecIndex]; }; + + void reset_g4_electrons(){ m_elecs.clear(); }; + + //void reset_g4Hits(){ m_g4x=0.0; m_g4y=0.0; m_g4z=0.0; m_g4t=0.0; m_g4E=0.0; m_elecs.clear(); }; + + + private: + + double m_g4xStart; + double m_g4yStart; + double m_g4zStart; + double m_g4tStart; + + double m_g4xEnd; + double m_g4yEnd; + double m_g4zEnd; + double m_g4tEnd; + + double m_g4E; + + std::vector m_elecs; + +}; + + class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface { public: @@ -68,6 +169,7 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface //! setup readout plane void registerPadPlane(PHG4TpcPadPlane *padplane); + private: //! map a given x,y,z coordinates to plane hits /* TpcClusterBuilder MapToPadPlane(const double x, const double y, const */ @@ -133,6 +235,11 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface double max_time = NAN; + TFile *m_outfile; + TTree *m_hitTree; + g4HitClass *m_g4Hits; + + /* std::array layer_clusterers; // Generate TrkrClusterv4's for TrkrTruthTracks */ TpcClusterBuilder* truth_clusterer { nullptr }; @@ -148,4 +255,5 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface std::unique_ptr RandomGenerator; }; + #endif // G4TPC_PHG4TPCELECTRONDRIFT_H From 30791af74a05b425c582f97de5313a0c0c7fa004 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 12 Mar 2023 03:23:34 -0400 Subject: [PATCH 009/468] Introduce TrkrHitSetTpc --- offline/packages/trackbase/Makefile.am | 4 + offline/packages/trackbase/TpcDefs.h | 5 + offline/packages/trackbase/TrkrHitSetTpcv1.cc | 145 ++++++++++++++++++ offline/packages/trackbase/TrkrHitSetTpcv1.h | 108 +++++++++++++ .../trackbase/TrkrHitSetTpcv1LinkDef.h | 5 + 5 files changed, 267 insertions(+) create mode 100644 offline/packages/trackbase/TrkrHitSetTpcv1.cc create mode 100644 offline/packages/trackbase/TrkrHitSetTpcv1.h create mode 100644 offline/packages/trackbase/TrkrHitSetTpcv1LinkDef.h diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 7942d9dfd3..62842a5021 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -76,6 +76,7 @@ pkginclude_HEADERS = \ TrkrHitSetContainer.h \ TrkrHitSetContainerv1.h \ TrkrHitSetv1.h \ + TrkrHitSetTpcv1.h \ TrkrHitTruthAssoc.h \ TrkrHitTruthAssocv1.h \ TrkrHitv1.h \ @@ -123,6 +124,7 @@ ROOTDICTS = \ TrkrHitSetContainerv1_Dict.cc \ TrkrHitSet_Dict.cc \ TrkrHitSetv1_Dict.cc \ + TrkrHitSetTpcv1_Dict.cc \ TrkrHitTruthAssoc_Dict.cc \ TrkrHitTruthAssocv1_Dict.cc \ TrkrHit_Dict.cc \ @@ -173,6 +175,7 @@ nobase_dist_pcm_DATA = \ TrkrHitSetContainerv1_Dict_rdict.pcm \ TrkrHitSet_Dict_rdict.pcm \ TrkrHitSetv1_Dict_rdict.pcm \ + TrkrHitSetTpcv1_Dict_rdict.pcm \ TrkrHitTruthAssoc_Dict_rdict.pcm \ TrkrHitTruthAssocv1_Dict_rdict.pcm \ TrkrHit_Dict_rdict.pcm \ @@ -227,6 +230,7 @@ libtrack_io_la_SOURCES = \ TrkrHitSetContainer.cc \ TrkrHitSetContainerv1.cc \ TrkrHitSetv1.cc \ + TrkrHitSetTpcv1.cc \ TrkrHitTruthAssocv1.cc \ TrkrHitv1.cc \ TrkrHitv2.cc \ diff --git a/offline/packages/trackbase/TpcDefs.h b/offline/packages/trackbase/TpcDefs.h index 9766753370..927bb174a2 100644 --- a/offline/packages/trackbase/TpcDefs.h +++ b/offline/packages/trackbase/TpcDefs.h @@ -38,6 +38,10 @@ static const unsigned int kBitShiftTBin __attribute__((unused)) = 0; static const uint16_t MAXPAD __attribute__((unused)) = 1024; static const uint16_t MAXTBIN __attribute__((unused)) = 512; +// in memory representation of TPC ADC data: 10bit ADC value as 16bit signed integer. +// This is signed to allow pedestal subtraction when needed +typedef int16_t ADCDataType; + /** * @brief Get the sector id from hitsetkey * @param[in] hitsetkey @@ -110,6 +114,7 @@ TrkrDefs::hitsetkey genHitSetKey(const uint8_t lyr, const uint8_t sector, const */ TrkrDefs::cluskey genClusKey(const uint8_t lyr, const uint8_t sector, const uint8_t side, const uint32_t clusid); + } // namespace TpcDefs #endif //TPC_TPCDEFS_H diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc new file mode 100644 index 0000000000..58dc448238 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -0,0 +1,145 @@ +/** + * @file trackbase/TrkrHitSetTpcv1.cc + * @author D. McGlinchey + * @date June 2018 + * @brief Implementation of TrkrHitSetTpcv1 + */ +#include "TrkrHitSetTpcv1.h" +#include "TrkrHit.h" + +#include +#include +#include // for exit +#include +#include // for __decay_and_strip<>::__type + +void TrkrHitSetTpcv1::Reset() +{ + m_hitSetKey = TrkrDefs::HITSETKEYMAX; + + for (auto& pad : m_timeFrameADCData) + { + std::fill(pad.begin(), pad.end(), 0); + } +} +void TrkrHitSetTpcv1::Resize(const unsigned int n_pad, const unsigned int n_tbin) +{ + m_timeFrameADCData.resize(n_pad); + + for (auto& pad : m_timeFrameADCData) + { + pad.resize(n_tbin); + } + + Reset(); +} + +void TrkrHitSetTpcv1::identify(std::ostream& os) const +{ + const unsigned int layer = TrkrDefs::getLayer(m_hitSetKey); + const unsigned int trkrid = TrkrDefs::getTrkrId(m_hitSetKey); + + os + << "TrkrHitSetTpcv1: " + << " hitsetkey " << getHitSetKey() + << " TrkrId " << trkrid + << " layer " << layer + << " m_nPads: " << m_nPads + << " n_tBins: " << n_tBins + << std::endl; + + // for( const auto& entry : m_hits ) + // { + // std::cout << " hitkey " << entry.first << std::endl; + // (entry.second)->identify(os); + // } + + for (int i = 0; i < m_nPads; ++i) + { + os << "Pad " << i << ":"; + + for (const auto& adc : m_timeFrameADCData[i]) + { + os << "\t" << adc; + } + os << std::endl; + } +} + +TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(TrkrDefs::hitkey key) +{ + const uint16_t pad = TpcDefs ::getPad(key); + const uint16_t tbin = TpcDefs ::getTBin(key); + + return getTpcADC(pad, tbin); +} + +const TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(TrkrDefs::hitkey key) const +{ + const uint16_t pad = TpcDefs ::getPad(key); + const uint16_t tbin = TpcDefs ::getTBin(key); + + return getTpcADC(pad, tbin); +} + +TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint16_t tbin) +{ + assert(pad < m_nPads); + assert(tbin < n_tBins); + + return m_timeFrameADCData[pad][tbin]; +} + +const TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint16_t tbin) const +{ + assert(pad < m_nPads); + assert(tbin < n_tBins); + + return m_timeFrameADCData[pad][tbin]; +} + +void TrkrHitSetTpcv1::removeHit(TrkrDefs::hitkey key) +{ + getTpcADC(key) = 0; +} + +TrkrHitSetTpcv1::ConstIterator +TrkrHitSetTpcv1::addHitSpecificKey(const TrkrDefs::hitkey key, TrkrHit* hit) +{ + std::cout << __PRETTY_FUNCTION__ + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + + if (hit) + { + getTpcADC(key) = hit->getAdc(); + delete hit; + } + + return TrkrHitSet::addHitSpecificKey(key, hit); +} + +TrkrHit* +TrkrHitSetTpcv1::getHit(const TrkrDefs::hitkey key) const +{ + std::cout << __PRETTY_FUNCTION__ + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + + exit(1); + TrkrHitSetTpcv1::ConstIterator it = m_hits.find(key); + + if (it != m_hits.end()) + return it->second; + else + return nullptr; +} + +TrkrHitSetTpcv1::ConstRange +TrkrHitSetTpcv1::getHits() const +{ + std::cout << __PRETTY_FUNCTION__ + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + + exit(1); + + return TrkrHitSet::getHits(); +} diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h new file mode 100644 index 0000000000..73aeeb7cf3 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -0,0 +1,108 @@ +#ifndef TRACKBASE_TrkrHitSetTpcv1_H +#define TRACKBASE_TrkrHitSetTpcv1_H + +#include "TpcDefs.h" +#include "TrkrDefs.h" +#include "TrkrHitSet.h" + +#include // for pair +#include + +// forward declaration +class TrkrHit; + +//! Vectorized TPC data time frame storage +class TrkrHitSetTpcv1 : public TrkrHitSet +{ + public: + TrkrHitSetTpcv1() = default; + + TrkrHitSetTpcv1(const unsigned int n_pad, const unsigned int n_tbin) { Resize(n_pad, n_tbin); } + + ~TrkrHitSetTpcv1() override + { + } + + void identify(std::ostream& os = std::cout) const override; + + void Resize(const unsigned int n_pad, const unsigned int n_tbin); + + void Reset() override; + + void setHitSetKey(const TrkrDefs::hitsetkey key) override + { + m_hitSetKey = key; + } + + TrkrDefs::hitsetkey getHitSetKey() const override + { + return m_hitSetKey; + } + + TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey); + + const TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey) const; + + TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin); + + const TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) const; + + ConstIterator addHitSpecificKey(const TrkrDefs::hitkey, TrkrHit*) override; + + void removeHit(TrkrDefs::hitkey) override; + + TrkrHit* getHit(const TrkrDefs::hitkey) const override; + + ConstRange getHits() const override; + + unsigned int size() const override + { + return m_hits.size(); + } + + unsigned int getNPads() const + { + return m_nPads; + } + + void setNPads(unsigned int nPads = 0) + { + m_nPads = nPads; + } + + const std::vector >& getTimeFrameAdcData() const + { + return m_timeFrameADCData; + } + + void setTimeFrameAdcData(const std::vector >& timeFrameAdcData) + { + m_timeFrameADCData = timeFrameAdcData; + } + + unsigned int getTBins() const + { + return n_tBins; + } + + void setTBins(unsigned int tBins = 0) + { + n_tBins = tBins; + } + + private: + /// unique key for this object + TrkrDefs::hitsetkey m_hitSetKey = TrkrDefs::HITSETKEYMAX; + + /// vector storage of TPC timeframe without zero suppression + // Top level indexes are vectors of pads + // Lower level indexes are vectors of time bin + std::vector > m_timeFrameADCData; + + unsigned int m_nPads = 0; + unsigned int n_tBins = 0; + + ClassDefOverride(TrkrHitSetTpcv1, 1); +}; + +#endif // TRACKBASE_TrkrHitSetTpcv1_H diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1LinkDef.h b/offline/packages/trackbase/TrkrHitSetTpcv1LinkDef.h new file mode 100644 index 0000000000..e6e64918c2 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpcv1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrHitSetTpcv1+; + +#endif From a71eea6468867f30d1a52731446d9b812fb21549 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 12 Mar 2023 16:30:39 -0400 Subject: [PATCH 010/468] add general interface class for vectorized TPC timeframe TrkrHitSet object --- offline/packages/trackbase/Makefile.am | 4 + offline/packages/trackbase/TrkrHitSetTpc.cc | 38 +++++++++ offline/packages/trackbase/TrkrHitSetTpc.h | 81 +++++++++++++++++++ .../packages/trackbase/TrkrHitSetTpcLinkDef.h | 5 ++ offline/packages/trackbase/TrkrHitSetTpcv1.cc | 34 ++------ offline/packages/trackbase/TrkrHitSetTpcv1.h | 42 +++++----- 6 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 offline/packages/trackbase/TrkrHitSetTpc.cc create mode 100644 offline/packages/trackbase/TrkrHitSetTpc.h create mode 100644 offline/packages/trackbase/TrkrHitSetTpcLinkDef.h diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 62842a5021..d762e27f69 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -76,6 +76,7 @@ pkginclude_HEADERS = \ TrkrHitSetContainer.h \ TrkrHitSetContainerv1.h \ TrkrHitSetv1.h \ + TrkrHitSetTpc.h \ TrkrHitSetTpcv1.h \ TrkrHitTruthAssoc.h \ TrkrHitTruthAssocv1.h \ @@ -124,6 +125,7 @@ ROOTDICTS = \ TrkrHitSetContainerv1_Dict.cc \ TrkrHitSet_Dict.cc \ TrkrHitSetv1_Dict.cc \ + TrkrHitSetTpc_Dict.cc \ TrkrHitSetTpcv1_Dict.cc \ TrkrHitTruthAssoc_Dict.cc \ TrkrHitTruthAssocv1_Dict.cc \ @@ -175,6 +177,7 @@ nobase_dist_pcm_DATA = \ TrkrHitSetContainerv1_Dict_rdict.pcm \ TrkrHitSet_Dict_rdict.pcm \ TrkrHitSetv1_Dict_rdict.pcm \ + TrkrHitSetTpc_Dict_rdict.pcm \ TrkrHitSetTpcv1_Dict_rdict.pcm \ TrkrHitTruthAssoc_Dict_rdict.pcm \ TrkrHitTruthAssocv1_Dict_rdict.pcm \ @@ -230,6 +233,7 @@ libtrack_io_la_SOURCES = \ TrkrHitSetContainer.cc \ TrkrHitSetContainerv1.cc \ TrkrHitSetv1.cc \ + TrkrHitSetTpc.cc \ TrkrHitSetTpcv1.cc \ TrkrHitTruthAssocv1.cc \ TrkrHitv1.cc \ diff --git a/offline/packages/trackbase/TrkrHitSetTpc.cc b/offline/packages/trackbase/TrkrHitSetTpc.cc new file mode 100644 index 0000000000..895b8878dd --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpc.cc @@ -0,0 +1,38 @@ +/** + * @file trackbase/TrkrHitSetTpc.cc + * @author D. McGlinchey + * @date June 2018 + * @brief Implementation of TrkrHitSetTpc + */ +#include "TrkrHitSetTpc.h" +#include "TrkrHit.h" + +#include +#include +#include // for exit +#include +#include // for __decay_and_strip<>::__type + +void TrkrHitSetTpc::identify(std::ostream& os) const +{ + os + << "TrkrHitSetTpc: " + << " hitsetkey " << getHitSetKey() + << std::endl; +} + +TpcDefs::ADCDataType& TrkrHitSetTpc::getTpcADC(TrkrDefs::hitkey key) +{ + const uint16_t pad = TpcDefs ::getPad(key); + const uint16_t tbin = TpcDefs ::getTBin(key); + + return getTpcADC(pad, tbin); +} + +const TpcDefs::ADCDataType& TrkrHitSetTpc::getTpcADC(TrkrDefs::hitkey key) const +{ + const uint16_t pad = TpcDefs ::getPad(key); + const uint16_t tbin = TpcDefs ::getTBin(key); + + return getTpcADC(pad, tbin); +} diff --git a/offline/packages/trackbase/TrkrHitSetTpc.h b/offline/packages/trackbase/TrkrHitSetTpc.h new file mode 100644 index 0000000000..8269b2c251 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpc.h @@ -0,0 +1,81 @@ +#ifndef TRACKBASE_TrkrHitSetTpc_H +#define TRACKBASE_TrkrHitSetTpc_H + +#include "TpcDefs.h" +#include "TrkrDefs.h" +#include "TrkrHitSet.h" + +#include // for pair +#include + +// forward declaration +class TrkrHit; + +//! Generalized interface class for vectorized TPC data time frame storage +class TrkrHitSetTpc : public TrkrHitSet +{ + public: + typedef std::vector > TimeFrameADCDataType; + + TrkrHitSetTpc() = default; + + TrkrHitSetTpc(const unsigned int /*n_pad*/, const unsigned int /*n_tbin*/) {} + + ~TrkrHitSetTpc() override + { + } + + virtual void identify(std::ostream& os = std::cout) const override; + + virtual void Resize(const unsigned int /*n_pad*/, const unsigned int /*n_tbin*/) {} + + TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey); + + const TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey) const; + + virtual TpcDefs::ADCDataType& getTpcADC(const uint16_t /*pad*/, const uint16_t /*tbin*/) + { + static TpcDefs::ADCDataType v = 0; + return v; + }; + + virtual const TpcDefs::ADCDataType& getTpcADC(const uint16_t /*pad*/, const uint16_t /*tbin*/) const + { + static TpcDefs::ADCDataType v = 0; + return v; + }; + + virtual unsigned int getNPads() const + { + return 0; + } + + virtual void setNPads(unsigned int /*nPads*/) + { + } + + virtual const TimeFrameADCDataType& getTimeFrameAdcData() const + { + static TimeFrameADCDataType tmp; + + return tmp; + } + + virtual void setTimeFrameAdcData(const TimeFrameADCDataType&) + { + } + + virtual unsigned int getTBins() const + { + return 0; + } + + virtual void setTBins(unsigned int /*tBins*/) + { + } + + private: + ClassDefOverride(TrkrHitSetTpc, 1); +}; + +#endif // TRACKBASE_TrkrHitSetTpc_H diff --git a/offline/packages/trackbase/TrkrHitSetTpcLinkDef.h b/offline/packages/trackbase/TrkrHitSetTpcLinkDef.h new file mode 100644 index 0000000000..2a997986ab --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetTpcLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrHitSetTpc+; + +#endif diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 58dc448238..7e87ad647d 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -54,7 +54,7 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const // (entry.second)->identify(os); // } - for (int i = 0; i < m_nPads; ++i) + for (unsigned int i = 0; i < m_nPads; ++i) { os << "Pad " << i << ":"; @@ -66,22 +66,6 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const } } -TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(TrkrDefs::hitkey key) -{ - const uint16_t pad = TpcDefs ::getPad(key); - const uint16_t tbin = TpcDefs ::getTBin(key); - - return getTpcADC(pad, tbin); -} - -const TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(TrkrDefs::hitkey key) const -{ - const uint16_t pad = TpcDefs ::getPad(key); - const uint16_t tbin = TpcDefs ::getTBin(key); - - return getTpcADC(pad, tbin); -} - TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint16_t tbin) { assert(pad < m_nPads); @@ -107,7 +91,7 @@ TrkrHitSetTpcv1::ConstIterator TrkrHitSetTpcv1::addHitSpecificKey(const TrkrDefs::hitkey key, TrkrHit* hit) { std::cout << __PRETTY_FUNCTION__ - << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << std::endl; if (hit) { @@ -115,31 +99,27 @@ TrkrHitSetTpcv1::addHitSpecificKey(const TrkrDefs::hitkey key, TrkrHit* hit) delete hit; } - return TrkrHitSet::addHitSpecificKey(key, hit); + return TrkrHitSetTpc::addHitSpecificKey(key, hit); } TrkrHit* TrkrHitSetTpcv1::getHit(const TrkrDefs::hitkey key) const { std::cout << __PRETTY_FUNCTION__ - << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << std::endl; exit(1); - TrkrHitSetTpcv1::ConstIterator it = m_hits.find(key); - if (it != m_hits.end()) - return it->second; - else - return nullptr; + return TrkrHitSetTpc::getHit(key); } TrkrHitSetTpcv1::ConstRange TrkrHitSetTpcv1::getHits() const { std::cout << __PRETTY_FUNCTION__ - << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << endl; + << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << std::endl; exit(1); - return TrkrHitSet::getHits(); + return TrkrHitSetTpc::getHits(); } diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h index 73aeeb7cf3..685411e6d0 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.h +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -1,9 +1,7 @@ #ifndef TRACKBASE_TrkrHitSetTpcv1_H #define TRACKBASE_TrkrHitSetTpcv1_H -#include "TpcDefs.h" -#include "TrkrDefs.h" -#include "TrkrHitSet.h" +#include "TrkrHitSetTpc.h" #include // for pair #include @@ -12,12 +10,16 @@ class TrkrHit; //! Vectorized TPC data time frame storage -class TrkrHitSetTpcv1 : public TrkrHitSet +class TrkrHitSetTpcv1 final : public TrkrHitSetTpc { public: TrkrHitSetTpcv1() = default; - TrkrHitSetTpcv1(const unsigned int n_pad, const unsigned int n_tbin) { Resize(n_pad, n_tbin); } + TrkrHitSetTpcv1(const unsigned int n_pad, const unsigned int n_tbin) + : TrkrHitSetTpc(n_pad, n_tbin) + { + Resize(n_pad, n_tbin); + } ~TrkrHitSetTpcv1() override { @@ -25,7 +27,10 @@ class TrkrHitSetTpcv1 : public TrkrHitSet void identify(std::ostream& os = std::cout) const override; - void Resize(const unsigned int n_pad, const unsigned int n_tbin); + void Resize(const unsigned int n_pad, const unsigned int n_tbin) override; + + //! For ROOT TClonesArray end of event Operation + void Clear(Option_t* /*option*/ = "") override { Reset(); } void Reset() override; @@ -39,13 +44,12 @@ class TrkrHitSetTpcv1 : public TrkrHitSet return m_hitSetKey; } - TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey); - - const TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey) const; + // legacy TrkrDefs::hitkey accesses + using TrkrHitSetTpc::getTpcADC; - TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin); + TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) override; - const TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) const; + const TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) const override; ConstIterator addHitSpecificKey(const TrkrDefs::hitkey, TrkrHit*) override; @@ -57,35 +61,35 @@ class TrkrHitSetTpcv1 : public TrkrHitSet unsigned int size() const override { - return m_hits.size(); + return m_nPads * n_tBins; } - unsigned int getNPads() const + unsigned int getNPads() const override { return m_nPads; } - void setNPads(unsigned int nPads = 0) + void setNPads(unsigned int nPads = 0) override { m_nPads = nPads; } - const std::vector >& getTimeFrameAdcData() const + const TimeFrameADCDataType& getTimeFrameAdcData() const override { return m_timeFrameADCData; } - void setTimeFrameAdcData(const std::vector >& timeFrameAdcData) + void setTimeFrameAdcData(const TimeFrameADCDataType& timeFrameAdcData) override { m_timeFrameADCData = timeFrameAdcData; } - unsigned int getTBins() const + unsigned int getTBins() const override { return n_tBins; } - void setTBins(unsigned int tBins = 0) + void setTBins(unsigned int tBins = 0) override { n_tBins = tBins; } @@ -97,7 +101,7 @@ class TrkrHitSetTpcv1 : public TrkrHitSet /// vector storage of TPC timeframe without zero suppression // Top level indexes are vectors of pads // Lower level indexes are vectors of time bin - std::vector > m_timeFrameADCData; + TimeFrameADCDataType m_timeFrameADCData; unsigned int m_nPads = 0; unsigned int n_tBins = 0; From 7354fe892a6195cbc1e1aa8b7cc522fdca45cd76 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 13 Mar 2023 01:32:14 -0400 Subject: [PATCH 011/468] IO and memory efficient container using TClonesArray --- offline/packages/trackbase/Makefile.am | 4 + .../packages/trackbase/TrkrHitSetContainer.cc | 2 +- .../trackbase/TrkrHitSetContainerv2.cc | 162 ++++++++++++++++++ .../trackbase/TrkrHitSetContainerv2.h | 74 ++++++++ .../trackbase/TrkrHitSetContainerv2LinkDef.h | 5 + 5 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 offline/packages/trackbase/TrkrHitSetContainerv2.cc create mode 100644 offline/packages/trackbase/TrkrHitSetContainerv2.h create mode 100644 offline/packages/trackbase/TrkrHitSetContainerv2LinkDef.h diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index d762e27f69..c48b245aba 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -75,6 +75,7 @@ pkginclude_HEADERS = \ TrkrHitSet.h \ TrkrHitSetContainer.h \ TrkrHitSetContainerv1.h \ + TrkrHitSetContainerv2.h \ TrkrHitSetv1.h \ TrkrHitSetTpc.h \ TrkrHitSetTpcv1.h \ @@ -123,6 +124,7 @@ ROOTDICTS = \ TrkrClusterv4_Dict.cc \ TrkrHitSetContainer_Dict.cc \ TrkrHitSetContainerv1_Dict.cc \ + TrkrHitSetContainerv2_Dict.cc \ TrkrHitSet_Dict.cc \ TrkrHitSetv1_Dict.cc \ TrkrHitSetTpc_Dict.cc \ @@ -175,6 +177,7 @@ nobase_dist_pcm_DATA = \ TrkrClusterv4_Dict_rdict.pcm \ TrkrHitSetContainer_Dict_rdict.pcm \ TrkrHitSetContainerv1_Dict_rdict.pcm \ + TrkrHitSetContainerv2_Dict_rdict.pcm \ TrkrHitSet_Dict_rdict.pcm \ TrkrHitSetv1_Dict_rdict.pcm \ TrkrHitSetTpc_Dict_rdict.pcm \ @@ -232,6 +235,7 @@ libtrack_io_la_SOURCES = \ TrkrHitSet.cc \ TrkrHitSetContainer.cc \ TrkrHitSetContainerv1.cc \ + TrkrHitSetContainerv2.cc \ TrkrHitSetv1.cc \ TrkrHitSetTpc.cc \ TrkrHitSetTpcv1.cc \ diff --git a/offline/packages/trackbase/TrkrHitSetContainer.cc b/offline/packages/trackbase/TrkrHitSetContainer.cc index 8198db015f..fe727fd73c 100644 --- a/offline/packages/trackbase/TrkrHitSetContainer.cc +++ b/offline/packages/trackbase/TrkrHitSetContainer.cc @@ -30,7 +30,7 @@ TrkrHitSetContainer::addHitSet(TrkrHitSet* /*newhit*/) TrkrHitSetContainer::ConstIterator TrkrHitSetContainer::addHitSetSpecifyKey(const TrkrDefs::hitsetkey /*key*/, TrkrHitSet* /*newhit*/) { return dummy_map.cbegin(); } - + TrkrHitSetContainer::Iterator TrkrHitSetContainer::findOrAddHitSet(TrkrDefs::hitsetkey /*key*/) { return dummy_map.begin(); } diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc new file mode 100644 index 0000000000..64cdffcf02 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -0,0 +1,162 @@ +/** + * @file trackbase/TrkrHitSetContainerv2.cc + * @author D. McGlinchey, H. PEREIRA DA COSTA + * @date June 2018 + * @brief Implementation for TrkrHitSetContainerv2 + */ +#include "TrkrHitSetContainerv2.h" + +#include "TrkrDefs.h" +#include "TrkrHitSetv1.h" + +#include + +#include +#include + +TrkrHitSetContainerv2:: + TrkrHitSetContainerv2(const std::string& hitsetclass) + : m_hitArray(hitsetclass.c_str()) +{ +} + +void TrkrHitSetContainerv2::Reset() +{ + m_hitmap.clear(); + //! fast clear without calling destructor + m_hitArray.Clear("C"); +} + +void TrkrHitSetContainerv2::identify(std::ostream& os) const +{ + syncMapArray(); + + os << "TrkrHitSetContainerv2 with class " + << m_hitArray.GetClass()->GetName() + << ": Number of hits: " << size() << " index map size = " << m_hitmap.size() << std::endl; + ConstIterator iter; + for (const auto& pair : m_hitmap) + { + int layer = TrkrDefs::getLayer(pair.first); + os << "hitsetkey " << pair.first << " layer " << layer << std::endl; + pair.second->identify(); + } + return; +} + +TrkrHitSetContainerv2::ConstIterator +TrkrHitSetContainerv2::addHitSet(TrkrHitSet* newhit) +{ + std::cout << __PRETTY_FUNCTION__ + << " : deprecated. Use findOrAddHitSet()." << std::endl; + return addHitSetSpecifyKey(newhit->getHitSetKey(), newhit); +} + +TrkrHitSetContainerv2::ConstIterator +TrkrHitSetContainerv2::addHitSetSpecifyKey(const TrkrDefs::hitsetkey key, TrkrHitSet* newhit) +{ + std::cout << __PRETTY_FUNCTION__ + << " : deprecated. Use findOrAddHitSet()." << std::endl; + + exit(1); + + return TrkrHitSetContainer::addHitSetSpecifyKey(key, newhit); +} + +void TrkrHitSetContainerv2::removeHitSet(TrkrDefs::hitsetkey key) +{ + std::cout << __PRETTY_FUNCTION__ + << " : deprecated. This function still works but slows down operation." << std::endl; + + syncMapArray(); + auto iter = m_hitmap.find(key); + if (iter != m_hitmap.end()) + { + TrkrHitSet* hitset = iter->second; + // delete hitset; + m_hitArray.Remove(hitset); + m_hitmap.erase(iter); + } +} + +void TrkrHitSetContainerv2::removeHitSet(TrkrHitSet* hitset) +{ + removeHitSet(hitset->getHitSetKey()); +} + +TrkrHitSetContainerv2::ConstRange +TrkrHitSetContainerv2::getHitSets(const TrkrDefs::TrkrId trackerid) const +{ + syncMapArray(); + const TrkrDefs::hitsetkey keylo = TrkrDefs::getHitSetKeyLo(trackerid); + const TrkrDefs::hitsetkey keyhi = TrkrDefs::getHitSetKeyHi(trackerid); + return std::make_pair(m_hitmap.lower_bound(keylo), m_hitmap.upper_bound(keyhi)); +} + +TrkrHitSetContainerv2::ConstRange +TrkrHitSetContainerv2::getHitSets(const TrkrDefs::TrkrId trackerid, const uint8_t layer) const +{ + syncMapArray(); + TrkrDefs::hitsetkey keylo = TrkrDefs::getHitSetKeyLo(trackerid, layer); + TrkrDefs::hitsetkey keyhi = TrkrDefs::getHitSetKeyHi(trackerid, layer); + return std::make_pair(m_hitmap.lower_bound(keylo), m_hitmap.upper_bound(keyhi)); +} + +TrkrHitSetContainerv2::ConstRange +TrkrHitSetContainerv2::getHitSets() const +{ + syncMapArray(); + return std::make_pair(m_hitmap.cbegin(), m_hitmap.cend()); +} + +TrkrHitSetContainerv2::Iterator +TrkrHitSetContainerv2::findOrAddHitSet(TrkrDefs::hitsetkey key) +{ + syncMapArray(); + auto it = m_hitmap.lower_bound(key); + if (it == m_hitmap.end() || (key < it->first)) + { + TrkrHitSet* hitset = (TrkrHitSet*) m_hitArray.ConstructedAt(m_hitArray.GetSize()); + assert(hitset); + + it = m_hitmap.insert(it, std::make_pair(key, hitset)); + it->second->setHitSetKey(key); + } + return it; +} + +TrkrHitSet* +TrkrHitSetContainerv2::findHitSet(TrkrDefs::hitsetkey key) +{ + syncMapArray(); + auto it = m_hitmap.find(key); + if (it != m_hitmap.end()) + { + return it->second; + } + else + { + return nullptr; + } +} + +void TrkrHitSetContainerv2::syncMapArray(void) const +{ + if (m_hitmap.size() == (size_t) m_hitArray.GetSize()) return; + + if (m_hitmap.size() > 0) + { + std::cout + << __PRETTY_FUNCTION__ << " Error: m_hitmap and m_hitArray get out of sync, which should not happen unless DST readback. " + << "m_hitmap.size( ) = " << m_hitmap.size() << " m_hitArray.GetSize() = " << m_hitArray.GetSize() << std::endl; + } + + for (int i = 0; i < m_hitArray.GetSize(); ++i) + { + TrkrHitSet* hitset = static_cast(m_hitArray[i]); + + assert(hitset); + + m_hitmap[hitset->getHitSetKey()] = hitset; + } +} diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.h b/offline/packages/trackbase/TrkrHitSetContainerv2.h new file mode 100644 index 0000000000..f8897432c8 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.h @@ -0,0 +1,74 @@ +#ifndef TRACKBASE_TrkrHitSetContainerv2_H +#define TRACKBASE_TrkrHitSetContainerv2_H + +#include "TrkrDefs.h" +#include "TrkrHitSetContainer.h" + +#include +#include // for cout, ostream +#include +#include // for pair +#include // for pair + +class TrkrHitSet; + +/** + * IO and memory efficient container using TClonesArray + * TrkrHitSet used in this container must impliment TrkrHitSet::Clear() function for fast reset without calling ~TrkrHitSet() + */ +class TrkrHitSetContainerv2 final : public TrkrHitSetContainer +{ + private: + //! only used in ROOT IO + TrkrHitSetContainerv2() = default; + + public: + TrkrHitSetContainerv2(const std::string& hitsetclass); + + ~TrkrHitSetContainerv2() override + { + } + + void Reset() override; + + void identify(std::ostream& = std::cout) const override; + + ConstIterator addHitSet(TrkrHitSet*) override; + + ConstIterator addHitSetSpecifyKey(const TrkrDefs::hitsetkey, TrkrHitSet*) override; + + //! Add a TrkrHitSet to TrkrHitSetContainerv2, return the iterater to the newly constructed TrkrHitSet + ConstIterator addHitSetSpecifyKey(const TrkrDefs::hitsetkey key); + + void removeHitSet(TrkrDefs::hitsetkey) override; + + void removeHitSet(TrkrHitSet*) override; + + Iterator findOrAddHitSet(TrkrDefs::hitsetkey key) override; + + ConstRange getHitSets(const TrkrDefs::TrkrId trackerid) const override; + + ConstRange getHitSets(const TrkrDefs::TrkrId trackerid, const uint8_t layer) const override; + + ConstRange getHitSets() const override; + + TrkrHitSet* findHitSet(TrkrDefs::hitsetkey key) override; + + unsigned int size() const override + { + return m_hitArray.GetSize(); + } + + private: + //! endure m_hitmap and m_hitArray are in sync, in particular m_hitmap need rebuild after reading back from the DST + void syncMapArray(void) const; + + //! used for indexing only, not used in storage. syncMapArray(void) rebuilds the map after DST readback + mutable Map m_hitmap; //! + + TClonesArray m_hitArray; + + ClassDefOverride(TrkrHitSetContainerv2, 1) +}; + +#endif // TRACKBASE_TrkrHitSetContainerv2_H diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2LinkDef.h b/offline/packages/trackbase/TrkrHitSetContainerv2LinkDef.h new file mode 100644 index 0000000000..19ca55e5ca --- /dev/null +++ b/offline/packages/trackbase/TrkrHitSetContainerv2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrHitSetContainerv2+; + +#endif /* __CINT__ */ From 7e751dddd638075a4efd5b13a7f62f18c731c4a1 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 13 Mar 2023 02:22:47 -0400 Subject: [PATCH 012/468] Avoid resize if same size is assigned --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 7e87ad647d..26eab9fe93 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -24,11 +24,13 @@ void TrkrHitSetTpcv1::Reset() } void TrkrHitSetTpcv1::Resize(const unsigned int n_pad, const unsigned int n_tbin) { - m_timeFrameADCData.resize(n_pad); + if (n_pad != m_timeFrameADCData.size()) + m_timeFrameADCData.resize(n_pad); for (auto& pad : m_timeFrameADCData) { - pad.resize(n_tbin); + if (n_tbin != pad.size()) + pad.resize(n_tbin); } Reset(); From da9ddfea9e30672696b93442af1838c0365c06a5 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 13 Mar 2023 02:23:18 -0400 Subject: [PATCH 013/468] reco tests --- offline/packages/tpc/TpcClusterizer.cc | 12 ++++++-- .../g4tpc/PHG4TpcElectronDrift.cc | 30 +++++-------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 8aa9e11a80..aa1fd9d454 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -8,6 +8,7 @@ #include // for hitkey, getLayer #include #include +#include #include #include @@ -45,6 +46,7 @@ #include // for pair #include #include +#include #include // Terra incognita.... #include @@ -66,7 +68,7 @@ namespace struct thread_data { PHG4TpcCylinderGeom *layergeom = nullptr; - TrkrHitSet *hitset = nullptr; + TrkrHitSetTpc *hitset = nullptr; RawHitSetv1 *rawhitset = nullptr; ActsGeometry *tGeometry = nullptr; unsigned int layer = 0; @@ -489,7 +491,7 @@ namespace } if( my_data->hitset!=nullptr){ - TrkrHitSet *hitset = my_data->hitset; + TrkrHitSetTpc *hitset = my_data->hitset; TrkrHitSet::ConstRange hitrangei = hitset->getHits(); for (TrkrHitSet::ConstIterator hitr = hitrangei.first; @@ -537,6 +539,9 @@ namespace } } } + + + }else if( my_data->rawhitset!=nullptr){ RawHitSetv1 *hitset = my_data->rawhitset; /*std::cout << "Layer: " << my_data->layer @@ -847,7 +852,8 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) ++hitsetitr) { //if(count>0)continue; - TrkrHitSet *hitset = hitsetitr->second; + TrkrHitSetTpc *hitset = dynamic_cast(hitsetitr->second); + assert(hitset); unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); unsigned int sector= TpcDefs::getSectorId(hitsetitr->first); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index ff9f97dc42..9c1a941651 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -12,8 +12,9 @@ #include #include // for TrkrHit -#include +#include #include +#include #include // for TrkrHitTruthA... #include #include @@ -140,7 +141,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) dstNode->addNode(DetNode); } - hitsetcontainer = new TrkrHitSetContainerv1; + hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1"); auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); DetNode->addNode(newNode); } @@ -621,6 +622,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // find or add this hitset on the node tree TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey); + TrkrHitSetTpc * hitset = dynamic_cast(node_hitsetit->second); + assert(hitset); // get all of the hits from the temporary hitset TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits(); @@ -641,17 +644,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) ncollectedhits++; } - // find or add this hit to the node tree - TrkrHit *node_hit = node_hitsetit->second->getHit(temp_hitkey); - if (!node_hit) - { - // Otherwise, create a new one - node_hit = new TrkrHitv2(); - node_hitsetit->second->addHitSpecificKey(temp_hitkey, node_hit); - } - - // Either way, add the energy to it - node_hit->addEnergy(temp_tpchit->getEnergy()); + hitset->getTpcADC(temp_hitkey) += temp_tpchit->getEnergy(); } // end loop over temp hits @@ -695,16 +688,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // get all of the hits from this hitset TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - TrkrDefs::hitkey hitkey = hit_iter->first; - TrkrHit *tpchit = hit_iter->second; - std::cout << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) << " z bin " << TpcDefs::getTBin(hitkey) - << " energy " << tpchit->getEnergy() << std::endl; - } + hitset->identify(std::cout); } } From e81e51c5e3bc2991e4fc73a56b36382ef7eee170 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 13 Mar 2023 03:01:18 -0400 Subject: [PATCH 014/468] clean deprecation --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 26eab9fe93..407e280046 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -95,11 +95,7 @@ TrkrHitSetTpcv1::addHitSpecificKey(const TrkrDefs::hitkey key, TrkrHit* hit) std::cout << __PRETTY_FUNCTION__ << " : This function is deprecated! Please use getTpcADC(TrkrDefs::hitkey key)" << std::endl; - if (hit) - { - getTpcADC(key) = hit->getAdc(); - delete hit; - } + exit(1); return TrkrHitSetTpc::addHitSpecificKey(key, hit); } From a529a458131dbe8d88fe1de127a1b050dea0c513 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 14 Mar 2023 13:46:07 -0400 Subject: [PATCH 015/468] Modified CM cluster and hit phi matching. Added new version of CMFlashCluster that contains 2 bools for identifying if meta-cluster consists of sub-clusters that cross sector/module boundaries --- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 199 ++++++++++++++++-- .../tpccalib/PHTpcCentralMembraneMatcher.h | 29 ++- .../trackbase/CMFlashClusterContainerv1.cc | 1 + .../packages/trackbase/CMFlashClusterv2.cc | 53 +++++ offline/packages/trackbase/CMFlashClusterv2.h | 84 ++++++++ .../trackbase/CMFlashClusterv2LinkDef.h | 5 + 6 files changed, 347 insertions(+), 24 deletions(-) create mode 100644 offline/packages/trackbase/CMFlashClusterv2.cc create mode 100644 offline/packages/trackbase/CMFlashClusterv2.h create mode 100644 offline/packages/trackbase/CMFlashClusterv2LinkDef.h diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index fefc4a61a0..6f9b99d619 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -20,10 +20,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include @@ -164,6 +167,32 @@ std::vector PHTpcCentralMembraneMatcher::getRGaps( TH2F *r_phi ){ } */ +double PHTpcCentralMembraneMatcher::getPhiRotation_smoothed(TH1D *hitHist, TH1D *clustHist){ + + TCanvas *c1 = new TCanvas(); + + gStyle->SetOptFit(1); + + hitHist->Smooth(); + // clustHist->Smooth(); + + TF1 *f1 = new TF1("f1",[&](double *x, double *p){ return p[0] * hitHist->GetBinContent(hitHist->FindBin(x[0] - p[1])); }, -M_PI, M_PI, 2); + f1->SetParNames("A","shift"); + f1->SetParameters(1.0,0.0); + // f1->SetParLimits(1,-M_PI/18,M_PI/18); + + clustHist->Fit("f1","IL"); + + clustHist->Draw(); + f1->Draw("same"); + + c1->SaveAs(Form("%s_fit.png",clustHist->GetName())); + + gStyle->SetOptFit(0); + + return f1->GetParameter(1); +} + std::vector> PHTpcCentralMembraneMatcher::getPhiGaps( TH2F *r_phi ){ int bin0 = r_phi->GetYaxis()->FindBin(0.0); @@ -232,6 +261,7 @@ std::vector PHTpcCentralMembraneMatcher::getAverageRotation(std::vector< } + std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ TH1D *proj = r_phi->ProjectionY("R_proj",1,360); @@ -340,12 +370,16 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) clust_r_phi = new TH2F("clust_r_phi","clust R vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - + + std::vector hitR; + std::vector hitPhi; + // Get truth cluster positions //===================== const double phi_petal = M_PI / 9.0; // angle span of one petal + /* * utility function to * - duplicate generated truth position to cover both sides of the central membrane @@ -359,6 +393,9 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) hit_r_phi->Fill(source.Phi(), source.Perp()); hit_r_phi_pos->Fill(source.Phi(), source.Perp()); + + hitR.push_back(source.Perp()); + hitPhi.push_back(source.Phi()); source.SetZ( -1 ); m_truth_pos.push_back( source ); @@ -421,14 +458,16 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) TVector3 dummyPos(cx3[i][j], cy3[i][j], 0.0); dummyPos.RotateZ(k * phi_petal); save_truth_position(dummyPos); - + if(Verbosity() > 2) std::cout << " i " << i << " j " << j << " k " << k << " x1 " << dummyPos.X() << " y1 " << dummyPos.Y() << " theta " << std::atan2(dummyPos.Y(), dummyPos.X()) << " radius " << get_r( dummyPos.X(), dummyPos.y()) << std::endl; if(m_savehistograms) hxy_truth->Fill(dummyPos.X(),dummyPos.Y()); - } - + } + + hit_r_phi_gr = new TGraph((int)hitR.size(), &hitPhi[0], &hitR[0]); + int ret = GetNodes(topNode); return ret; } @@ -439,6 +478,36 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) std::vector reco_pos; std::vector reco_nclusters; + std::vector clustR; + std::vector clustPhi; + + std::vector clustR_pos; + std::vector clustPhi_pos; + + std::vector clustR_neg; + std::vector clustPhi_neg; + + + std::vector clustR1; + std::vector clustPhi1; + + std::vector clustR_pos1; + std::vector clustPhi_pos1; + + std::vector clustR_neg1; + std::vector clustPhi_neg1; + + std::vector clustR2; + std::vector clustPhi2; + + std::vector clustR_pos2; + std::vector clustPhi_pos2; + + std::vector clustR_neg2; + std::vector clustPhi_neg2; + + + // reset output distortion correction container histograms for( const auto& harray:{m_dcc_out->m_hDRint, m_dcc_out->m_hDPint, m_dcc_out->m_hDZint, m_dcc_out->m_hentries} ) { for( const auto& h:harray ) { h->Reset(); } } @@ -446,7 +515,7 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) clust_r_phi->Reset(); clust_r_phi_pos->Reset(); clust_r_phi_neg->Reset(); - + // read the reconstructed CM clusters auto clusrange = m_corrected_CMcluster_map->getClusters(); for (auto cmitr = clusrange.first; @@ -464,9 +533,44 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) reco_pos.push_back(tmp_pos); reco_nclusters.push_back(nclus); + clustR.push_back(tmp_pos.Perp()); + clustPhi.push_back(tmp_pos.Phi()); + + if(nclus == 1){ + clustR1.push_back(tmp_pos.Perp()); + clustPhi1.push_back(tmp_pos.Phi()); + }else{ + clustR2.push_back(tmp_pos.Perp()); + clustPhi2.push_back(tmp_pos.Phi()); + } + clust_r_phi->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - if(tmp_pos.Z() > 0) clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - else if(tmp_pos.Z() < 0) clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + if(tmp_pos.Z() > 0){ + clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + clustR_pos.push_back(tmp_pos.Perp()); + clustPhi_pos.push_back(tmp_pos.Phi()); + + if(nclus == 1){ + clustR_pos1.push_back(tmp_pos.Perp()); + clustPhi_pos1.push_back(tmp_pos.Phi()); + }else{ + clustR_pos2.push_back(tmp_pos.Perp()); + clustPhi_pos2.push_back(tmp_pos.Phi()); + } + + }else if(tmp_pos.Z() < 0){ + clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + clustR_neg.push_back(tmp_pos.Perp()); + clustPhi_neg.push_back(tmp_pos.Phi()); + + if(nclus == 1){ + clustR_neg1.push_back(tmp_pos.Perp()); + clustPhi_neg1.push_back(tmp_pos.Phi()); + }else{ + clustR_neg2.push_back(tmp_pos.Perp()); + clustPhi_neg2.push_back(tmp_pos.Phi()); + } + } if(Verbosity()) { @@ -483,6 +587,20 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) } + clust_r_phi_gr = new TGraph((int)clustR.size(), &clustPhi[0], &clustR[0]); + clust_r_phi_gr_pos = new TGraph((int)clustR_pos.size(), &clustPhi_pos[0], &clustR_pos[0]); + clust_r_phi_gr_neg = new TGraph((int)clustR_neg.size(), &clustPhi_neg[0], &clustR_neg[0]); + + + clust_r_phi_gr1 = new TGraph((int)clustR1.size(), &clustPhi1[0], &clustR1[0]); + clust_r_phi_gr1_pos = new TGraph((int)clustR_pos1.size(), &clustPhi_pos1[0], &clustR_pos1[0]); + clust_r_phi_gr1_neg = new TGraph((int)clustR_neg1.size(), &clustPhi_neg1[0], &clustR_neg1[0]); + + + clust_r_phi_gr2 = new TGraph((int)clustR2.size(), &clustPhi2[0], &clustR2[0]); + clust_r_phi_gr2_pos = new TGraph((int)clustR_pos2.size(), &clustPhi_pos2[0], &clustR_pos2[0]); + clust_r_phi_gr2_neg = new TGraph((int)clustR_neg2.size(), &clustPhi_neg2[0], &clustR_neg2[0]); + std::vector> hit_phiGaps = getPhiGaps(hit_r_phi); std::vector> clust_phiGaps = getPhiGaps(clust_r_phi); std::vector angleDiff = getAverageRotation(hit_phiGaps, clust_phiGaps); @@ -496,9 +614,29 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) std::vector> clust_phiGaps_neg = getPhiGaps(clust_r_phi_neg); std::vector angleDiff_neg = getAverageRotation(hit_phiGaps_neg, clust_phiGaps_neg); - std::cout << "rotation R1: " << angleDiff[0] << " R2: " << angleDiff[1] << " R3: " << angleDiff[2] << std::endl; - std::cout << "pos rotation R1: " << angleDiff_pos[0] << " R2: " << angleDiff_pos[1] << " R3: " << angleDiff_pos[2] << std::endl; - std::cout << "neg rotation R1: " << angleDiff_neg[0] << " R2: " << angleDiff_neg[1] << " R3: " << angleDiff_neg[2] << std::endl; + // std::cout << "rotation R1: " << angleDiff[0] << " R2: " << angleDiff[1] << " R3: " << angleDiff[2] << std::endl; + // std::cout << "pos rotation R1: " << angleDiff_pos[0] << " R2: " << angleDiff_pos[1] << " R3: " << angleDiff_pos[2] << std::endl; + // std::cout << "neg rotation R1: " << angleDiff_neg[0] << " R2: " << angleDiff_neg[1] << " R3: " << angleDiff_neg[2] << std::endl; + + double clustRotation[3]; + double clustRotation_pos[3]; + double clustRotation_neg[3]; + + clustRotation[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi->ProjectionX("cR1",151,206)); + clustRotation[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi->ProjectionX("cR2",206,290)); + clustRotation[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi->ProjectionX("cR3",290,499)); + + clustRotation_pos[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_pos->ProjectionX("cR1_pos",151,206)); + clustRotation_pos[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_pos->ProjectionX("cR2_pos",206,290)); + clustRotation_pos[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_pos->ProjectionX("cR3_pos",290,499)); + + clustRotation_neg[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_neg->ProjectionX("cR1_neg",151,206)); + clustRotation_neg[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_neg->ProjectionX("cR2_neg",206,290)); + clustRotation_neg[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_neg->ProjectionX("cR3_neg",290,499)); + + std::cout << "clust rotation R1: "<< clustRotation[0] << " R2: " << clustRotation[1] << " R3: " << clustRotation[2] << std::endl; + std::cout << "pos clust rotation R1: "<< clustRotation_pos[0] << " R2: " << clustRotation_pos[1] << " R3: " << clustRotation_pos[2] << std::endl; + std::cout << "neg clust rotation R1: "<< clustRotation_neg[0] << " R2: " << clustRotation_neg[1] << " R3: " << clustRotation_neg[2] << std::endl; std::vector hit_RPeaks = getRPeaks(hit_r_phi); std::vector clust_RPeaks_pos = getRPeaks(clust_r_phi_pos); @@ -577,19 +715,20 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) int angleR = -1; - if(reco_pos[j].Perp() < 40) angleR = 0; - else if(reco_pos[j].Perp() >= 40 && reco_pos[j].Perp() <58) angleR = 1; + if(reco_pos[j].Perp() < 41) angleR = 0; + else if(reco_pos[j].Perp() >= 41 && reco_pos[j].Perp() < 58) angleR = 1; if(reco_pos[j].Perp() >= 58) angleR = 2; - if(angleR != -1) reco_pos[j].RotateZ(-1.0*angleDiff[angleR]); - const double phi2_rot = reco_pos[j].Phi(); - if(angleR != -1) reco_pos[j].RotateZ(angleDiff[angleR]); - - //const auto& nclus = reco_nclusters[j]; + double phi2 = reco_pos[j].Phi(); const double z2 = reco_pos[j].Z(); const double rad2=get_r(reco_pos[j].X(), reco_pos[j].Y()); + if(angleR != -1){ + if(z2 > 0) phi2 += (hitRotation[angleR+1] - clustRotation_pos[angleR]); + else phi2 += (hitRotation[angleR+1] - clustRotation_neg[angleR]); + } + int clustRMatchIndex = -1; if(z2 > 0) clustRMatchIndex = getClusterRMatch(hitMatches_pos, clust_RPeaks_pos, rad2); @@ -609,16 +748,16 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) const bool accepted_r = (hitRadIndex == clustRMatchIndex); // const auto dphi = delta_phi(phi1-phi2); - const auto dphi_rot = delta_phi(phi1-phi2_rot); - const bool accepted_phi = std::abs(dphi_rot) < m_phi_cut; + const auto dphi = delta_phi(phi1-phi2); + const bool accepted_phi = std::abs(dphi) < m_phi_cut; if(!accepted_r || !accepted_phi) continue; // std::cout << "matching cluster " << j << " rad: " << rad2 << " clustRMatchIndex: " << clustRMatchIndex << " hitRadIndex: " << hitRadIndex << " hitMatchedR: " << (clustRMatchIndex != -1 ? hit_RPeaks[clustRMatchIndex] : -1) << std::endl; - if(fabs(dphi_rot)Write(); hit_r_phi_neg->Write(); + hit_r_phi_gr->Write("hit_r_phi_gr"); + + clust_r_phi->Write(); clust_r_phi_pos->Write(); clust_r_phi_neg->Write(); + clust_r_phi_gr->Write("clust_r_phi_gr"); + clust_r_phi_gr_pos->Write("clust_r_phi_gr_pos"); + clust_r_phi_gr_neg->Write("clust_r_phi_gr_neg"); + + + clust_r_phi_gr1->Write("clust_r_phi_gr1"); + clust_r_phi_gr1_pos->Write("clust_r_phi_gr1_pos"); + clust_r_phi_gr1_neg->Write("clust_r_phi_gr1_neg"); + + clust_r_phi_gr2->Write("clust_r_phi_gr2"); + clust_r_phi_gr2_pos->Write("clust_r_phi_gr2_pos"); + clust_r_phi_gr2_neg->Write("clust_r_phi_gr2_neg"); + fout2->Close(); // write evaluation histograms diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index d987b3a70e..caf764e3cb 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -26,7 +26,9 @@ class TF1; class TNtuple; class TFile; class TH1F; +class TH1D; class TH2F; +class TGraph; class TVector3; class PHTpcCentralMembraneMatcher : public SubsysReco @@ -117,6 +119,21 @@ class PHTpcCentralMembraneMatcher : public SubsysReco TH2F *clust_r_phi; TH2F *clust_r_phi_pos; TH2F *clust_r_phi_neg; + + TGraph *hit_r_phi_gr; + + TGraph *clust_r_phi_gr; + TGraph *clust_r_phi_gr_pos; + TGraph *clust_r_phi_gr_neg; + + TGraph *clust_r_phi_gr1; + TGraph *clust_r_phi_gr1_pos; + TGraph *clust_r_phi_gr1_neg; + + TGraph *clust_r_phi_gr2; + TGraph *clust_r_phi_gr2_pos; + TGraph *clust_r_phi_gr2_neg; + std::string m_outputfile2 = "CM_r_phi_maps.root"; std::unique_ptr fout2; @@ -134,13 +151,13 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@{ /// distortion correction grid size along phi - int m_phibins = 40; + int m_phibins = 200; static constexpr float m_phiMin = 0; static constexpr float m_phiMax = 2.*M_PI; /// distortion correction grid size along r - int m_rbins = 26; + int m_rbins = 58; static constexpr float m_rMin = 20; // cm static constexpr float m_rMax = 78; // cm @@ -219,10 +236,18 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@} + double hitRotationTotal; + double hitRotation[4]; + double clustRotation[3]; + double clustRotation_pos[3]; + double clustRotation_neg[3]; + std::vector> getPhiGaps(TH2F *r_phi); std::vector getAverageRotation(std::vector> hit, std::vector> clust); + double getPhiRotation_smoothed( TH1D *hitHist, TH1D *clustHist ); + std::vector getRPeaks(TH2F *r_phi); int getClusterRMatch( std::vector hitMatches, std::vector clusterPeaks, double clusterR); diff --git a/offline/packages/trackbase/CMFlashClusterContainerv1.cc b/offline/packages/trackbase/CMFlashClusterContainerv1.cc index f2d8bbbdca..95a8467bf2 100644 --- a/offline/packages/trackbase/CMFlashClusterContainerv1.cc +++ b/offline/packages/trackbase/CMFlashClusterContainerv1.cc @@ -7,6 +7,7 @@ #include "CMFlashClusterContainerv1.h" #include "CMFlashCluster.h" #include "CMFlashClusterv1.h" +//#include "CMFlashClusterv2.h" #include diff --git a/offline/packages/trackbase/CMFlashClusterv2.cc b/offline/packages/trackbase/CMFlashClusterv2.cc new file mode 100644 index 0000000000..290b6b766f --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv2.cc @@ -0,0 +1,53 @@ +/** + * @file trackbase/CMFlashClusterv2.cc + * @author Ben Kimelman + * @date March 2023 + * @brief Implementation of CMFlashClusterv2 + */ +#include "CMFlashClusterv2.h" + +#include +#include // for swap + +void CMFlashClusterv2::identify(std::ostream& os) const +{ + os << "---CMFlashClusterv2--------------------" << std::endl; + + os << " (x,y,z) = (" << m_pos[0]; + os << ", " << m_pos[1] << ", "; + os << m_pos[2] << ") cm"; + + os << " adc = " << getAdc() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int CMFlashClusterv2::isValid() const +{ + if(std::isnan(getX())) return 0; + if(std::isnan(getY())) return 0; + if(std::isnan(getZ())) return 0; + + if (m_adc == 0xFFFFFFFF) return 0; + + return 1; +} + +void CMFlashClusterv2::CopyFrom( const CMFlashCluster& source ) +{ + // do nothing if copying onto oneself + if( this == &source ) return; + + // parent class method + CMFlashCluster::CopyFrom( source ); + + setX( source.getX() ); + setY( source.getY() ); + setZ( source.getZ() ); + setAdc( source.getAdc() ); + +} + diff --git a/offline/packages/trackbase/CMFlashClusterv2.h b/offline/packages/trackbase/CMFlashClusterv2.h new file mode 100644 index 0000000000..12c4f02fd0 --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv2.h @@ -0,0 +1,84 @@ +/** + * @file trackbase/CMFlashClusterv2.h + * @author Ben Kimelman + * @date March 2023 + * @brief Version 2 of CMFlashCluster + */ +#ifndef TRACKBASE_CMFLASHCLUSTERV2_H +#define TRACKBASE_CMFLASHCLUSTERV2_H + +#include "CMFlashCluster.h" + +#include + +class PHObject; + +/** + * @brief Version 2 of CMFlashCluster + * + * Adding bool variables to identify if + * meta-cluster contains sub-clusters from + * both sides of sector (phi) or module (R) + * gaps + * + */ +class CMFlashClusterv2 : public CMFlashCluster +{ + public: + //! ctor + CMFlashClusterv2() = default; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override {} + int isValid() const override; + PHObject* CloneMe() const override { return new CMFlashClusterv2(*this); } + + //! copy content from base class + void CopyFrom( const CMFlashCluster& ) override; + + //! copy content from base class + void CopyFrom( CMFlashCluster* source ) override + { CopyFrom( *source ); } + + // + // cluster position + // + float getX() const override { return m_pos[0]; } + void setX(float x) override { m_pos[0] = x; } + float getY() const override { return m_pos[1]; } + void setY(float y) override { m_pos[1] = y; } + float getZ() const override { return m_pos[2]; } + void setZ(float z) override { m_pos[2] = z; } + unsigned int getNclusters() const override {return m_nclusters;} + void setNclusters(unsigned int n) override { m_nclusters = n;} + bool getIsRGap() { return m_isRGap; } + void setIsRGap(bool isRGap) { m_isRGap = isRGap;} + bool getIsPhiGap() { return m_isPhiGap; } + void setIsPhiGap(bool isPhiGap) { m_isPhiGap = isPhiGap;} + + // + // cluster info + // + unsigned int getAdc() const override { return m_adc; } + void setAdc(unsigned int adc) override { m_adc = adc; } + + protected: + + /// mean cluster position + float m_pos[3] = {NAN, NAN, NAN}; + + /// cluster sum adc + unsigned int m_adc = 0xFFFFFFFF; + + /// number of TPC clusters used to create this central mebrane cluster + unsigned int m_nclusters = UINT_MAX; + + /// bools to identify if meta-cluster is across sector/module gaps + bool m_isRGap = false; + bool m_isPhiGap = false; + + ClassDefOverride(CMFlashClusterv2, 1) +}; + +#endif //TRACKBASE_CMFLASHCLUSTERV2_H diff --git a/offline/packages/trackbase/CMFlashClusterv2LinkDef.h b/offline/packages/trackbase/CMFlashClusterv2LinkDef.h new file mode 100644 index 0000000000..e7df16928f --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class CMFlashClusterv2+; + +#endif From 1243b20c578c6e02978dd69e346a38d4d2f21ddc Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 14 Mar 2023 13:53:37 -0400 Subject: [PATCH 016/468] xsx --- simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h | 1 + 1 file changed, 1 insertion(+) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 41b4a74944..26f6132f25 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -21,6 +21,7 @@ class PHCompositeNode; class TH1; class TH2; class TNtuple; +class TTree; class TFile; class TrkrHitSetContainer; class TrkrHitTruthAssoc; From 733f3e3a68b773ecb3bc98b0ef80edae92c14673 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 14 Mar 2023 13:56:48 -0400 Subject: [PATCH 017/468] pull prep --- offline/packages/tpc/TpcClusterizer.cc | 145 +++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 8aa9e11a80..083cda8dcb 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -96,7 +96,45 @@ namespace }; pthread_mutex_t mythreadlock; + + std::vector clusterx; + std::vector clustery; + std::vector clusterz; + std::vector clustert; + std::vector clustert_early; + std::vector clusterE; + std::vector> hitx; + std::vector> hity; + std::vector> hitz; + std::vector> hitE; + + /* + void set_hitData(double x, double y, double z, double e){ + m_hitx.push_back(x); + m_hity.push_back(y); + m_hitz.push_back(z); + m_hitE.push_back(e); + return; + } + + void clear_hitData(){ + m_hitx.clear(); + m_hity.clear(); + m_hitz.clear(); + m_hitE.clear(); + return; + } + + void set_clustData(double x, double y, double z, double e){ + m_clustx = x; + m_clusty = y; + m_clustz = z; + m_clustE = e; + return; + } + */ + void remove_hit(double adc, int phibin, int tbin, int edge, std::multimap &all_hit_map, std::vector> &adcval) { typedef std::multimap::iterator hit_iterator; @@ -310,12 +348,26 @@ namespace if(clus_size == 1) return; // std::cout << "process list" << std::endl; + + std::vector temp_vectx; + std::vector temp_vecty; + std::vector temp_vectz; + std::vector temp_vectE; + + //std::cout << "made temp vectors" << std::endl; + + //clear_hitData(); + //::m_hitx.clear(); + //::m_hity.clear(); + //::m_hitz.clear(); + //::m_hitE.clear(); std::vector hitkeyvec; for(auto iter = ihit_list.begin(); iter != ihit_list.end();++iter){ double adc = iter->adc; if (adc <= 0) continue; + int iphi = iter->iphi + my_data.phioffset; int it = iter->it + my_data.toffset; if(iphi > phibinhi) phibinhi = iphi; @@ -323,6 +375,19 @@ namespace if(it > tbinhi) tbinhi = it; if(it < tbinlo) tbinlo = it; + double hitPhi = my_data.layergeom->get_phicenter(iphi); + + //std::cout << "working on hit " << std::distance(std::begin(ihit_list),iter) << std::endl; + + //set_hitData(radius * cos(hitPhi), radius * sin(hitPhi), my_data.layergeom->get_zcenter(it),adc); + temp_vectx.push_back(radius * cos(hitPhi)); + temp_vecty.push_back(radius * sin(hitPhi)); + temp_vectz.push_back(my_data.layergeom->get_zcenter(it)); + temp_vectE.push_back(adc); + + //std::cout << "pushed back temp vectors" << std::endl; + + // update phi sums // double phi_center = my_data.layergeom->get_phicenter(iphi); @@ -403,6 +468,9 @@ namespace // To get equivalent charge per T bin, so that summing ADC input voltage over all T bins returns total input charge, divide voltages by 2.4 for 80 ns SAMPA // Equivalent charge per T bin is then (ADU x 2200 mV / 1024) / 2.4 x (1/20) fC/mV x (1/1.6e-04) electrons/fC x (1/2000) = ADU x 0.14 + clustert_early.push_back(clust); + + // SAMPA shaping bias correction clust = clust + my_data.sampa_tbias; @@ -414,6 +482,23 @@ namespace //std::cout << "done transform" << std::endl; // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) + //set_clustData(clusx,clusy,clusz,adc_sum); + + hitx.push_back(temp_vectx); + hity.push_back(temp_vecty); + hitz.push_back(temp_vectz); + hitE.push_back(temp_vectE); + + clusterx.push_back(clusx); + clustery.push_back(clusy); + clusterz.push_back(clusz); + clustert.push_back(clust); + clusterE.push_back(adc_sum); + + // std::cout << "pushed back namespace vectors" << std::endl; + + // ::m_cluster_tree->Fill(); + if(my_data.cluster_version==3){ // Fill in the cluster details @@ -735,6 +820,28 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } + m_outfile = new TFile(m_filename.c_str(),"RECREATE"); + + m_hitEnergy = new TH1F("m_hitEnergy","",10000,0.0,1e-4); + m_cluster_hitEnergy = new TH1F("m_cluster_hitEnergy","",10000,0.0,100); + m_hit_clusterEnergy = new TH2F("m_hit_clusterEnergy","",10000,0.0,1e-4,10000,0.0,100); + + m_cluster_tree = new TTree("m_cluster_tree",""); + + m_cluster_tree->Branch("clustx",&m_clustx); + m_cluster_tree->Branch("clusty",&m_clusty); + m_cluster_tree->Branch("clustz",&m_clustz); + m_cluster_tree->Branch("clustt",&m_clustt); + m_cluster_tree->Branch("clustt_early",&m_clustt_early); + m_cluster_tree->Branch("clustE",&m_clustE); + + m_cluster_tree->Branch("hitx",&m_hitx); + m_cluster_tree->Branch("hity",&m_hity); + m_cluster_tree->Branch("hitz",&m_hitz); + m_cluster_tree->Branch("hitE",&m_hitE); + + + return Fun4AllReturnCodes::EVENT_OK; } @@ -1095,6 +1202,31 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) } } + // std::cout << "about to push back member vectors" << std::endl; + + for(int ic=0; ic<(int)clusterx.size(); ic++){ + //std::cout << "cluster number " << ic << std::endl; + + m_clustx = clusterx[ic]; + m_clusty = clustery[ic]; + m_clustz = clusterz[ic]; + m_clustt = clustert[ic]; + m_clustt_early = clustert_early[ic]; + m_clustE = clusterE[ic]; + + m_hitx = hitx[ic]; + m_hity = hity[ic]; + m_hitz = hitz[ic]; + m_hitE = hitE[ic]; + + //std::cout << "pushed back member vectors" << std::endl; + + m_cluster_tree->Fill(); + + //std::cout << "Filled tree" << std::endl; + + } + if (Verbosity() > 0) std::cout << "TPC Clusterizer found " << m_clusterlist->size() << " Clusters " << std::endl; return Fun4AllReturnCodes::EVENT_OK; @@ -1102,5 +1234,18 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) int TpcClusterizer::End(PHCompositeNode */*topNode*/) { + + m_outfile->cd(); + + m_cluster_tree->Write(); + + m_hitEnergy->Write(); + m_cluster_hitEnergy->Write(); + m_hit_clusterEnergy->Write(); + + + + m_outfile->Close(); + return Fun4AllReturnCodes::EVENT_OK; } From 6d5ee284198c35af0aec6676a5440e7883bc84c7 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 14 Mar 2023 16:55:40 -0400 Subject: [PATCH 018/468] clang format --- offline/packages/trackbase/TpcDefs.h | 91 ++++++++++++++-------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/offline/packages/trackbase/TpcDefs.h b/offline/packages/trackbase/TpcDefs.h index 927bb174a2..7ade28f4e4 100644 --- a/offline/packages/trackbase/TpcDefs.h +++ b/offline/packages/trackbase/TpcDefs.h @@ -9,7 +9,7 @@ #include "TrkrDefs.h" -#include // for uint8_t, uint16_t, uint32_t +#include // for uint8_t, uint16_t, uint32_t /** * @brief Utility functions for TPC @@ -19,80 +19,84 @@ */ namespace TpcDefs { -// hitsetkey layout: -// Tpc specific lower 16 bits -// 24 - 32 tracker id -// 16 - 24 layer -// 8 - 16 sector id -// 0 - 8 side -static const unsigned int kBitShiftSectorId __attribute__((unused)) = 8; -static const unsigned int kBitShiftSide __attribute__((unused)) = 0; - -// bit shift for hitkey -// 16 - 32 pad id -// 0 - 16 time bin -static const unsigned int kBitShiftPad __attribute__((unused)) = 16; -static const unsigned int kBitShiftTBin __attribute__((unused)) = 0; - -// max values for pad and time bin -static const uint16_t MAXPAD __attribute__((unused)) = 1024; -static const uint16_t MAXTBIN __attribute__((unused)) = 512; - -// in memory representation of TPC ADC data: 10bit ADC value as 16bit signed integer. -// This is signed to allow pedestal subtraction when needed -typedef int16_t ADCDataType; -/** + //! in memory representation of TPC ADC data: 10bit ADC value as 16bit signed integer. + // This is signed to allow pedestal subtraction when needed + typedef int16_t ADCDataType; + + //! in memory representation of BCO clock using standard 64bit sPHENIX time stamp precision + typedef uint64_t BCODataType; + + // hitsetkey layout: + // Tpc specific lower 16 bits + // 24 - 32 tracker id + // 16 - 24 layer + // 8 - 16 sector id + // 0 - 8 side + static const unsigned int kBitShiftSectorId __attribute__((unused)) = 8; + static const unsigned int kBitShiftSide __attribute__((unused)) = 0; + + // bit shift for hitkey + // 16 - 32 pad id + // 0 - 16 time bin + static const unsigned int kBitShiftPad __attribute__((unused)) = 16; + static const unsigned int kBitShiftTBin __attribute__((unused)) = 0; + + // max values for pad and time bin + static const uint16_t MAXPAD __attribute__((unused)) = 1024; + static const uint16_t MAXTBIN __attribute__((unused)) = 512; + + /** * @brief Get the sector id from hitsetkey * @param[in] hitsetkey * @param[out] sector id */ -uint8_t getSectorId(TrkrDefs::hitsetkey key); + uint8_t getSectorId(TrkrDefs::hitsetkey key); -/** + /** * @brief Get the sector id from cluskey * @param[in] cluskey * @param[out] sector id */ -uint8_t getSectorId(TrkrDefs::cluskey key); + uint8_t getSectorId(TrkrDefs::cluskey key); -/** + /** * @brief Get the side from hitsetkey * @param[in] hitsetkey * @param[out] side */ -uint8_t getSide(TrkrDefs::hitsetkey key); + uint8_t getSide(TrkrDefs::hitsetkey key); -/** + /** * @brief Get the side id from cluskey * @param[in] cluskey * @param[out] side id */ -uint8_t getSide(TrkrDefs::cluskey key); + uint8_t getSide(TrkrDefs::cluskey key); -/** + /** * @brief Get the pad index from hitkey * @param[in] hitkey * @param[out] pad index */ -uint16_t getPad(TrkrDefs::hitkey key); + uint16_t getPad(TrkrDefs::hitkey key); -/** + /** * @brief Get the time bin from hitkey * @param[in] hitkey * @param[out] time bin */ -uint16_t getTBin(TrkrDefs::hitkey key); + uint16_t getTBin(TrkrDefs::hitkey key); -/** + /** * @brief Generate a hitkey from a pad index and time bin * @param[in] pad Pad index * @param[in] tbin Time bin * @param[out] hitkey */ -TrkrDefs::hitkey genHitKey(const uint16_t pad, const uint16_t tbin); + TrkrDefs::hitkey genHitKey(const uint16_t pad, const uint16_t tbin); -/** + /** * @brief Generate a hitsetkey for the tpc * @param[in] lyr Layer index * @param[in] sector Sector index @@ -102,19 +106,18 @@ TrkrDefs::hitkey genHitKey(const uint16_t pad, const uint16_t tbin); * Generate a hitsetkey for the tpc. The tracker id is known * implicitly and used in the function. */ -TrkrDefs::hitsetkey genHitSetKey(const uint8_t lyr, const uint8_t sector, const uint8_t side); + TrkrDefs::hitsetkey genHitSetKey(const uint8_t lyr, const uint8_t sector, const uint8_t side); -/** - * @brief Generate a cluster key from indeces + /** + * @brief Generate a cluster key from indeces * @param[in] lyr Layer index * @param[in] sector Sector index * @param[in] side Side index * @param[in] clusid Cluster id * @param[out] cluskey */ -TrkrDefs::cluskey genClusKey(const uint8_t lyr, const uint8_t sector, const uint8_t side, const uint32_t clusid); - + TrkrDefs::cluskey genClusKey(const uint8_t lyr, const uint8_t sector, const uint8_t side, const uint32_t clusid); } // namespace TpcDefs -#endif //TPC_TPCDEFS_H +#endif // TPC_TPCDEFS_H From b627b6156c03b09a2687e1d6c85f4292ed6749b0 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 15 Mar 2023 01:31:05 -0400 Subject: [PATCH 019/468] make explicit local and global index separation --- offline/packages/trackbase/TrkrHitSetTpc.cc | 57 ++++++++++++++++-- offline/packages/trackbase/TrkrHitSetTpc.h | 49 +++++++++++++--- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 18 ++++-- offline/packages/trackbase/TrkrHitSetTpcv1.h | 58 +++++++++++++++---- 4 files changed, 154 insertions(+), 28 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpc.cc b/offline/packages/trackbase/TrkrHitSetTpc.cc index 895b8878dd..febef73fdd 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.cc +++ b/offline/packages/trackbase/TrkrHitSetTpc.cc @@ -23,16 +23,65 @@ void TrkrHitSetTpc::identify(std::ostream& os) const TpcDefs::ADCDataType& TrkrHitSetTpc::getTpcADC(TrkrDefs::hitkey key) { - const uint16_t pad = TpcDefs ::getPad(key); - const uint16_t tbin = TpcDefs ::getTBin(key); + std::pair local_phi_t = getLocalPhiTBin(key); - return getTpcADC(pad, tbin); + return getTpcADC(local_phi_t.first, local_phi_t.second); } const TpcDefs::ADCDataType& TrkrHitSetTpc::getTpcADC(TrkrDefs::hitkey key) const +{ + std::pair local_phi_t = getLocalPhiTBin(key); + + return getTpcADC(local_phi_t.first, local_phi_t.second); +} + +std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey key) const { const uint16_t pad = TpcDefs ::getPad(key); const uint16_t tbin = TpcDefs ::getTBin(key); + const uint8_t side = TpcDefs::getSide(getHitSetKey()); + + if (side == 0) + { + const uint16_t local_pad = pad - getPadIndexStart(); + const uint16_t local_tbin = tbin - getTBinIndexStart(); + + assert(local_pad < getNPads()); + assert(local_tbin < getTBins()); + + return std::make_pair(local_pad, local_tbin); + } + else + { + const uint16_t local_pad = getNPads() - 1 - pad + getPadIndexStart(); + const uint16_t local_tbin = -tbin + getTBinIndexStart(); + + assert(local_pad < getNPads()); + assert(local_tbin < getTBins()); + + return std::make_pair(local_pad, local_tbin); + } +} + +TrkrDefs::hitkey TrkrHitSetTpc::getHitKeyfromLocalBin( + const uint16_t local_pad, + const uint16_t local_tbin) + const +{ + const uint8_t side = TpcDefs::getSide(getHitSetKey()); + + if (side == 0) + { + const uint16_t pad = local_pad + getPadIndexStart(); + const uint16_t tbin = local_tbin + getTBinIndexStart(); + + return TpcDefs::genHitKey(pad, tbin); + } + else + { + const uint16_t pad = getNPads() - 1 - local_pad + getPadIndexStart(); + const uint16_t tbin = -local_tbin + getTBinIndexStart(); - return getTpcADC(pad, tbin); + return TpcDefs::genHitKey(pad, tbin); + } } diff --git a/offline/packages/trackbase/TrkrHitSetTpc.h b/offline/packages/trackbase/TrkrHitSetTpc.h index 8269b2c251..ae3e8b5f40 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.h +++ b/offline/packages/trackbase/TrkrHitSetTpc.h @@ -19,7 +19,7 @@ class TrkrHitSetTpc : public TrkrHitSet TrkrHitSetTpc() = default; - TrkrHitSetTpc(const unsigned int /*n_pad*/, const unsigned int /*n_tbin*/) {} + TrkrHitSetTpc(const uint16_t /*n_pad*/, const uint16_t /*n_tbin*/) {} ~TrkrHitSetTpc() override { @@ -27,30 +27,36 @@ class TrkrHitSetTpc : public TrkrHitSet virtual void identify(std::ostream& os = std::cout) const override; - virtual void Resize(const unsigned int /*n_pad*/, const unsigned int /*n_tbin*/) {} + virtual void Resize(const uint16_t /*n_pad*/, const uint16_t /*n_tbin*/) {} + + //! global -> local conversion + std::pair getLocalPhiTBin(const TrkrDefs::hitkey) const; + + //! local -> global conversion + TrkrDefs::hitkey getHitKeyfromLocalBin(const uint16_t /*local_pad*/, const uint16_t /*local_tbin*/) const; TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey); const TpcDefs::ADCDataType& getTpcADC(const TrkrDefs::hitkey) const; - virtual TpcDefs::ADCDataType& getTpcADC(const uint16_t /*pad*/, const uint16_t /*tbin*/) + virtual TpcDefs::ADCDataType& getTpcADC(const uint16_t /*local_pad*/, const uint16_t /*local_tbin*/) { static TpcDefs::ADCDataType v = 0; return v; }; - virtual const TpcDefs::ADCDataType& getTpcADC(const uint16_t /*pad*/, const uint16_t /*tbin*/) const + virtual const TpcDefs::ADCDataType& getTpcADC(const uint16_t /*local_pad*/, const uint16_t /*local_tbin*/) const { static TpcDefs::ADCDataType v = 0; return v; }; - virtual unsigned int getNPads() const + virtual uint16_t getNPads() const { return 0; } - virtual void setNPads(unsigned int /*nPads*/) + virtual void setNPads(uint16_t /*nPads*/) { } @@ -65,12 +71,39 @@ class TrkrHitSetTpc : public TrkrHitSet { } - virtual unsigned int getTBins() const + virtual uint16_t getTBins() const + { + return 0; + } + + virtual void setTBins(uint16_t /*tBins*/) + { + } + + virtual uint16_t getPadIndexStart() const + { + return 0; + } + + virtual void setPadIndexStart(uint16_t ) + { + } + + virtual TpcDefs::BCODataType getStartingBco() const + { + return 0; + } + + virtual void setStartingBco(TpcDefs::BCODataType ) + { + } + + virtual uint16_t getTBinIndexStart() const { return 0; } - virtual void setTBins(unsigned int /*tBins*/) + virtual void setTBinIndexStart(uint16_t) { } diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 407e280046..805dd6aefd 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -22,7 +22,7 @@ void TrkrHitSetTpcv1::Reset() std::fill(pad.begin(), pad.end(), 0); } } -void TrkrHitSetTpcv1::Resize(const unsigned int n_pad, const unsigned int n_tbin) +void TrkrHitSetTpcv1::Resize(const uint16_t n_pad, const uint16_t n_tbin) { if (n_pad != m_timeFrameADCData.size()) m_timeFrameADCData.resize(n_pad); @@ -38,16 +38,19 @@ void TrkrHitSetTpcv1::Resize(const unsigned int n_pad, const unsigned int n_tbin void TrkrHitSetTpcv1::identify(std::ostream& os) const { - const unsigned int layer = TrkrDefs::getLayer(m_hitSetKey); - const unsigned int trkrid = TrkrDefs::getTrkrId(m_hitSetKey); + const uint16_t layer = TrkrDefs::getLayer(m_hitSetKey); + const uint16_t trkrid = TrkrDefs::getTrkrId(m_hitSetKey); os << "TrkrHitSetTpcv1: " << " hitsetkey " << getHitSetKey() - << " TrkrId " << trkrid - << " layer " << layer + << " TrkrId: " << trkrid + << " layer: " << layer << " m_nPads: " << m_nPads << " n_tBins: " << n_tBins + << " m_padIndexStart: " << m_padIndexStart + << " m_tBinIndexStart: " << m_tBinIndexStart + << " m_StartingBCO: " << m_StartingBCO << std::endl; // for( const auto& entry : m_hits ) @@ -56,8 +59,11 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const // (entry.second)->identify(os); // } - for (unsigned int i = 0; i < m_nPads; ++i) + for (uint16_t i = 0; i < m_nPads; ++i) { + // skip empty pads + if (*std::max_element(m_timeFrameADCData[i].begin(), m_timeFrameADCData[i].end()) == 0) continue; + os << "Pad " << i << ":"; for (const auto& adc : m_timeFrameADCData[i]) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h index 685411e6d0..04ecabd6e3 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.h +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -15,7 +15,7 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc public: TrkrHitSetTpcv1() = default; - TrkrHitSetTpcv1(const unsigned int n_pad, const unsigned int n_tbin) + TrkrHitSetTpcv1(const uint16_t n_pad, const uint16_t n_tbin) : TrkrHitSetTpc(n_pad, n_tbin) { Resize(n_pad, n_tbin); @@ -27,7 +27,7 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc void identify(std::ostream& os = std::cout) const override; - void Resize(const unsigned int n_pad, const unsigned int n_tbin) override; + void Resize(const uint16_t n_pad, const uint16_t n_tbin) override; //! For ROOT TClonesArray end of event Operation void Clear(Option_t* /*option*/ = "") override { Reset(); } @@ -47,9 +47,9 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc // legacy TrkrDefs::hitkey accesses using TrkrHitSetTpc::getTpcADC; - TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) override; + TpcDefs::ADCDataType& getTpcADC(const uint16_t local_pad, const uint16_t local_tbin) override; - const TpcDefs::ADCDataType& getTpcADC(const uint16_t pad, const uint16_t tbin) const override; + const TpcDefs::ADCDataType& getTpcADC(const uint16_t local_pad, const uint16_t local_tbin) const override; ConstIterator addHitSpecificKey(const TrkrDefs::hitkey, TrkrHit*) override; @@ -64,12 +64,12 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc return m_nPads * n_tBins; } - unsigned int getNPads() const override + uint16_t getNPads() const override { return m_nPads; } - void setNPads(unsigned int nPads = 0) override + void setNPads(uint16_t nPads = 0) override { m_nPads = nPads; } @@ -84,16 +84,46 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc m_timeFrameADCData = timeFrameAdcData; } - unsigned int getTBins() const override + uint16_t getTBins() const override { return n_tBins; } - void setTBins(unsigned int tBins = 0) override + void setTBins(uint16_t tBins = 0) override { n_tBins = tBins; } + uint16_t getPadIndexStart() const override + { + return m_padIndexStart; + } + + void setPadIndexStart(uint16_t padIndexStart) override + { + m_padIndexStart = padIndexStart; + } + + TpcDefs::BCODataType getStartingBco() const override + { + return m_StartingBCO; + } + + void setStartingBco(TpcDefs::BCODataType startingBco) override + { + m_StartingBCO = startingBco; + } + + uint16_t getTBinIndexStart() const override + { + return m_tBinIndexStart; + } + + void setTBinIndexStart(uint16_t tBinIndexStart) override + { + m_tBinIndexStart = tBinIndexStart; + } + private: /// unique key for this object TrkrDefs::hitsetkey m_hitSetKey = TrkrDefs::HITSETKEYMAX; @@ -103,8 +133,16 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc // Lower level indexes are vectors of time bin TimeFrameADCDataType m_timeFrameADCData; - unsigned int m_nPads = 0; - unsigned int n_tBins = 0; + //! beam collision (BCO) clock counter at the start of the time frame + TpcDefs::BCODataType m_StartingBCO = 0; + + //! local to global index conversion + uint16_t m_padIndexStart = 0; + uint16_t m_tBinIndexStart = 0; + + //! size of the local index + uint16_t m_nPads = 0; + uint16_t n_tBins = 0; ClassDefOverride(TrkrHitSetTpcv1, 1); }; From 2362ed872c0d6b531e076d6dfcb37985cacb955d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 15 Mar 2023 02:14:49 -0400 Subject: [PATCH 020/468] init hitset --- offline/packages/trackbase/TpcDefs.h | 4 + offline/packages/trackbase/TrkrHitSetTpcv1.h | 20 +- .../g4tpc/PHG4TpcElectronDrift.cc | 179 ++++++++++++------ .../g4tpc/PHG4TpcPadPlaneReadout.h | 8 +- 4 files changed, 136 insertions(+), 75 deletions(-) diff --git a/offline/packages/trackbase/TpcDefs.h b/offline/packages/trackbase/TpcDefs.h index 7ade28f4e4..41e211e47e 100644 --- a/offline/packages/trackbase/TpcDefs.h +++ b/offline/packages/trackbase/TpcDefs.h @@ -20,6 +20,10 @@ namespace TpcDefs { + constexpr int NSides = 2; + constexpr int NSectors = 12; + constexpr int NRSectors = 3; + //! in memory representation of TPC ADC data: 10bit ADC value as 16bit signed integer. // This is signed to allow pedestal subtraction when needed typedef int16_t ADCDataType; diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h index 04ecabd6e3..cabb6f43aa 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.h +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -74,16 +74,6 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc m_nPads = nPads; } - const TimeFrameADCDataType& getTimeFrameAdcData() const override - { - return m_timeFrameADCData; - } - - void setTimeFrameAdcData(const TimeFrameADCDataType& timeFrameAdcData) override - { - m_timeFrameADCData = timeFrameAdcData; - } - uint16_t getTBins() const override { return n_tBins; @@ -124,6 +114,16 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc m_tBinIndexStart = tBinIndexStart; } + const TimeFrameADCDataType& getTimeFrameAdcData() const override + { + return m_timeFrameADCData; + } + + void setTimeFrameAdcData(const TimeFrameADCDataType& timeFrameAdcData) override + { + m_timeFrameADCData = timeFrameAdcData; + } + private: /// unique key for this object TrkrDefs::hitsetkey m_hitSetKey = TrkrDefs::HITSETKEYMAX; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 9c1a941651..808693a003 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -12,16 +12,16 @@ #include #include // for TrkrHit -#include #include #include +#include #include // for TrkrHitTruthA... #include #include -#include -#include #include +#include +#include #include #include @@ -29,8 +29,8 @@ #include #include -#include #include +#include #include // for PHParameterIn... #include @@ -202,7 +202,6 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) runNode->addNode(newNode); } - UpdateParametersWithMacro(); PHNodeIterator runIter(runNode); auto RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); @@ -262,7 +261,8 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) min_active_radius = get_double_param("min_active_radius"); max_active_radius = get_double_param("max_active_radius"); - if (Verbosity() > 0) { + if (Verbosity() > 0) + { std::cout << PHWHERE << " drift velocity " << drift_velocity << " extended_readout_time " << get_double_param("extended_readout_time") << " max time cutoff " << max_time << std::endl; } @@ -308,14 +308,14 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) // print all layers radii if (Verbosity()) { - const auto range = seggeo->get_begin_end(); + const auto range = seggeo->get_begin_end(); std::cout << "PHG4TpcElectronDrift::InitRun - layers: " << std::distance(range.first, range.second) << std::endl; int counter = 0; for (auto layeriter = range.first; layeriter != range.second; ++layeriter) { const auto radius = layeriter->second->get_radius(); - std::cout << Form( "%.3f ", radius ); - if( ++counter == 8 ) + std::cout << Form("%.3f ", radius); + if (++counter == 8) { counter = 0; std::cout << std::endl; @@ -323,33 +323,34 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } std::cout << std::endl; } - + return Fun4AllReturnCodes::EVENT_OK; } int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); - if(!m_tGeometry) + if (!m_tGeometry) { std::cout << PHWHERE << "ActsGeometry not found on node tree. Exiting" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - if (truth_clusterer == nullptr) { + if (truth_clusterer == nullptr) + { /* if (Verbosity()) std::cout << " truth clusterer was a null pointer " << std::endl; */ truth_clusterer = new TpcClusterBuilder(truthclustercontainer, m_tGeometry, seggeo); - } else { + } + else + { if (Verbosity()) std::cout << " truth clusterer was NOT a null pointer " << std::endl; } - static constexpr unsigned int print_layer = 18; truth_clusterer->is_embedded_track = false; - std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer + std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer /* std::map> truthtrack_hits; */ - // tells m_distortionMap which event to look at if (m_distortionMap) { @@ -364,16 +365,16 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) gSystem->Exit(1); } PHG4TruthInfoContainer *truthinfo = - findNode::getClass(topNode, "G4TruthInfo"); + findNode::getClass(topNode, "G4TruthInfo"); m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); - if(!m_tGeometry) - { - std::cout << PHWHERE - << "ActsGeometry not found on node tree. Exiting" - << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + if (!m_tGeometry) + { + std::cout << PHWHERE + << "ActsGeometry not found on node tree. Exiting" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits(); unsigned int count_g4hits = 0; @@ -404,21 +405,22 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ false); trkid = trkid_new; truth_clusterer->is_embedded_track = (truthinfo->isEmbeded(trkid)); - if (Verbosity() > 1000){ - std::cout << " New track " << trkid << " is embed? : " - << truth_clusterer->is_embedded_track << std::endl; + if (Verbosity() > 1000) + { + std::cout << " New track " << trkid << " is embed? : " + << truth_clusterer->is_embedded_track << std::endl; } - if (truth_clusterer->is_embedded_track) - { // build new TrkrTruthTrack + if (truth_clusterer->is_embedded_track) + { // build new TrkrTruthTrack current_track = truthtracks->getTruthTrack(trkid, truthinfo); truth_clusterer->set_current_track(current_track); - } + } } - // for very high occupancy events, accessing the TrkrHitsets on the node tree + // for very high occupancy events, accessing the TrkrHitsets on the node tree // for every drifted electron seems to be very slow - // Instead, use a temporary map to accumulate the charge from all + // Instead, use a temporary map to accumulate the charge from all // drifted electrons, then copy to the node tree later - + double eion = hiter->second->get_eion(); unsigned int n_electrons = gsl_ran_poisson(RandomGenerator.get(), eion * electrons_per_gev); // count_electrons += n_electrons; @@ -426,26 +428,27 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (Verbosity() > 100) std::cout << " new hit with t0, " << t0 << " g4hitid " << hiter->first << " eion " << eion << " n_electrons " << n_electrons - << " entry z " << hiter->second->get_z(0) << " exit z " - << hiter->second->get_z(1) << " avg z" + << " entry z " << hiter->second->get_z(0) << " exit z " + << hiter->second->get_z(1) << " avg z" << (hiter->second->get_z(0) + hiter->second->get_z(1)) / 2.0 << std::endl; - if (n_electrons == 0) { continue; } + if (n_electrons == 0) + { + continue; + } if (Verbosity() > 100) { std::cout << std::endl - << "electron drift: g4hit " << hiter->first << " created electrons: " + << "electron drift: g4hit " << hiter->first << " created electrons: " << n_electrons << " from " << eion * 1000000 << " keV" << std::endl; - std::cout << " entry x,y,z = " << hiter->second->get_x(0) << " " + std::cout << " entry x,y,z = " << hiter->second->get_x(0) << " " << hiter->second->get_y(0) << " " << hiter->second->get_z(0) - << " radius " << sqrt(pow(hiter->second->get_x(0), 2) + - pow(hiter->second->get_y(0), 2)) << std::endl; - std::cout << " exit x,y,z = " << hiter->second->get_x(1) << " " + << " radius " << sqrt(pow(hiter->second->get_x(0), 2) + pow(hiter->second->get_y(0), 2)) << std::endl; + std::cout << " exit x,y,z = " << hiter->second->get_x(1) << " " << hiter->second->get_y(1) << " " << hiter->second->get_z(1) - << " radius " << sqrt(pow(hiter->second->get_x(1), 2) + - pow(hiter->second->get_y(1), 2)) << std::endl; + << " radius " << sqrt(pow(hiter->second->get_x(1), 2) + pow(hiter->second->get_y(1), 2)) << std::endl; } for (unsigned int i = 0; i < n_electrons; i++) @@ -522,15 +525,15 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { const double phi_final_nodiff = phistart + phi_distortion; const double rad_final_nodiff = radstart + r_distortion; - deltarnodiff->Fill(radstart, rad_final_nodiff - radstart); //delta r no diffusion, just distortion - deltaphinodiff->Fill(phistart, phi_final_nodiff - phistart); //delta phi no diffusion, just distortion + deltarnodiff->Fill(radstart, rad_final_nodiff - radstart); // delta r no diffusion, just distortion + deltaphinodiff->Fill(phistart, phi_final_nodiff - phistart); // delta phi no diffusion, just distortion deltaphivsRnodiff->Fill(radstart, phi_final_nodiff - phistart); deltaRphinodiff->Fill(radstart, rad_final_nodiff * phi_final_nodiff - radstart * phistart); // Fill Diagnostic plots, written into ElectronDriftQA.root hitmapstart->Fill(x_start, y_start); // G4Hit starting positions - hitmapend->Fill(x_final, y_final); //INcludes diffusion and distortion - deltar->Fill(radstart, rad_final - radstart); //total delta r + hitmapend->Fill(x_final, y_final); // INcludes diffusion and distortion + deltar->Fill(radstart, rad_final - radstart); // total delta r deltaphi->Fill(phistart, phi_final - phistart); // total delta phi deltaz->Fill(z_start, z_distortion); // map of distortion in Z (time) } @@ -538,7 +541,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // remove electrons outside of our acceptance. Careful though, electrons from just inside 30 cm can contribute in the 1st active layer readout, so leave a little margin if (rad_final < min_active_radius - 2.0 || rad_final > max_active_radius + 1.0) - { continue; } + { + continue; + } if (Verbosity() > 1000) { @@ -553,9 +558,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) << std::endl; std::cout << " rad_final " << rad_final << " x_final " << x_final - << " y_final " << y_final - << " z_final " << z_final << " t_final " << t_final - << " zdiff " << z_final - z_start << std::endl; + << " y_final " << y_final + << " z_final " << z_final << " t_final " << t_final + << " zdiff " << z_final - z_start << std::endl; } if (Verbosity() > 0) @@ -565,8 +570,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } // this fills the cells and updates the hits in temp_hitsetcontainer for this drifted electron hitting the GEM stack padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(), - temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, - side, hiter, ntpad, nthit); + temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, + side, hiter, ntpad, nthit); } // end loop over electrons for this g4hit TrkrHitSetContainer::ConstRange single_hitset_range = single_hitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); @@ -603,7 +608,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // - if this is the last g4hit if (dump_counter >= dump_interval || count_g4hits == g4hit->size()) { - //std::cout << " dump_counter " << dump_counter << " count_g4hits " << count_g4hits << std::endl; + // std::cout << " dump_counter " << dump_counter << " count_g4hits " << count_g4hits << std::endl; double eg4hit = 0.0; TrkrHitSetContainer::ConstRange temp_hitset_range = temp_hitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); @@ -622,9 +627,57 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // find or add this hitset on the node tree TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey); - TrkrHitSetTpc * hitset = dynamic_cast(node_hitsetit->second); + TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); assert(hitset); + // ensure the hitset is prepared + { + assert(seggeo); + PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); + assert(layer_geometry); + + const int npad = layer_geometry->get_phibins() / TpcDefs::NRSectors; + const int start_pad = sector * npad; + if (hitset->getNPads()) + { + assert(hitset->getNPads() == npad); + } + else + { + hitset->setNPads(npad); + } + if (hitset->getPadIndexStart()) + { + assert(hitset->getPadIndexStart() == start_pad); + } + else + { + hitset->setPadIndexStart(start_pad); + } + + // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. + const int ntbin = layer_geometry->get_zbins(); + const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); + if (hitset->getTBins()) + { + assert(hitset->getTBins() == ntbin); + } + else + { + hitset->SetTBins(ntbin); + } + if (hitset->getTBinIndexStart()) + { + assert(hitset->getTBinIndexStart() == start_tbin); + } + else + { + hitset->setTBinIndexStart(start_tbin); + } + + + } // ensure the hitset is prepared + // get all of the hits from the temporary hitset TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits(); for (TrkrHitSet::ConstIterator temp_hit_iter = temp_hit_range.first; @@ -640,7 +693,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) << " energy " << temp_tpchit->getEnergy() << " eg4hit " << eg4hit << std::endl; eg4hit += temp_tpchit->getEnergy(); - // ecollectedhits += temp_tpchit->getEnergy(); + // ecollectedhits += temp_tpchit->getEnergy(); ncollectedhits++; } @@ -702,15 +755,16 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) ++event_num; // if doing more than one event, event_num will be incremented. - if (Verbosity() > 500) + if (Verbosity() > 500) { std::cout << " TruthTrackContainer results at end of event in PHG4TpcElectronDrift::process_event " << std::endl; truthtracks->identify(); } - if (Verbosity()>800) { + if (Verbosity() > 800) + { truth_clusterer->print(truthtracks); - truth_clusterer->print_file(truthtracks,"drift_clusters.txt"); + truth_clusterer->print_file(truthtracks, "drift_clusters.txt"); } return Fun4AllReturnCodes::EVENT_OK; @@ -780,8 +834,8 @@ void PHG4TpcElectronDrift::SetDefaultParameters() set_default_double_param("min_active_radius", 30.); // cm set_default_double_param("max_active_radius", 78.); // cm set_default_double_param("drift_velocity", 8.0 / 1000.0); // cm/ns - set_default_double_param("max_time", 13200.); //ns - set_default_double_param("extended_readout_time", 7000.); //ns + set_default_double_param("max_time", 13200.); // ns + set_default_double_param("extended_readout_time", 7000.); // ns // These are purely fudge factors, used to increase the resolution to 150 microns and 500 microns, respectively // override them from the macro to get a different resolution @@ -791,7 +845,8 @@ void PHG4TpcElectronDrift::SetDefaultParameters() return; } -PHG4TpcElectronDrift::~PHG4TpcElectronDrift() { +PHG4TpcElectronDrift::~PHG4TpcElectronDrift() +{ if (truth_clusterer != nullptr) delete truth_clusterer; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index f7e3719d14..b219726139 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -4,7 +4,9 @@ #include "PHG4TpcPadPlane.h" #include "TpcClusterBuilder.h" +#include #include + #include #include #include @@ -64,9 +66,9 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array MaxRadius; std::array Thickness; - static const int NSides = 2; - static const int NSectors = 12; - static const int NRSectors = 3; + static const int NSides = TpcDefs::NSides; + static const int NSectors = TpcDefs::NSectors; + static const int NRSectors = TpcDefs::NRSectors; std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dR; std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dPhi; From 3ee4b4f6e98e72845d60affc1a8a38d701227480 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 15 Mar 2023 02:21:47 -0400 Subject: [PATCH 021/468] compilation fix --- simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 808693a003..1fefe1cef8 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -630,7 +630,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); assert(hitset); - // ensure the hitset is prepared + // ensure the hitset is prepared and consistent { assert(seggeo); PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); @@ -664,7 +664,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } else { - hitset->SetTBins(ntbin); + hitset->setTBins(ntbin); } if (hitset->getTBinIndexStart()) { @@ -674,9 +674,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { hitset->setTBinIndexStart(start_tbin); } - - - } // ensure the hitset is prepared + } // ensure the hitset is prepared and consistent // get all of the hits from the temporary hitset TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits(); From 4edcfe4f01804f98474fa6f59beaae7057082728 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 15 Mar 2023 16:39:44 -0400 Subject: [PATCH 022/468] Changes to CM cluster matching. After discussion with Christof, not keeping and moving to using larger scale matching --- .../PHTpcCentralMembraneClusterizer.cc | 27 ++++++++++++++++--- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 13 +++++++-- offline/packages/trackbase/Makefile.am | 4 +++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index 1af516bffd..f9052d1de5 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -180,6 +180,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) // redundant to the 'adjacent row' check: if (i==j) continue; //can't match yourself. // must match to an adjacent row. if (std::abs(layer[i]-layer[j])!=1) continue; + + if( (layer[i] == 22 && layer[j] == 23) || (layer[i] == 23 && layer[j] == 22) || (layer[i] == 38 && layer[j] == 39) || (layer[i] == 39 && layer[j] == 38) ) continue; // must match clusters that are on the same side if( side[i] != side[j] ) continue; @@ -237,6 +239,14 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vectoraveenergy; std::vector avepos; std::vector nclusters; + std::vector isREdge; + + int nR2 = 0; + int nR3 = 0; + + double R2AveE = 0.0; + double R3AveE = 0.0; + for (int i=0;iFill(energy[i]); @@ -248,6 +258,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(_histos) hClustE[1]->Fill(energy[i]+energy[i_pair[i]]); aveenergy.push_back(energy[i]+energy[i_pair[i]]); + + // if( + // The pads measure phi and z accurately // They do not measure R! It is taken as the center of the padrow @@ -304,7 +317,10 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) TVector3 temppos(aveR*cos(avePhi), aveR*sin(avePhi), aveZ); avepos.push_back(temppos); nclusters.push_back(2); - + if( (layer[i] == 22 && layer[i_pair[i]] == 23) || (layer[i] == 23 && layer[i_pair[i]] == 22) || (layer[i] == 38 && layer[i_pair[i]] == 39) || (layer[i] == 39 || layer[i_pair[i]] == 38) ) isREdge.push_back(true); + else isREdge.push_back(false); + + if(Verbosity() > 0) std::cout << " layer i " << layer[i] << " energy " << energy[i] << " pos i " << pos[i].X() << " " << pos[i].Y() << " " << pos[i].Z() << " layer i_pair " << layer[i_pair[i]] << " energy i_pair " << energy[i_pair[i]] @@ -318,7 +334,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); nclusters.push_back(1); - } + if( (layer[i] == 22 && layer[i_pair[i]] == 23) || (layer[i] == 23 && layer[i_pair[i]] == 22) || (layer[i] == 38 && layer[i_pair[i]] == 39) || (layer[i] == 39 || layer[i_pair[i]] == 38) ) isREdge.push_back(true); + else isREdge.push_back(false); + } } // Loop over the vectors and put the clusters on the node tree @@ -327,13 +345,14 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) for(unsigned int iv = 0; iv setX(avepos[iv].X()); cmfc->setY(avepos[iv].Y()); cmfc->setZ(avepos[iv].Z()); cmfc->setAdc(aveenergy[iv]); cmfc->setNclusters(nclusters[iv]); + cmfc->setIsRGap(isREdge[iv]); _corrected_CMcluster_map->addClusterSpecifyKey(iv, cmfc); diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 6f9b99d619..f4704ff964 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -522,14 +522,23 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) cmitr !=clusrange.second; ++cmitr) { - const auto& [cmkey, cmclus] = *cmitr; + const auto& [cmkey, cmclus_orig] = *cmitr; + CMFlashClusterv2 *cmclus = dynamic_cast(cmclus_orig); const unsigned int nclus = cmclus->getNclusters(); + + const bool isRGap = cmclus->getIsRGap(); + // Do the static + average distortion corrections if the container was found Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); if( m_dcc_in) pos = m_distortionCorrection.get_corrected_position( pos, m_dcc_in ); TVector3 tmp_pos(pos[0], pos[1], pos[2]); + + // std::cout << "cmkey " << cmkey << " R: " << tmp_pos.Perp() << " isgap: " << isRGap << std::endl; + + if(isRGap) continue; + reco_pos.push_back(tmp_pos); reco_nclusters.push_back(nclus); diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 14b64ec067..8d2c792e09 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -31,6 +31,7 @@ pkginclude_HEADERS = \ CMFlashClusterContainer.h \ CMFlashClusterContainerv1.h \ CMFlashClusterv1.h \ + CMFlashClusterv2.h \ CMFlashDifference.h \ CMFlashDifferenceContainer.h \ CMFlashDifferenceContainerv1.h \ @@ -90,6 +91,7 @@ ROOTDICTS = \ CMFlashClusterContainerv1_Dict.cc \ CMFlashCluster_Dict.cc \ CMFlashClusterv1_Dict.cc \ + CMFlashClusterv2_Dict.cc \ CMFlashDifferenceContainer_Dict.cc \ CMFlashDifferenceContainerv1_Dict.cc \ CMFlashDifference_Dict.cc \ @@ -142,6 +144,7 @@ nobase_dist_pcm_DATA = \ CMFlashClusterContainerv1_Dict_rdict.pcm \ CMFlashCluster_Dict_rdict.pcm \ CMFlashClusterv1_Dict_rdict.pcm \ + CMFlashClusterv2_Dict_rdict.pcm \ CMFlashDifferenceContainer_Dict_rdict.pcm \ CMFlashDifferenceContainerv1_Dict_rdict.pcm \ CMFlashDifference_Dict_rdict.pcm \ @@ -194,6 +197,7 @@ libtrack_io_la_SOURCES = \ AlignmentTransformation.cc \ CMFlashClusterContainerv1.cc \ CMFlashClusterv1.cc \ + CMFlashClusterv2.cc \ CMFlashDifferenceContainerv1.cc \ CMFlashDifferencev1.cc \ ClusterErrorPara.cc \ From 33f4516bbcc25fbaaed10196f242de841339fa50 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 17 Mar 2023 12:44:55 -0400 Subject: [PATCH 023/468] progression --- .../g4eval/FillTruthRecoMatchTree.cc | 409 ++++++++++++++++++ .../g4eval/FillTruthRecoMatchTree.h | 203 +++++++++ simulation/g4simulation/g4eval/Makefile.am | 8 +- simulation/g4simulation/g4eval/Tools.cc | 200 +++++++++ simulation/g4simulation/g4eval/Tools.h | 128 ++++++ .../g4eval/TruthRecoTrackMatching.cc | 228 ++++------ .../g4eval/TruthRecoTrackMatching.h | 52 +-- 7 files changed, 1042 insertions(+), 186 deletions(-) create mode 100644 simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc create mode 100644 simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h create mode 100644 simulation/g4simulation/g4eval/Tools.cc create mode 100644 simulation/g4simulation/g4eval/Tools.h diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc new file mode 100644 index 0000000000..569e55cce9 --- /dev/null +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -0,0 +1,409 @@ +#include "FillTruthRecoMatchTree.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for PHObject +#include +#include // for PHWHERE +#include +#include +#include + +using std::cout; +using std::endl; +//____________________________________________________________________________.. +FillTruthRecoMatchTree::FillTruthRecoMatchTree(const std::string &name + , bool _fill_clusters + , const std::string _tfile_name) + : SubsysReco(name), m_fill_clusters { _fill_clusters } +{ + m_tfile = new TFile(_tfile_name.c_str(), "recreate"); + m_tfile->cd(); + m_ttree->Branch("event", &nevent); + m_ttree->Branch("nphg4_part", &nphg4_part); + m_ttree->Branch("centrality", ¢rality); + m_ttree->Branch("ntrackmatches", &nmatchtracks); + m_ttree->Branch("nphg4", &nphg4); + m_ttree->Branch("nsvtx", &nsvtx); + + m_ttree->Branch("g4M_trackid", &b_g4M_trackid); + m_ttree->Branch("g4M_nclus", &b_g4M_nclus); + m_ttree->Branch("g4M_nclusmvtx", &b_g4M_nclusmvtx); + m_ttree->Branch("g4M_nclusintt", &b_g4M_nclusintt); + m_ttree->Branch("g4M_nclustpc", &b_g4M_nclustpc); + m_ttree->Branch("g4M_nclusmvtx_matchrat", &b_g4M_nclusmvtx_matchrat); + m_ttree->Branch("g4M_nclusintt_matchrat", &b_g4M_nclusintt_matchrat); + m_ttree->Branch("g4M_nclustpc_matchrat", &b_g4M_nclustpc_matchrat); + m_ttree->Branch("g4M_pt", &b_g4M_pt); + m_ttree->Branch("g4M_px", &b_g4M_px); + m_ttree->Branch("g4M_py", &b_g4M_py); + m_ttree->Branch("g4M_pz", &b_g4M_pz); + m_ttree->Branch("g4M_clusM_i0", &b_g4M_clusM_i0); + m_ttree->Branch("g4M_clusM_i1", &b_g4M_clusM_i1); + m_ttree->Branch("g4M_clusM_layer", &b_g4M_clusM_layer); + m_ttree->Branch("g4M_clusM_x", &b_g4M_clusM_x); + m_ttree->Branch("g4M_clusM_y", &b_g4M_clusM_y); + m_ttree->Branch("g4M_clusM_z", &b_g4M_clusM_z); + m_ttree->Branch("g4M_clusM_r", &b_g4M_clusM_r); + m_ttree->Branch("g4M_clusU_i0", &b_g4M_clusU_i0); + m_ttree->Branch("g4M_clusU_i1", &b_g4M_clusU_i1); + m_ttree->Branch("g4M_clusU_layer", &b_g4M_clusU_layer); + m_ttree->Branch("g4M_clusU_x", &b_g4M_clusU_x); + m_ttree->Branch("g4M_clusU_y", &b_g4M_clusU_y); + m_ttree->Branch("g4M_clusU_z", &b_g4M_clusU_z); + m_ttree->Branch("g4M_clusU_r", &b_g4M_clusU_r); + m_ttree->Branch("svM_trackid", &b_svM_trackid); + m_ttree->Branch("svM_nclus", &b_svM_nclus); + m_ttree->Branch("svM_nclusmvtx", &b_svM_nclusmvtx); + m_ttree->Branch("svM_nclusintt", &b_svM_nclusintt); + m_ttree->Branch("svM_nclustpc", &b_svM_nclustpc); + m_ttree->Branch("svM_nclusmvtx_matchrat", &b_svM_nclusmvtx_matchrat); + m_ttree->Branch("svM_nclusintt_matchrat", &b_svM_nclusintt_matchrat); + m_ttree->Branch("svM_nclustpc_matchrat", &b_svM_nclustpc_matchrat); + m_ttree->Branch("svM_pt", &b_svM_pt); + m_ttree->Branch("svM_px", &b_svM_px); + m_ttree->Branch("svM_py", &b_svM_py); + m_ttree->Branch("svM_pz", &b_svM_pz); + m_ttree->Branch("svM_clusM_i0", &b_svM_clusM_i0); + m_ttree->Branch("svM_clusM_i1", &b_svM_clusM_i1); + m_ttree->Branch("svM_clusM_layer", &b_svM_clusM_layer); + m_ttree->Branch("svM_clusM_x", &b_svM_clusM_x); + m_ttree->Branch("svM_clusM_y", &b_svM_clusM_y); + m_ttree->Branch("svM_clusM_z", &b_svM_clusM_z); + m_ttree->Branch("svM_clusM_r", &b_svM_clusM_r); + m_ttree->Branch("svM_clusU_i0", &b_svM_clusU_i0); + m_ttree->Branch("svM_clusU_i1", &b_svM_clusU_i1); + m_ttree->Branch("svM_clusU_layer", &b_svM_clusU_layer); + m_ttree->Branch("svM_clusU_x", &b_svM_clusU_x); + m_ttree->Branch("svM_clusU_y", &b_svM_clusU_y); + m_ttree->Branch("svM_clusU_z", &b_svM_clusU_z); + m_ttree->Branch("svM_clusU_r", &b_svM_clusU_r); + m_ttree->Branch("nclus_match", &b_nclus_match); + m_ttree->Branch("g4svmatch_nclusmvtx", &b_g4svmatch_nclusmvtx); + m_ttree->Branch("g4svmatch_nclusintt", &b_g4svmatch_nclusintt); + m_ttree->Branch("g4svmatch_nclustpc", &b_g4svmatch_nclustpc); + m_ttree->Branch("g4U_trackid", &b_g4U_trackid); + m_ttree->Branch("g4U_nclus", &b_g4U_nclus); + m_ttree->Branch("g4U_nclusmvtx", &b_g4U_nclusmvtx); + m_ttree->Branch("g4U_nclusintt", &b_g4U_nclusintt); + m_ttree->Branch("g4U_nclustpc", &b_g4U_nclustpc); + m_ttree->Branch("g4U_pt", &b_g4U_pt); + m_ttree->Branch("g4U_px", &b_g4U_px); + m_ttree->Branch("g4U_py", &b_g4U_py); + m_ttree->Branch("g4U_pz", &b_g4U_pz); + m_ttree->Branch("g4U_clusU_i0", &b_g4U_clusU_i0); + m_ttree->Branch("g4U_clusU_i1", &b_g4U_clusU_i1); + m_ttree->Branch("g4U_clusU_layer", &b_g4U_clusU_layer); + m_ttree->Branch("g4U_clusU_x", &b_g4U_clusU_x); + m_ttree->Branch("g4U_clusU_y", &b_g4U_clusU_y); + m_ttree->Branch("g4U_clusU_z", &b_g4U_clusU_z); + m_ttree->Branch("g4U_clusU_r", &b_g4U_clusU_r); + m_ttree->Branch("svU_trackid", &b_svU_trackid); + m_ttree->Branch("svU_nclus", &b_svU_nclus); + m_ttree->Branch("svU_nclusmvtx", &b_svU_nclusmvtx); + m_ttree->Branch("svU_nclusintt", &b_svU_nclusintt); + m_ttree->Branch("svU_nclustpc", &b_svU_nclustpc); + m_ttree->Branch("svU_pt", &b_svU_pt); + m_ttree->Branch("svU_px", &b_svU_px); + m_ttree->Branch("svU_py", &b_svU_py); + m_ttree->Branch("svU_pz", &b_svU_pz); + m_ttree->Branch("svU_clusU_i0", &b_svU_clusU_i0); + m_ttree->Branch("svU_clusU_i1", &b_svU_clusU_i1); + m_ttree->Branch("svU_clusU_layer", &b_svU_clusU_layer); + m_ttree->Branch("svU_clusU_x", &b_svU_clusU_x); + m_ttree->Branch("svU_clusU_y", &b_svU_clusU_y); + m_ttree->Branch("svU_clusU_z", &b_svU_clusU_z); + m_ttree->Branch("svU_clusU_r", &b_svU_clusU_r); + +} + +//____________________________________________________________________________.. +FillTruthRecoMatchTree::~FillTruthRecoMatchTree() +{ +} + +//____________________________________________________________________________.. +int FillTruthRecoMatchTree::Init(PHCompositeNode *topNode) +{ + if (Verbosity()>1) topNode->print(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int FillTruthRecoMatchTree::InitRun(PHCompositeNode *topNode) +{ + if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int FillTruthRecoMatchTree::createNodes(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + + if (!dstNode) + { + std::cout << PHWHERE << " DST node is missing, quitting" << std::endl; + std::cerr << PHWHERE << " DST node is missing, quitting" << std::endl; + throw std::runtime_error("Failed to find DST node in FillTruthRecoMatchTree::createNodes"); + } + + m_EmbRecoMatchContainer = findNode::getClass(topNode,"TRKR_EMBRECOMATCHCONTAINER"); + if (!m_EmbRecoMatchContainer) { + std::cout << PHWHERE << " Cannot find node TRKR_EMBRECOMATCHCONTAINER on node tree; quitting " << std::endl; + std::cerr << PHWHERE << " Cannot find node TRKR_EMBRECOMATCHCONTAINER on node tree; quitting " << std::endl; + throw std::runtime_error(" Cannot find node TRKR_EMBRECOMATCHCONTAINER on node tree; quitting"); + } + + PHCompositeNode *svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); + if (!svtxNode) + { + svtxNode = new PHCompositeNode("SVTX"); + dstNode->addNode(svtxNode); + } + + m_PHG4TruthInfoContainer = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_PHG4TruthInfoContainer) + { + std::cout << "Could not locate G4TruthInfo node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_SvtxTrackMap = findNode::getClass(topNode, "SvtxTrackMap"); + if (!m_SvtxTrackMap) + { + std::cout << "Could not locate SvtxTrackMap node when running " + <<"\"TruthRecoTrackMatching\" module." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + + m_TruthClusterContainer = findNode::getClass(topNode, + "TRKR_TRUTHCLUSTERCONTAINER"); + if (!m_TruthClusterContainer) + { + std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_RecoClusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!m_RecoClusterContainer) + { + std::cout << "Could not locate TRKR_CLUSTER node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_TrkrTruthTrackContainer = findNode::getClass(topNode, + "TRKR_TRUTHTRACKCONTAINER"); + if (!m_TrkrTruthTrackContainer) + { + std::cout << "Could not locate TRKR_TRUTHTRACKCONTAINER node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) +{ + if (Verbosity()>5) cout << " FillTruthRecoMatchTree::process_event() " << endl; + + // fill in the event data + ++nevent; + nphg4 = m_TrkrTruthTrackContainer ->getMap().size(); + nsvtx = m_SvtxTrackMap ->size(); + ntrackmatches = m_EmbRecoMatchContainer->getMatches().size(); + // get centrality later... + + nphg4_part = 0; + const auto range = m_PHG4TruthInfoContainer->GetPrimaryParticleRange(); + for (PHG4TruthInfoContainer::ConstIterator iter = range.first; + iter != range.second; ++iter) + { nphg4_part++; } + + + // unmatched tracks are only entered once + // matches can repeat a given svtx or phg4 track, depending on the + // parameters in teh matching in filltruthrecomatchtree + // + // (1) fill unmatched phg4 + // (2) fill unmatched svtx + // (3) fill matched phg4 and svtx + for (auto& match : m_EmbRecoMatchContainer->getMatches()) { + if (match) cout << "waste" << endl; + // every match is a unique match from truth to embedded particles + /* const int gtrackID = match->idTruthTrack() ; */ + /* const unsigned int id_reco = match->idRecoTrack() ; */ + /* const unsigned short n_match = match->nClustersMatched() ; */ + /* const unsigned short n_truth = match->nClustersTruth() ; */ + /* const unsigned short n_reco = match->nClustersReco() ; */ + + /* // fill the map_TtoR */ + /* /1* PHG4ParticleSvtxMap::WeightedRecoTrackMap* entry_TtoR; *1/ */ + /* if (map_TtoR.find(gtrackID) == map_TtoR.end()) { */ + /* map_TtoR[gtrackID] = PHG4ParticleSvtxMap::WeightedRecoTrackMap{}; */ + /* } */ + /* auto& entry_TtoR = map_TtoR[gtrackID]; */ + /* float weight_TtoR = (float)n_match + (float)n_truth/100.; */ + /* if (entry_TtoR.find(weight_TtoR) == entry_TtoR.end()) { */ + /* entry_TtoR[weight_TtoR] = { id_reco }; // i.e. std::set { id_reco }; */ + /* } else { */ + /* entry_TtoR[weight_TtoR].insert(id_reco); */ + /* } */ + + /* // fill the map_RtoT */ + /* /1* SvtxPHG4ParticleMap::WeightedTruthTrackMap* entry_RtoT; *1/ */ + /* if (map_RtoT.find(id_reco) == map_RtoT.end()) { */ + /* map_RtoT[id_reco] = SvtxPHG4ParticleMap::WeightedTruthTrackMap{}; */ + /* } */ + /* auto& entry_RtoT = map_RtoT[id_reco]; */ + /* float weight_RtoT = (float)n_match + (float)n_reco/100.; */ + /* if (entry_RtoT.find(weight_RtoT) == entry_RtoT.end()) { */ + /* entry_RtoT[weight_RtoT] = { gtrackID }; // i.e. std::set { gtrackID } */ + /* } else { */ + /* entry_RtoT[weight_RtoT].insert(gtrackID); */ + /* } */ + + /* if (Verbosity() > 20) { */ + /* printf("EmbRecoMatch: gtrackID(%2i) id_reco(%2i) nclusters:match(%i),gtrack(%2i),reco(%2i)\n", */ + /* gtrackID, (int)id_reco, (int)n_match, (int)n_truth, (int)n_reco); */ + /* printf(" -> in SvtxPHG4ParticleMap {id_reco->{weight->id_true}} = {%2i->{%5.2f->%2i}}\n", */ + /* (int)id_reco, weight_RtoT, (int)gtrackID); */ + /* printf(" -> in PHG4ParticleSvtxMap {id_true->{weight->id_reco}} = {%2i->{%5.2f->%2i}}\n", */ + /* gtrackID, weight_TtoR, (int)id_reco ); */ + } + + m_ttree->Fill(); + clear_vectors(); + return Fun4AllReturnCodes::EVENT_OK; +} + +int FillTruthRecoMatchTree::End(PHCompositeNode *) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +void FillTruthRecoMatchTree::clear_vectors() { + // Tracks and clustes + // + // lables: + // tracks: + // g4M : phg4track matched + // svM : svtx_track matched + // g4U : phg4track not-matched + // svU : svtx_track not-matched + // clusters: + // clusM : matched + // clusU : unmatched + b_g4M_trackid .clear(); + b_g4M_nclus .clear(); + b_g4M_nclusmvtx .clear(); + b_g4M_nclusintt .clear(); + b_g4M_nclustpc .clear(); + b_g4M_nclusmvtx_matchrat .clear(); + b_g4M_nclusintt_matchrat .clear(); + b_g4M_nclustpc_matchrat .clear(); + b_g4M_pt .clear(); + b_g4M_px .clear(); + b_g4M_py .clear(); + b_g4M_pz .clear(); + b_g4M_clusM_i0 .clear(); + b_g4M_clusM_i1 .clear(); + b_g4M_clusM_layer .clear(); + b_g4M_clusM_x .clear(); + b_g4M_clusM_y .clear(); + b_g4M_clusM_z .clear(); + b_g4M_clusM_r .clear(); + b_g4M_clusU_i0 .clear(); + b_g4M_clusU_i1 .clear(); + b_g4M_clusU_layer .clear(); + b_g4M_clusU_x .clear(); + b_g4M_clusU_y .clear(); + b_g4M_clusU_z .clear(); + b_g4M_clusU_r .clear(); + b_svM_trackid .clear(); + b_svM_nclus .clear(); + b_svM_nclusmvtx .clear(); + b_svM_nclusintt .clear(); + b_svM_nclustpc .clear(); + b_svM_nclusmvtx_matchrat .clear(); + b_svM_nclusintt_matchrat .clear(); + b_svM_nclustpc_matchrat .clear(); + b_svM_pt .clear(); + b_svM_px .clear(); + b_svM_py .clear(); + b_svM_pz .clear(); + b_svM_clusM_i0 .clear(); + b_svM_clusM_i1 .clear(); + b_svM_clusM_layer .clear(); + b_svM_clusM_x .clear(); + b_svM_clusM_y .clear(); + b_svM_clusM_z .clear(); + b_svM_clusM_r .clear(); + b_svM_clusU_i0 .clear(); + b_svM_clusU_i1 .clear(); + b_svM_clusU_layer .clear(); + b_svM_clusU_x .clear(); + b_svM_clusU_y .clear(); + b_svM_clusU_z .clear(); + b_svM_clusU_r .clear(); + b_nclus_match .clear(); + b_g4svmatch_nclusmvtx .clear(); + b_g4svmatch_nclusintt .clear(); + b_g4svmatch_nclustpc .clear(); + b_g4U_trackid .clear(); + b_g4U_nclus .clear(); + b_g4U_nclusmvtx .clear(); + b_g4U_nclusintt .clear(); + b_g4U_nclustpc .clear(); + b_g4U_pt .clear(); + b_g4U_px .clear(); + b_g4U_py .clear(); + b_g4U_pz .clear(); + b_g4U_clusU_i0 .clear(); + b_g4U_clusU_i1 .clear(); + b_g4U_clusU_layer .clear(); + b_g4U_clusU_x .clear(); + b_g4U_clusU_y .clear(); + b_g4U_clusU_z .clear(); + b_g4U_clusU_r .clear(); + b_svU_trackid .clear(); + b_svU_nclus .clear(); + b_svU_nclusmvtx .clear(); + b_svU_nclusintt .clear(); + b_svU_nclustpc .clear(); + b_svU_pt .clear(); + b_svU_px .clear(); + b_svU_py .clear(); + b_svU_pz .clear(); + b_svU_clusU_i0 .clear(); + b_svU_clusU_i1 .clear(); + b_svU_clusU_layer .clear(); + b_svU_clusU_x .clear(); + b_svU_clusU_y .clear(); + b_svU_clusU_z .clear(); + b_svU_clusU_r .clear(); + +} diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h new file mode 100644 index 0000000000..bc13b54437 --- /dev/null +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -0,0 +1,203 @@ +#ifndef FILLTRUTHRECOMATCHTREE_H +#define FILLTRUTHRECOMATCHTREE_H + +/** + * @file trackbase/TrkrMatchDefs.h + * @author D. Stewart + * @date February 2023 + * @brief Write a TFile with a TTree with the matched tracks and (optionall) clusters + * + * read out the matched tracks from the node tree, + * look at the matched (and un-matched) tracks and plot out their + * kinematics and the locations (potentially) of the matched clusters. + * + * An entry in SvtxPHG4ParticleMap could be: + * 12 -> 41.46 -> { 2, 4 } + * -> 18.46 -> { 7 } + * which is to say, reco track id 12 has matches to truth tracks 2, 4, and + * 7. Matches 12->2 and 12->4 weighting key (41.46) indicate that there were + * 41 matched clusters, that the reco track had 46 clusters. Match 12->7 key + * (18.46) indicates that there were 18 matched clusters (and, again, the reco track had 46 clusters) + * + * Assuming that truth tracks 2, 4, and 7, were matched only to reco track 12, and + * each had 45, 44, and 47 clusters, respectively, then the corresponding entries + * in PHG4ParticleSvtxMap would be: + * 2 -> 41.45 { 12 } + * 4 -> 41.44 { 12 } + * 7 -> 18.47 { 12 } + * + */ + +#include +#include +#include + +class EmbRecoMatchContainer; +class PHCompositeNode; +class PHG4ParticleSvtxMap; +class SvtxPHG4ParticleMap; +class EmbRecoMatchContainer; +class PHCompositeNode; +class PHG4TpcCylinderGeom; +class PHG4TpcCylinderGeomContainer; +class PHG4TruthInfoContainer; +class SvtxTrack; +class SvtxTrackMap; +class TrackSeedContainer; +class TrkrCluster; +class TrkrClusterContainer; +class TrkrTruthTrack; +class TrkrTruthTrackContainer; +class TTree; +class TFile; + +class FillTruthRecoMatchTree : public SubsysReco +{ + public: + FillTruthRecoMatchTree(const std::string &name = "FillTruthRecoMatchTree", + bool _fill_clusters = false, const std::string tfile_name="trackclusmatch.root"); + + virtual ~FillTruthRecoMatchTree(); + + int Init(PHCompositeNode *) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode * /*topNode*/) override; + int End(PHCompositeNode *topNode) override; + + void clear_vectors(); + + private: + + int createNodes(PHCompositeNode *topNode); + // if looking for matched and un-matched clusters, need + // the matching criteria. + // This should match that in TruthRecoTrackMatching + double _cluster_nzwidths { 0.5 }; + double _cluster_nphiwidths { 0.5 }; + + + // contianer used to fill the other track matches + EmbRecoMatchContainer *m_EmbRecoMatchContainer {nullptr}; + PHG4TruthInfoContainer *m_PHG4TruthInfoContainer {nullptr}; + SvtxTrackMap *m_SvtxTrackMap {nullptr}; + TrkrClusterContainer *m_TruthClusterContainer {nullptr}; + TrkrClusterContainer *m_RecoClusterContainer {nullptr}; + TrkrTruthTrackContainer *m_TrkrTruthTrackContainer {nullptr}; + PHG4TpcCylinderGeomContainer *m_PHG4TpcCylinderGeomContainer {nullptr}; + + TFile* m_tfile; + TTree* m_ttree; + bool m_fill_clusters { false }; + + // Tree Branch members: + int nevent {-1}; + int nphg4 {0}; + int nsvtx {0}; + int ntrackmatches {0}; + int nphg4_part {0}; + float centrality {0.}; + + // Tracks and clustes + // + // lables: + // tracks: + // g4 : phg4track matched + // sv : svtx_track matched + // gU : phg4track not-matched + // sU : svtx_track not-matched + // clusters: + // M : matched + // U : unmatched + + // TRACKS WHICH ARE MATCHED + std::vector b_g4M_trackid {}; // g4-track-matched + std::vector b_g4M_nclus {}; + std::vector b_g4M_nclusmvtx {}; + std::vector b_g4M_nclusintt {}; + std::vector b_g4M_nclustpc {}; + std::vector b_g4M_nclusmvtx_matchrat {}; + std::vector b_g4M_nclusintt_matchrat {}; + std::vector b_g4M_nclustpc_matchrat {}; + std::vector b_g4M_pt {}; + std::vector b_g4M_px {}; + std::vector b_g4M_py {}; + std::vector b_g4M_pz {}; + std::vector b_g4M_clusM_i0 {}; // g4-track-cluster-matched + std::vector b_g4M_clusM_i1 {}; + std::vector b_g4M_clusM_layer {}; + std::vector b_g4M_clusM_x {}; + std::vector b_g4M_clusM_y {}; + std::vector b_g4M_clusM_z {}; + std::vector b_g4M_clusM_r {}; + std::vector b_g4M_clusU_i0 {}; // g4-track-cluster-unmatched + std::vector b_g4M_clusU_i1 {}; + std::vector b_g4M_clusU_layer {}; + std::vector b_g4M_clusU_x {}; + std::vector b_g4M_clusU_y {}; + std::vector b_g4M_clusU_z {}; + std::vector b_g4M_clusU_r {}; + std::vector b_svM_trackid {}; //svtx-track-matched + std::vector b_svM_nclus {}; + std::vector b_svM_nclusmvtx {}; + std::vector b_svM_nclusintt {}; + std::vector b_svM_nclustpc {}; + std::vector b_svM_nclusmvtx_matchrat {}; + std::vector b_svM_nclusintt_matchrat {}; + std::vector b_svM_nclustpc_matchrat {}; + std::vector b_svM_pt {}; + std::vector b_svM_px {}; + std::vector b_svM_py {}; + std::vector b_svM_pz {}; + std::vector b_svM_clusM_i0 {}; // svtx-track-matched-cluster-matched + std::vector b_svM_clusM_i1 {}; + std::vector b_svM_clusM_layer {}; + std::vector b_svM_clusM_x {}; + std::vector b_svM_clusM_y {}; + std::vector b_svM_clusM_z {}; + std::vector b_svM_clusM_r {}; + std::vector b_svM_clusU_i0 {}; + std::vector b_svM_clusU_i1 {}; + std::vector b_svM_clusU_layer {}; + std::vector b_svM_clusU_x {}; + std::vector b_svM_clusU_y {}; + std::vector b_svM_clusU_z {}; + std::vector b_svM_clusU_r {}; + std::vector b_nclus_match {}; // Ratios for clusters for matched tracks + std::vector b_g4svmatch_nclusmvtx {}; + std::vector b_g4svmatch_nclusintt {}; + std::vector b_g4svmatch_nclustpc {}; + std::vector b_g4U_trackid {}; // g4-track-unmatched- + std::vector b_g4U_nclus {}; + std::vector b_g4U_nclusmvtx {}; + std::vector b_g4U_nclusintt {}; + std::vector b_g4U_nclustpc {}; + std::vector b_g4U_pt {}; + std::vector b_g4U_px {}; + std::vector b_g4U_py {}; + std::vector b_g4U_pz {}; + std::vector b_g4U_clusU_i0 {}; // g4-track-unmatched-clust-unmatched + std::vector b_g4U_clusU_i1 {}; + std::vector b_g4U_clusU_layer {}; + std::vector b_g4U_clusU_x {}; + std::vector b_g4U_clusU_y {}; + std::vector b_g4U_clusU_z {}; + std::vector b_g4U_clusU_r {}; + std::vector b_svU_trackid {}; // svtx-track-unmatched + std::vector b_svU_nclus {}; + std::vector b_svU_nclusmvtx {}; + std::vector b_svU_nclusintt {}; + std::vector b_svU_nclustpc {}; + std::vector b_svU_pt {}; + std::vector b_svU_px {}; + std::vector b_svU_py {}; + std::vector b_svU_pz {}; + std::vector b_svU_clusU_i0 {}; // svtx-track-unmatched-cluster-unmatched + std::vector b_svU_clusU_i1 {}; + std::vector b_svU_clusU_layer {}; + std::vector b_svU_clusU_x {}; + std::vector b_svU_clusU_y {}; + std::vector b_svU_clusU_z {}; + std::vector b_svU_clusU_r {}; +}; + +#endif // FILLTRUTHRECOMATCHTREE_H diff --git a/simulation/g4simulation/g4eval/Makefile.am b/simulation/g4simulation/g4eval/Makefile.am index a13431069a..072ff97e27 100644 --- a/simulation/g4simulation/g4eval/Makefile.am +++ b/simulation/g4simulation/g4eval/Makefile.am @@ -6,7 +6,7 @@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ - -isystem`root-config --incdir` + -isystem`root-config --incdir` AM_LDFLAGS = \ -L$(libdir) \ @@ -47,7 +47,8 @@ pkginclude_HEADERS = \ DSTCompressor.h \ DSTEmulator.h \ EventEvaluator.h \ - FillTruthRecoMatchMap.h \ + FillTruthRecoMatchMap.h \ + FillTruthRecoMatchTree.h \ JetEvalStack.h \ JetEvaluator.h \ JetRecoEval.h \ @@ -63,6 +64,7 @@ pkginclude_HEADERS = \ SvtxTruthEval.h \ SvtxTruthRecoTableEval.h \ SvtxVertexEval.h \ + Tools.h \ TrackEvaluation.h \ TrackEvaluationContainer.h \ TrackEvaluationContainerv1.h \ @@ -94,6 +96,7 @@ libg4eval_la_SOURCES = \ DSTEmulator.cc \ EventEvaluator.cc \ FillTruthRecoMatchMap.cc \ + FillTruthRecoMatchTree.cc \ JetEvalStack.cc \ JetEvaluator.cc \ JetRecoEval.cc \ @@ -109,6 +112,7 @@ libg4eval_la_SOURCES = \ SvtxTruthEval.cc \ SvtxTruthRecoTableEval.cc \ SvtxVertexEval.cc \ + Tools.cc \ TrackEvaluation.cc \ TrackSeedTrackMapConverter.cc \ TruthRecoTrackMatching.cc diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc new file mode 100644 index 0000000000..e6f9a553d1 --- /dev/null +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -0,0 +1,200 @@ +#include "Tools.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for PHWHERE +#include +#include // for PHNode +#include +#include +#include // for PHObject +#include + +using std::cout; +using std::endl; + +namespace G4Eval { + + //Implementation of Cluster comparator + TrkrClusterComparer::TrkrClusterComparer (float _nphi_widths, float _nz_widths ) + : m_nphi_widths { _nphi_widths }, + m_nz_widths { _nz_widths } + {}; + int TrkrClusterComparer::init(PHCompositeNode* topNode, + std::string name_phg4_clusters, + std::string name_reco_clusters) + { + // fill bin/pixel sizes + // ------ MVTX data ------ + PHG4CylinderGeomContainer* geom_container_mvtx + = findNode::getClass(topNode, "CYLINDERGEOM_MVTX"); + if (!geom_container_mvtx) { + std::cout << PHWHERE << " Could not locate CYLINDERGEOM_MVTX " << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + for (int layer=0; layer<3; ++layer) { + auto layergeom = dynamic_cast + (geom_container_mvtx->GetLayerGeom(layer)); + const double pitch = layergeom->get_pixel_x(); + const double length = layergeom->get_pixel_z(); + m_phistep [layer] = pitch; + if (layer == 0) m_zstep_mvtx = length; + } + + // ------ INTT data ------ + PHG4CylinderGeomContainer* geom_container_intt + = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + if (!geom_container_intt) { + std::cout << PHWHERE << " Could not locate CYLINDERGEOM_INTT " << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + // get phi and Z steps for intt + for (int layer=3; layer<7; ++layer) { + CylinderGeomIntt* geom = + dynamic_cast(geom_container_intt->GetLayerGeom(layer)); + float pitch = geom->get_strip_y_spacing(); + m_phistep [layer] = pitch; + } + + // ------ TPC data ------ + auto geom_tpc = + findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); + if (!geom_tpc) + { + std::cout << PHWHERE << " Could not locate CYLINDERCELLGEOM_SVTX node " << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + for (int layer=7; layer<55; ++layer) { + PHG4TpcCylinderGeom *layergeom = geom_tpc->GetLayerCellGeom(layer); + if (layer==7) m_zstep_tpc = layergeom->get_zstep(); + m_phistep[layer] = layergeom->get_phistep(); + } + + m_TruthClusters = + findNode::getClass(topNode, name_phg4_clusters.c_str()); + if (!m_TruthClusters) + { + std::cout << PHWHERE << " Could not locate " << name_phg4_clusters << " node" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_RecoClusters = + findNode::getClass(topNode, name_reco_clusters.c_str()); + if (!m_TruthClusters) + { + std::cout << PHWHERE << " Could not locate " << name_reco_clusters << " node" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + return Fun4AllReturnCodes::EVENT_OK; + } + + std::pair TrkrClusterComparer::operator() + (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R) + { + layer = TrkrDefs::getLayer(key_T); + if (layer > 55) { + std::cout << " Error! Trying to compar cluster in layer > 55, " + << "which is not programmed yet!" << std::endl; + return {false, 0.}; + } + + in_mvtx = ( layer <3 ); + in_intt = (layer >2 && layer <7); + in_tpc = (layer >6 && layer <55); + + float phi_step = m_phistep[layer]; + float z_step = in_mvtx ? m_zstep_mvtx : m_zstep_tpc; + + clus_T = m_TruthClusters ->findCluster(key_T); + clus_R = m_RecoClusters ->findCluster(key_R); + + phi_T = clus_T->getPosition(0); + phi_R = clus_R->getPosition(0); + phisize_R = clus_R->getPhiSize() * phi_step; + phisize_T = clus_T->getPhiSize() * phi_step; // only for user to get, if they want + + z_T = clus_T->getPosition(1); + z_R = clus_R->getPosition(1); + + if (!in_intt) { + zsize_R = clus_R->getZSize() * z_step; + zsize_T = clus_R->getZSize() * z_step; + } + + float dphi = fabs(phi_T-phi_R); + while (dphi > M_PI) dphi = fabs(dphi-2*M_PI); + z_delta = fabs (z_T-z_R); + + float phi_stat = (m_nphi_widths * phisize_R ); + + bool is_match = (phi_delta < phi_stat); + float fit_statistic = (phi_delta / phi_stat); + if (!in_intt) { + float z_stat = (m_nz_widths * zsize_R ); + is_match = is_match && (z_delta < z_stat); + fit_statistic += z_delta / z_stat; + } + return { is_match, fit_statistic }; + } + + // Implementation of the iterable struct to get cluster keys from + // a SvtxTrack. It is used like: + // for (auto& cluskey : ClusKeyIter(svtx_track)) { + // ... // do things with cluster keys + // } + ClusKeyIter::ClusKeyIter(SvtxTrack* _track) : + track {_track} + , in_silicon { _track->get_silicon_seed()!=nullptr } + , has_tpc { _track->get_tpc_seed()!=nullptr } + , no_data { !in_silicon && !has_tpc } + { + } + + ClusKeyIter ClusKeyIter::begin() { + ClusKeyIter iter0 { track }; + if (iter0.no_data) return iter0; + if (iter0.in_silicon) { + iter0.iter = track->get_silicon_seed()->begin_cluster_keys(); + iter0.iter_end_silicon = track->get_silicon_seed()->end_cluster_keys(); + } else if (has_tpc) { + iter0.iter = track->get_tpc_seed()->begin_cluster_keys(); + } + return iter0; + } + + ClusKeyIter ClusKeyIter::end() { + ClusKeyIter iter0 { track }; + if (iter0.no_data) return iter0; + if (has_tpc) { + iter0.iter = track->get_tpc_seed()->end_cluster_keys(); + } else if (in_silicon) { + iter0.iter = track->get_silicon_seed()->end_cluster_keys(); + } + return iter0; + } + + void ClusKeyIter::operator++() { + if (no_data) return; + ++iter; + if (in_silicon && has_tpc && iter == iter_end_silicon) { + in_silicon = false; + iter = track->get_tpc_seed()->begin_cluster_keys(); + } + } + + bool ClusKeyIter::operator!=(const ClusKeyIter& rhs) { + if (no_data) return false; + return iter != rhs.iter; + } + + TrkrDefs::cluskey ClusKeyIter::operator*() { + return *iter; + } +} diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h new file mode 100644 index 0000000000..04e44baa9a --- /dev/null +++ b/simulation/g4simulation/g4eval/Tools.h @@ -0,0 +1,128 @@ +#ifndef CLUSTERMATCHTOOLS__H +#define CLUSTERMATCHTOOLS__H + +#include +#include +#include +#include +#include +/* #include */ + +class TrkrClusterContainer; +class PHCompositeNode; +class TrkrCluster; +class SvtxTrack; + +namespace G4Eval { + class TrkrClusterComparer { + + // most members are public for easy access after the node has been used + public: + TrkrClusterComparer (float _nphi_widths=0.5, float _nz_widths=0.5 ); + int init(PHCompositeNode* topNode, + std::string name_truth_clusters="TRKR_TRUTHCLUSTERCONTAINER", + std::string name_reco_clusters="TRKR_CLUSTER"); + + bool status_good {false}; + TrkrCluster* clus_T {nullptr}; + TrkrCluster* clus_R {nullptr}; + int layer; + + std::pair operator() // return pair(is_matched,how_good_match) + (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R); + + // Members that are set with each set of cluster keys that + // are passed to it. + // z and phi locations of phg4 hit (T) and Svtx hit (R) + float z_T, z_R, phi_T, phi_R; + float phisize_R, phisize_T, zsize_R, zsize_T; // sizes are in pixels/layers + float phi_delta; // abs(phi_T-phi_R) + float z_delta; // abs(z_T-z_R) + + bool in_tpc {false}; + bool in_mvtx {false}; + bool in_intt {false}; + bool in_tpot {false}; + + //z pixel sizes. n.b.: there is no z clustering in the INTT + float m_zstep_tpc {0.}; // from tpc geometry + float m_zstep_mvtx {0.}; + // TPOT not implemented yet... + + void set_nz_widths(float val) { m_nz_widths = val; }; + void set_nphi_widths(float val) { m_nphi_widths = val; }; + private: + //phi pixel sizes, got for the geometries from the topNode + std::array m_phistep {0.}; // the phistep squared + float m_nphi_widths; + float m_nz_widths; + + TrkrClusterContainer* m_TruthClusters {nullptr}; + TrkrClusterContainer* m_RecoClusters {nullptr}; + }; + + // The following is a struct to iterate over the cluster keys for a given + // StvxTrack* tracks, starting with the silicone seed and then returning + // values for the tpc seed. It is used like: + // + // for (auto& cluskey : ClusKeyIter(svtx_track)) { + // ... // do things with cluster keys + // } + struct ClusKeyIter { + typedef std::set ClusterKeySet; + typedef ClusterKeySet::iterator ClusterKeyIter; + + ClusKeyIter(SvtxTrack* _track); + // data + SvtxTrack* track; + bool in_silicon; + bool has_tpc; + bool no_data; // neither a tpc nor a silicon seed + ClusterKeyIter iter { }; + ClusterKeyIter iter_end_silicon { }; + + ClusKeyIter begin(); + ClusKeyIter end(); + void operator++(); + TrkrDefs::cluskey operator*(); + bool operator!=(const ClusKeyIter& rhs); + }; + + struct HitSetClusKeyVec { + using Vector = std::vector>; + using Iter = Vector::iterator; + + vector keys_svtx; + vector keys_phg4; + + vector bool matches_svtx; + vector bool matches_phg4; + + double find_matches(TrkrClusterCommparer&); + + int addSvtxClusters(SvtxTrack*); + int addPHG4Clusters(TrkrTruthTrack*); + + std::array svtx_cntclus_allMvtxInttTpc(); + std::array phg4_cntclus_allMvtxInttTpc(); + + std::array svtx_cntmatchclus_allMvtxInttTpc(); + std::array phg4_cntmatchclus_allMvtxInttTpc(); + + + // Does the following: + // for a given SvtxTrack or TrkrTruthTrack, + // - makes a vector of pairs: {hitsetkey, cluskey}, and sort it + // - can return pointers to first and last pair with a given hitsetkey + // - can keep track of which one's are matched and which are not + HitSetClusKeyVec(SvtxTrack*); + HitSetClusKeyVec(TrkrTruthTrack*); + std::vector< std::pair> data; + int cnt(TrkrDefs::hitsetkey); // count how many pairs have + vector #include @@ -52,15 +53,16 @@ using std::cout; TruthRecoTrackMatching::TruthRecoTrackMatching ( const unsigned short _nmincluster_match , const float _nmincluster_ratio - , const double _cutoff_dphi - , const double _same_dphi - , const double _cutoff_deta - , const double _same_deta - , const double _cluster_nzwidths - , const double _cluster_nphiwidths + , const float _cutoff_dphi + , const float _same_dphi + , const float _cutoff_deta + , const float _same_deta + , const float _cluster_nzwidths + , const float _cluster_nphiwidths , const unsigned short _max_nreco_per_truth , const unsigned short _max_ntruth_per_reco - ) : m_nmincluster_match { _nmincluster_match } // minimum number of clusters to match, default=4 + ) : m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } + , m_nmincluster_match { _nmincluster_match } // minimum number of clusters to match, default=4 , m_nmincluster_ratio { _nmincluster_ratio } // minimum ratio to match a track, default=0. // -- Track Kinematic Cuts to match -- , m_cutoff_dphi { _cutoff_dphi } // maximum |dphi|=|phi_reco-phi_truth| to search for match @@ -68,8 +70,6 @@ TruthRecoTrackMatching::TruthRecoTrackMatching , m_cutoff_deta { _cutoff_deta } // same as m_cutoff_dphi for deta , m_same_deta { _same_deta } // same as m_same_dphi for deta // cluster matching widths (how close the truth center must be reco center) - , m_cluster_nzwidths { _cluster_nzwidths } - , m_cluster_nphiwidths { _cluster_nphiwidths } // number of truth tracks allowed matched per reco track, and v. versa , m_max_nreco_per_truth { _max_nreco_per_truth } , m_max_ntruth_per_reco { _max_ntruth_per_reco } @@ -82,6 +82,10 @@ TruthRecoTrackMatching::TruthRecoTrackMatching int TruthRecoTrackMatching::InitRun(PHCompositeNode *topNode) //` { + topNode->print(); + auto init_status = m_cluster_comp.init(topNode); + if (init_status == Fun4AllReturnCodes::ABORTRUN) return init_status; + if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) { return Fun4AllReturnCodes::ABORTRUN; @@ -94,7 +98,7 @@ int TruthRecoTrackMatching::InitRun(PHCompositeNode *topNode) //` } -int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) //` +int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) { if (topnode == nullptr) { return Fun4AllReturnCodes::ABORTRUN; @@ -143,7 +147,8 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) //` // phi-0 eta-0 pT-0 index-0 // <- values wrapped from the lowest phi values // phi-1 eta-1 pT-1 index-1 // <- RECOvec wraps{}; - auto wrap_from_start = std::upper_bound(recoData.begin(), recoData.end(), (-M_PI+m_cutoff_dphi), CompRECOtoPhi()); + auto wrap_from_start = std::upper_bound(recoData.begin(), + recoData.end(), (-M_PI+m_cutoff_dphi), CompRECOtoPhi()); for (auto iter = recoData.begin(); iter != wrap_from_start; ++iter) { auto entry = *iter; // make a new copy to wrap to the other side of recoData get(entry) = get(entry) + 2*M_PI; // put the new copy on the other end @@ -178,12 +183,17 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) //` std::vector> outerbox_pairs {}; std::vector> innerbox_pairs {}; + if (topnode == nullptr) { + return Fun4AllReturnCodes::ABORTRUN; + } if (Verbosity()>70) { - std::cout << "Number of truth tracks: " << m_TrkrTruthTrackContainer->getMap().size() << std::endl; + std::cout << "Number of truth tracks: " << + m_TrkrTruthTrackContainer->getMap().size() << std::endl; for (auto& _pair : m_TrkrTruthTrackContainer->getMap()) { auto& track = _pair.second; cout << Form(" id:%2i (phi:eta:pt) (%5.2f:%5.2f:%5.2f nclus: %i)", track->getTrackid(), - track->getPhi(), track->getPseudoRapidity(), track->getPt(), (int)track->getClusters().size()) << endl; + track->getPhi(), track->getPseudoRapidity(), track->getPt(), + (int)track->getClusters().size()) << endl; } cout << " ----end-listing-truth-tracks---------- " << endl; } @@ -192,7 +202,8 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) //` auto id_true = _pair.first; auto track = _pair.second; - auto match_indices = find_box_matches(track->getPhi(), track->getPseudoRapidity(), track->getPt()); + auto match_indices = find_box_matches(track->getPhi(), + track->getPseudoRapidity(), track->getPt()); // keep track of all truth tracks (by track-id) which has been matched @@ -201,7 +212,8 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) //` if (Verbosity() > 80) { cout << Form(" T(%i) find box(%5.2f:%5.2f:%5.2f)", - (int)track->getTrackid(), track->getPhi(), track->getPseudoRapidity(), track->getPt()); + (int)track->getTrackid(), track->getPhi(), + track->getPseudoRapidity(), track->getPt()); for (auto& id_reco : match_indices.first) cout <<"->IB("<OB("< + (iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + exit(1); + } + // Initiailize the modules m_PHG4TruthInfoContainer = findNode::getClass(topNode, "G4TruthInfo"); if (!m_PHG4TruthInfoContainer) { - std::cout << "Could not locate G4TruthInfo node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate G4TruthInfo node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } m_SvtxTrackMap = findNode::getClass(topNode, "SvtxTrackMap"); if (!m_SvtxTrackMap) { - std::cout << "Could not locate SvtxTrackMap node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate SvtxTrackMap node when running " + << "\"TruthRecoTrackMatching\" module." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - m_TruthClusterContainer = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + m_TruthClusterContainer = findNode::getClass(topNode, + "TRKR_TRUTHCLUSTERCONTAINER"); if (!m_TruthClusterContainer) { - std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when " + << "running \"TruthRecoTrackMatching\" module." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } m_RecoClusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); if (!m_RecoClusterContainer) { - std::cout << "Could not locate TRKR_CLUSTER node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate TRKR_CLUSTER node when running " + <<"\"TruthRecoTrackMatching\" module." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - m_TrkrTruthTrackContainer = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + m_TrkrTruthTrackContainer = findNode::getClass(topNode, + "TRKR_TRUTHTRACKCONTAINER"); if (!m_TrkrTruthTrackContainer) { - std::cout << "Could not locate TRKR_TRUTHTRACKCONTAINER node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate TRKR_TRUTHTRACKCONTAINER node when " + << "running \"TruthRecoTrackMatching\" module." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -297,30 +326,25 @@ int TruthRecoTrackMatching::createNodes(PHCompositeNode* topNode) findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); if (!m_PHG4TpcCylinderGeomContainer) { - std::cout << "Could not locate CYLINDERCELLGEOM_SVTX node when running \"TruthRecoTrackMatching\" module." << std::endl; + std::cout << "Could not locate CYLINDERCELLGEOM_SVTX node when " + << "running \"TruthRecoTrackMatching\" module." << std::endl; /* std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; */ return Fun4AllReturnCodes::ABORTEVENT; } // note that layers 0-6, and > 55, don't work - for (int layer=7; layer<55; ++layer) { - PHG4TpcCylinderGeom *layergeom = m_PHG4TpcCylinderGeomContainer->GetLayerCellGeom(layer); - if (layer==7) m_zstep = layergeom->get_zstep(); - m_phistep[layer] = layergeom->get_phistep(); - } - - PHNodeIterator iter(topNode); - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - exit(1); - } - m_EmbRecoMatchContainer = findNode::getClass(topNode,"TRKR_EMBRECOMATCHCONTAINER"); + /* for (int layer=7; layer<55; ++layer) { */ + /* PHG4TpcCylinderGeom *layergeom = m_PHG4TpcCylinderGeomContainer->GetLayerCellGeom(layer); */ + /* if (layer==7) m_zstep = layergeom->get_zstep(); */ + /* m_phistep[layer] = layergeom->get_phistep(); */ + /* } */ + m_EmbRecoMatchContainer = findNode::getClass(topNode, + "TRKR_EMBRECOMATCHCONTAINER"); if (!m_EmbRecoMatchContainer) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto DetNode = dynamic_cast + (dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); @@ -328,7 +352,8 @@ int TruthRecoTrackMatching::createNodes(PHCompositeNode* topNode) } m_EmbRecoMatchContainer = new EmbRecoMatchContainerv1; - auto newNode = new PHIODataNode(m_EmbRecoMatchContainer, "TRKR_EMBRECOMATCHCONTAINER", "PHObject"); + auto newNode = new PHIODataNode(m_EmbRecoMatchContainer, + "TRKR_EMBRECOMATCHCONTAINER", "PHObject"); DetNode->addNode(newNode); } @@ -396,8 +421,10 @@ TruthRecoTrackMatching::find_box_matches(float truth_phi, float truth_eta, float inner_box = outer_box; if (_delta_inner_pt > 0) { // start the inner pair -- the outerbox is already sorted by pT - inner_box.first = std::lower_bound(inner_box.first, inner_box.second, truth_pt-_delta_inner_pt, CompRECOtoPt()); - inner_box.second = std::upper_bound(inner_box.first, inner_box.second, truth_pt+_delta_inner_pt, CompRECOtoPt()); + inner_box.first = std::lower_bound(inner_box.first, + inner_box.second, truth_pt-_delta_inner_pt, CompRECOtoPt()); + inner_box.second = std::upper_bound(inner_box.first, + inner_box.second, truth_pt+_delta_inner_pt, CompRECOtoPt()); } // go back to sorted by eta @@ -494,13 +521,13 @@ void TruthRecoTrackMatching::match_tracks_in_box( SvtxTrack* reco_track = m_SvtxTrackMap->get(ipair->second); - for (auto reco_ckey : ClusKeyIter(reco_track)) { + for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { ++nclus_reco; auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); if (truth_keys.count(hitsetkey) != 0) { // reco and truth cluster are in same hitsetkey-indexed subsurface. // See if they match (++nclus_match) or not (++nclus_nomatch) - if (compare_cluster_pair(truth_keys[hitsetkey], reco_ckey, hitsetkey).first) { + if (m_cluster_comp(truth_keys[hitsetkey], reco_ckey).first) { ++nclus_match; } else { ++nclus_nomatch; @@ -521,7 +548,8 @@ void TruthRecoTrackMatching::match_tracks_in_box( if ( nclus_match >= m_nmincluster_match && ( static_cast(nclus_match)/nclus_true >= m_nmincluster_ratio) ) { - poss_matches.push_back( {nclus_match, nclus_true, nclus_reco, ipair->first, ipair->second} ); + poss_matches.push_back( {nclus_match, nclus_true, nclus_reco, + ipair->first, ipair->second} ); } ++ipair; } @@ -602,53 +630,6 @@ inline float TruthRecoTrackMatching::abs_dphi (float phi0, float phi1) { return dphi; } -/* - input: TrkrCluster* truth, TrkrCluster *reco, TrkrDefs::hitsetkey, bool calc_sigma=false - pair - out: Does it match? - - */ -std::pair TruthRecoTrackMatching::compare_cluster_pair ( - TrkrDefs::cluskey key_T - , TrkrDefs::cluskey key_R - , TrkrDefs::hitsetkey hitsetkey - , bool calc_sigma -) { - auto layer = TrkrDefs::getLayer(hitsetkey); - if (layer > 55) { - cout << " Error! Trying to compar cluster in layer > 55, which is not programmed yet!" << endl; - return {false, 0.}; - } - - auto clus_T = m_TruthClusterContainer ->findCluster(key_T); - auto clus_R = m_RecoClusterContainer ->findCluster(key_R); - - const auto phi_step = m_phistep[layer]; - - const auto phi_T = clus_T->getPosition(0); - // const auto phisize_T = clus_T->getPhiSize(); // not currently used for matching - const auto phi_R = clus_R->getPosition(0); - const auto phisize_R = clus_R->getPhiSize(); - - const auto z_T = clus_T->getPosition(1); - // const auto zsize_T = clus_T->getZSize(); // not currently used for matching - const auto z_R = clus_R->getPosition(1); - const auto zsize_R = clus_R->getZSize(); - - const double phi_delta = abs_dphi (phi_T,phi_R); - const double z_delta = fabs (z_T-z_R); - - const double phi_stat = (m_cluster_nphiwidths * phi_step * phisize_R ); - const double z_stat = (m_cluster_nzwidths * m_zstep * zsize_R ); - - if ( phi_delta > phi_stat || z_delta > z_stat ) return { false, 0. }; - else if (!calc_sigma) { - return { true, 0. }; - } else { - return { true, phi_delta/phi_stat +z_delta/z_stat }; - } -} - float TruthRecoTrackMatching::sigma_CompMatchClusters(PossibleMatch& match) { auto id_true = match[PM_idtrue]; auto id_reco = match[PM_idreco]; @@ -656,7 +637,8 @@ float TruthRecoTrackMatching::sigma_CompMatchClusters(PossibleMatch& match) { auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); if (!truth_track) return std::numeric_limits::max(); std::map truth_keys; // truth cluster keys - for (auto& key : truth_track->getClusters()) truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; + for (auto& key : truth_track->getClusters()) + truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; SvtxTrack* reco_track = m_SvtxTrackMap->get(id_reco); @@ -668,10 +650,10 @@ float TruthRecoTrackMatching::sigma_CompMatchClusters(PossibleMatch& match) { double n_matches = 0.; // get the mean match values double sum_diff = 0.; - for (auto reco_ckey : ClusKeyIter(reco_track)) { + for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); if (truth_keys.count(hitsetkey) == 0) continue; - auto comp_val = compare_cluster_pair(truth_keys[hitsetkey], reco_ckey, hitsetkey, true); + auto comp_val = m_cluster_comp(truth_keys[hitsetkey], reco_ckey); if (comp_val.first) { n_matches += 1.; @@ -852,7 +834,7 @@ void TruthRecoTrackMatching::fill_tree() { SvtxTrack* reco_track = m_SvtxTrackMap->get(trkid); m_i0_reco_matched.push_back(cnt); - for (auto reco_ckey : ClusKeyIter(reco_track)) { + for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { auto cluster = m_RecoClusterContainer->findCluster(reco_ckey); Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(reco_ckey, cluster); m_layer_reco_matched .push_back(TrkrDefs::getLayer(reco_ckey)); @@ -875,7 +857,7 @@ void TruthRecoTrackMatching::fill_tree() { m_trkid_reco_notmatched.push_back(trkid); SvtxTrack* reco_track = m_SvtxTrackMap->get(trkid); m_i0_reco_notmatched.push_back(cnt); - for (auto reco_ckey : ClusKeyIter(reco_track)) { + for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { auto cluster = m_RecoClusterContainer->findCluster(reco_ckey); Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(reco_ckey, cluster); m_layer_reco_notmatched .push_back(TrkrDefs::getLayer(reco_ckey)); @@ -891,59 +873,7 @@ void TruthRecoTrackMatching::fill_tree() { ++m_event; m_diag_tree->Fill(); clear_branch_vectors(); + return; } -// Implementation of the iterable struct to get cluster keys from -// a SvtxTrack. It is used like: -// for (auto& cluskey : ClusKeyIter(svtx_track)) { -// ... // do things with cluster keys -// } -TruthRecoTrackMatching::ClusKeyIter::ClusKeyIter(SvtxTrack* _track) : - track {_track} - , in_silicon { _track->get_silicon_seed()!=nullptr } - , has_tpc { _track->get_tpc_seed()!=nullptr } - , no_data { !in_silicon && !has_tpc } -{ -} - -TruthRecoTrackMatching::ClusKeyIter TruthRecoTrackMatching::ClusKeyIter::begin() { - ClusKeyIter iter0 { track }; - if (iter0.no_data) return iter0; - if (iter0.in_silicon) { - iter0.iter = track->get_silicon_seed()->begin_cluster_keys(); - iter0.iter_end_silicon = track->get_silicon_seed()->end_cluster_keys(); - } else if (has_tpc) { - iter0.iter = track->get_tpc_seed()->begin_cluster_keys(); - } - return iter0; -} - -TruthRecoTrackMatching::ClusKeyIter TruthRecoTrackMatching::ClusKeyIter::end() { - ClusKeyIter iter0 { track }; - if (iter0.no_data) return iter0; - if (has_tpc) { - iter0.iter = track->get_tpc_seed()->end_cluster_keys(); - } else if (in_silicon) { - iter0.iter = track->get_silicon_seed()->end_cluster_keys(); - } - return iter0; -} - -void TruthRecoTrackMatching::ClusKeyIter::operator++() { - if (no_data) return; - ++iter; - if (in_silicon && has_tpc && iter == iter_end_silicon) { - in_silicon = false; - iter = track->get_tpc_seed()->begin_cluster_keys(); - } -} - -bool TruthRecoTrackMatching::ClusKeyIter::operator!=(const ClusKeyIter& rhs) { - if (no_data) return false; - return iter != rhs.iter; -} - -TrkrDefs::cluskey TruthRecoTrackMatching::ClusKeyIter::operator*() { - return *iter; -} diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h index 6a8f822457..e420c71489 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h @@ -1,6 +1,8 @@ #ifndef TRUTHTRKMATCHER__H #define TRUTHTRKMATCHER__H +#include "Tools.h" // has some G4Eval tools (TrkrClusterComparer) + #include #include #include @@ -55,12 +57,12 @@ class TruthRecoTrackMatching : public SubsysReco *--------------------------------------------------------*/ const unsigned short _nmin_match = 4 , const float _nmin_ratio = 0. - , const double _cutoff_dphi = 0.3 - , const double _same_dphi = 0.05 - , const double _cutoff_deta = 0.3 - , const double _same_deta = 0.05 - , const double _cluster_nzwidths = 0.5 - , const double _cluster_nphiwidths = 0.5 + , const float _cutoff_dphi = 0.3 + , const float _same_dphi = 0.05 + , const float _cutoff_deta = 0.3 + , const float _same_deta = 0.05 + , const float _cluster_nzwidths = 0.5 + , const float _cluster_nphiwidths = 0.5 , const unsigned short _max_nreco_per_truth = 4 , const unsigned short _max_ntruth_per_reco = 4 ); // for some output kinematis @@ -71,11 +73,12 @@ class TruthRecoTrackMatching : public SubsysReco int process_event(PHCompositeNode *) override; //` int End(PHCompositeNode *) override; + G4Eval::TrkrClusterComparer m_cluster_comp; int createNodes(PHCompositeNode* topNode); - void set_cluster_nphiwidths (float val) { m_cluster_nphiwidths = val; }; - void set_cluster_nzwidths (float val) { m_cluster_nzwidths = val; }; + void set_cluster_nphiwidths (float val) { m_cluster_comp.set_nphi_widths(val);}; + void set_cluster_nzwidths (float val) { m_cluster_comp.set_nz_widths(val);}; void set_cutoff_deta (float val) { m_cutoff_deta = val; }; void set_cutoff_dphi (float val) { m_cutoff_dphi = val; }; void set_nmin_truth_cluster_ratio (float val) { m_nmincluster_ratio = val; }; @@ -89,10 +92,12 @@ class TruthRecoTrackMatching : public SubsysReco //-------------------------------------------------- // Internal functions //-------------------------------------------------- + //-------------------------------------------------- // Constant parameters for track matching //-------------------------------------------------- + unsigned short m_nmincluster_match; // minimum of matched clustered to keep a truth to emb match float m_nmincluster_ratio; // minimum ratio of truth clustered that must be matched in reconstructed track @@ -101,15 +106,15 @@ class TruthRecoTrackMatching : public SubsysReco double m_cutoff_deta; // how far in |eta_truth-eta_reco| to match double m_same_deta; // |eta_truth-eta_reco| to auto-evaluate (is < m_cutoff_deta) - double m_cluster_nzwidths; // cutoff in *getPhiSize() in cluster for |cluster_phi_truth-cluster_phi_reco| to match - double m_cluster_nphiwidths; // same for eta + /* double m_cluster_nzwidths; // cutoff in *getPhiSize() in cluster for |cluster_phi_truth-cluster_phi_reco| to match */ + /* double m_cluster_nphiwidths; // same for eta */ unsigned short m_max_nreco_per_truth; unsigned short m_max_ntruth_per_reco; - std::array m_phistep {0.}; // the phistep squared - double m_zstep {0.}; + /* std::array m_phistep {0.}; // the phistep squared */ + /* double m_zstep {0.}; */ std::map m_nmatched_index_true {}; @@ -267,29 +272,6 @@ class TruthRecoTrackMatching : public SubsysReco void clear_branch_vectors(); void fill_tree(); - // The following is a struct to iterate over the cluster keys for a given - // StvxTrack* tracks, starting with the silicone seed and then returning - // values for the tpc seed. It is used like: - // - // for (auto& cluskey : ClusKeyIter(svtx_track)) { - // ... // do things with cluster keys - // } - struct ClusKeyIter { - ClusKeyIter(SvtxTrack* _track); - // data - SvtxTrack* track; - bool in_silicon; - bool has_tpc; - bool no_data; // neither a tpc nor a silicon seed - TrackSeed::ClusterKeyIter iter { }; - TrackSeed::ClusterKeyIter iter_end_silicon { }; - - ClusKeyIter begin(); - ClusKeyIter end(); - void operator++(); - TrkrDefs::cluskey operator*(); - bool operator!=(const ClusKeyIter& rhs); - }; }; #endif From 33c34aabf42b89f5c632d3e3de6d182dc4690117 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Mon, 20 Mar 2023 17:09:53 -0400 Subject: [PATCH 024/468] fixes with some statemnts Seeing huge numbers of MVTX tracks --- .../g4eval/FillTruthRecoMatchTree.cc | 610 +++++++++++------- .../g4eval/FillTruthRecoMatchTree.h | 242 +++---- simulation/g4simulation/g4eval/Tools.cc | 254 ++++++++ simulation/g4simulation/g4eval/Tools.h | 88 ++- .../g4eval/TruthRecoTrackMatching.cc | 148 +++-- .../g4eval/TruthRecoTrackMatching.h | 1 + 6 files changed, 902 insertions(+), 441 deletions(-) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index 569e55cce9..71a3b25150 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -24,108 +24,114 @@ using std::cout; using std::endl; //____________________________________________________________________________.. -FillTruthRecoMatchTree::FillTruthRecoMatchTree(const std::string &name - , bool _fill_clusters - , const std::string _tfile_name) - : SubsysReco(name), m_fill_clusters { _fill_clusters } +FillTruthRecoMatchTree::FillTruthRecoMatchTree( + bool _fill_clusters + , bool _fill_SvUnMatched + , float _cluster_nzwidths + , float _cluster_nphiwidths + , const std::string _tfile_name + ) + : + m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } + , m_fill_clusters { _fill_clusters } + , m_fill_SvU { _fill_SvUnMatched } { + m_cluscntr.set_comparer(&m_cluster_comp); m_tfile = new TFile(_tfile_name.c_str(), "recreate"); m_tfile->cd(); + m_ttree = new TTree("T", "Tracks (and sometimes clusters)"); + m_ttree->Branch("event", &nevent); m_ttree->Branch("nphg4_part", &nphg4_part); m_ttree->Branch("centrality", ¢rality); - m_ttree->Branch("ntrackmatches", &nmatchtracks); + m_ttree->Branch("ntrackmatches", &ntrackmatches); m_ttree->Branch("nphg4", &nphg4); m_ttree->Branch("nsvtx", &nsvtx); - m_ttree->Branch("g4M_trackid", &b_g4M_trackid); - m_ttree->Branch("g4M_nclus", &b_g4M_nclus); - m_ttree->Branch("g4M_nclusmvtx", &b_g4M_nclusmvtx); - m_ttree->Branch("g4M_nclusintt", &b_g4M_nclusintt); - m_ttree->Branch("g4M_nclustpc", &b_g4M_nclustpc); - m_ttree->Branch("g4M_nclusmvtx_matchrat", &b_g4M_nclusmvtx_matchrat); - m_ttree->Branch("g4M_nclusintt_matchrat", &b_g4M_nclusintt_matchrat); - m_ttree->Branch("g4M_nclustpc_matchrat", &b_g4M_nclustpc_matchrat); - m_ttree->Branch("g4M_pt", &b_g4M_pt); - m_ttree->Branch("g4M_px", &b_g4M_px); - m_ttree->Branch("g4M_py", &b_g4M_py); - m_ttree->Branch("g4M_pz", &b_g4M_pz); - m_ttree->Branch("g4M_clusM_i0", &b_g4M_clusM_i0); - m_ttree->Branch("g4M_clusM_i1", &b_g4M_clusM_i1); - m_ttree->Branch("g4M_clusM_layer", &b_g4M_clusM_layer); - m_ttree->Branch("g4M_clusM_x", &b_g4M_clusM_x); - m_ttree->Branch("g4M_clusM_y", &b_g4M_clusM_y); - m_ttree->Branch("g4M_clusM_z", &b_g4M_clusM_z); - m_ttree->Branch("g4M_clusM_r", &b_g4M_clusM_r); - m_ttree->Branch("g4M_clusU_i0", &b_g4M_clusU_i0); - m_ttree->Branch("g4M_clusU_i1", &b_g4M_clusU_i1); - m_ttree->Branch("g4M_clusU_layer", &b_g4M_clusU_layer); - m_ttree->Branch("g4M_clusU_x", &b_g4M_clusU_x); - m_ttree->Branch("g4M_clusU_y", &b_g4M_clusU_y); - m_ttree->Branch("g4M_clusU_z", &b_g4M_clusU_z); - m_ttree->Branch("g4M_clusU_r", &b_g4M_clusU_r); - m_ttree->Branch("svM_trackid", &b_svM_trackid); - m_ttree->Branch("svM_nclus", &b_svM_nclus); - m_ttree->Branch("svM_nclusmvtx", &b_svM_nclusmvtx); - m_ttree->Branch("svM_nclusintt", &b_svM_nclusintt); - m_ttree->Branch("svM_nclustpc", &b_svM_nclustpc); - m_ttree->Branch("svM_nclusmvtx_matchrat", &b_svM_nclusmvtx_matchrat); - m_ttree->Branch("svM_nclusintt_matchrat", &b_svM_nclusintt_matchrat); - m_ttree->Branch("svM_nclustpc_matchrat", &b_svM_nclustpc_matchrat); - m_ttree->Branch("svM_pt", &b_svM_pt); - m_ttree->Branch("svM_px", &b_svM_px); - m_ttree->Branch("svM_py", &b_svM_py); - m_ttree->Branch("svM_pz", &b_svM_pz); - m_ttree->Branch("svM_clusM_i0", &b_svM_clusM_i0); - m_ttree->Branch("svM_clusM_i1", &b_svM_clusM_i1); - m_ttree->Branch("svM_clusM_layer", &b_svM_clusM_layer); - m_ttree->Branch("svM_clusM_x", &b_svM_clusM_x); - m_ttree->Branch("svM_clusM_y", &b_svM_clusM_y); - m_ttree->Branch("svM_clusM_z", &b_svM_clusM_z); - m_ttree->Branch("svM_clusM_r", &b_svM_clusM_r); - m_ttree->Branch("svM_clusU_i0", &b_svM_clusU_i0); - m_ttree->Branch("svM_clusU_i1", &b_svM_clusU_i1); - m_ttree->Branch("svM_clusU_layer", &b_svM_clusU_layer); - m_ttree->Branch("svM_clusU_x", &b_svM_clusU_x); - m_ttree->Branch("svM_clusU_y", &b_svM_clusU_y); - m_ttree->Branch("svM_clusU_z", &b_svM_clusU_z); - m_ttree->Branch("svM_clusU_r", &b_svM_clusU_r); - m_ttree->Branch("nclus_match", &b_nclus_match); - m_ttree->Branch("g4svmatch_nclusmvtx", &b_g4svmatch_nclusmvtx); - m_ttree->Branch("g4svmatch_nclusintt", &b_g4svmatch_nclusintt); - m_ttree->Branch("g4svmatch_nclustpc", &b_g4svmatch_nclustpc); - m_ttree->Branch("g4U_trackid", &b_g4U_trackid); - m_ttree->Branch("g4U_nclus", &b_g4U_nclus); - m_ttree->Branch("g4U_nclusmvtx", &b_g4U_nclusmvtx); - m_ttree->Branch("g4U_nclusintt", &b_g4U_nclusintt); - m_ttree->Branch("g4U_nclustpc", &b_g4U_nclustpc); - m_ttree->Branch("g4U_pt", &b_g4U_pt); - m_ttree->Branch("g4U_px", &b_g4U_px); - m_ttree->Branch("g4U_py", &b_g4U_py); - m_ttree->Branch("g4U_pz", &b_g4U_pz); - m_ttree->Branch("g4U_clusU_i0", &b_g4U_clusU_i0); - m_ttree->Branch("g4U_clusU_i1", &b_g4U_clusU_i1); - m_ttree->Branch("g4U_clusU_layer", &b_g4U_clusU_layer); - m_ttree->Branch("g4U_clusU_x", &b_g4U_clusU_x); - m_ttree->Branch("g4U_clusU_y", &b_g4U_clusU_y); - m_ttree->Branch("g4U_clusU_z", &b_g4U_clusU_z); - m_ttree->Branch("g4U_clusU_r", &b_g4U_clusU_r); - m_ttree->Branch("svU_trackid", &b_svU_trackid); - m_ttree->Branch("svU_nclus", &b_svU_nclus); - m_ttree->Branch("svU_nclusmvtx", &b_svU_nclusmvtx); - m_ttree->Branch("svU_nclusintt", &b_svU_nclusintt); - m_ttree->Branch("svU_nclustpc", &b_svU_nclustpc); - m_ttree->Branch("svU_pt", &b_svU_pt); - m_ttree->Branch("svU_px", &b_svU_px); - m_ttree->Branch("svU_py", &b_svU_py); - m_ttree->Branch("svU_pz", &b_svU_pz); - m_ttree->Branch("svU_clusU_i0", &b_svU_clusU_i0); - m_ttree->Branch("svU_clusU_i1", &b_svU_clusU_i1); - m_ttree->Branch("svU_clusU_layer", &b_svU_clusU_layer); - m_ttree->Branch("svU_clusU_x", &b_svU_clusU_x); - m_ttree->Branch("svU_clusU_y", &b_svU_clusU_y); - m_ttree->Branch("svU_clusU_z", &b_svU_clusU_z); - m_ttree->Branch("svU_clusU_r", &b_svU_clusU_r); + m_ttree->Branch("G4M_trackid", &b_G4M_trackid); + m_ttree->Branch("G4M_nclus", &b_G4M_nclus); + m_ttree->Branch("G4M_nclusmvtx", &b_G4M_nclusmvtx); + m_ttree->Branch("G4M_nclusintt", &b_G4M_nclusintt); + m_ttree->Branch("G4M_nclustpc", &b_G4M_nclustpc); + m_ttree->Branch("G4M_nclus_matchrat", &b_G4M_nclus_matchrat); + m_ttree->Branch("G4M_nclusmvtx_matchrat", &b_G4M_nclusmvtx_matchrat); + m_ttree->Branch("G4M_nclusintt_matchrat", &b_G4M_nclusintt_matchrat); + m_ttree->Branch("G4M_nclustpc_matchrat", &b_G4M_nclustpc_matchrat); + m_ttree->Branch("G4M_pt", &b_G4M_pt); + m_ttree->Branch("G4M_phi", &b_G4M_phi); + m_ttree->Branch("G4M_eta", &b_G4M_eta); + m_ttree->Branch("SvM_trackid", &b_SvM_trackid); + m_ttree->Branch("SvM_nclus", &b_SvM_nclus); + m_ttree->Branch("SvM_nclusmvtx", &b_SvM_nclusmvtx); + m_ttree->Branch("SvM_nclusintt", &b_SvM_nclusintt); + m_ttree->Branch("SvM_nclustpc", &b_SvM_nclustpc); + m_ttree->Branch("SvM_nclus_matchrat", &b_SvM_nclus_matchrat); + m_ttree->Branch("SvM_nclusmvtx_matchrat", &b_SvM_nclusmvtx_matchrat); + m_ttree->Branch("SvM_nclusintt_matchrat", &b_SvM_nclusintt_matchrat); + m_ttree->Branch("SvM_nclustpc_matchrat", &b_SvM_nclustpc_matchrat); + m_ttree->Branch("SvM_pt", &b_SvM_pt); + m_ttree->Branch("SvM_phi", &b_SvM_phi); + m_ttree->Branch("SvM_eta", &b_SvM_eta); + if (m_fill_clusters) { + m_ttree->Branch("clusM_i0", &b_clusM_i0); + m_ttree->Branch("clusM_i1", &b_clusM_i1); + m_ttree->Branch("clusM_layer", &b_clusM_layer); + m_ttree->Branch("clusM_x", &b_clusM_x); + m_ttree->Branch("clusM_y", &b_clusM_y); + m_ttree->Branch("clusM_z", &b_clusM_z); + m_ttree->Branch("clusM_r", &b_clusM_r); + m_ttree->Branch("G4M_clusU_i0", &b_G4M_clusU_i0); + m_ttree->Branch("G4M_clusU_i1", &b_G4M_clusU_i1); + m_ttree->Branch("G4M_clusU_layer", &b_G4M_clusU_layer); + m_ttree->Branch("G4M_clusU_x", &b_G4M_clusU_x); + m_ttree->Branch("G4M_clusU_y", &b_G4M_clusU_y); + m_ttree->Branch("G4M_clusU_z", &b_G4M_clusU_z); + m_ttree->Branch("G4M_clusU_r", &b_G4M_clusU_r); + m_ttree->Branch("SvM_clusU_i0", &b_SvM_clusU_i0); + m_ttree->Branch("SvM_clusU_i1", &b_SvM_clusU_i1); + m_ttree->Branch("SvM_clusU_layer", &b_SvM_clusU_layer); + m_ttree->Branch("SvM_clusU_x", &b_SvM_clusU_x); + m_ttree->Branch("SvM_clusU_y", &b_SvM_clusU_y); + m_ttree->Branch("SvM_clusU_z", &b_SvM_clusU_z); + m_ttree->Branch("SvM_clusU_r", &b_SvM_clusU_r); + } + m_ttree->Branch("G4U_trackid", &b_G4U_trackid); + m_ttree->Branch("G4U_nclus", &b_G4U_nclus); + m_ttree->Branch("G4U_nclusmvtx", &b_G4U_nclusmvtx); + m_ttree->Branch("G4U_nclusintt", &b_G4U_nclusintt); + m_ttree->Branch("G4U_nclustpc", &b_G4U_nclustpc); + m_ttree->Branch("G4U_pt", &b_G4U_pt); + m_ttree->Branch("G4U_phi", &b_G4U_phi); + m_ttree->Branch("G4U_eta", &b_G4U_eta); + if (m_fill_SvU) { + m_ttree->Branch("SvU_trackid", &b_SvU_trackid); + m_ttree->Branch("SvU_nclus", &b_SvU_nclus); + m_ttree->Branch("SvU_nclusmvtx", &b_SvU_nclusmvtx); + m_ttree->Branch("SvU_nclusintt", &b_SvU_nclusintt); + m_ttree->Branch("SvU_nclustpc", &b_SvU_nclustpc); + m_ttree->Branch("SvU_pt", &b_SvU_pt); + m_ttree->Branch("SvU_phi", &b_SvU_phi); + m_ttree->Branch("SvU_eta", &b_SvU_eta); + } + if (m_fill_clusters) { + m_ttree->Branch("G4U_clusU_i0", &b_G4U_clusU_i0); + m_ttree->Branch("G4U_clusU_i1", &b_G4U_clusU_i1); + m_ttree->Branch("G4U_clusU_layer", &b_G4U_clusU_layer); + m_ttree->Branch("G4U_clusU_x", &b_G4U_clusU_x); + m_ttree->Branch("G4U_clusU_y", &b_G4U_clusU_y); + m_ttree->Branch("G4U_clusU_z", &b_G4U_clusU_z); + m_ttree->Branch("G4U_clusU_r", &b_G4U_clusU_r); + if (m_fill_SvU) { + m_ttree->Branch("SvU_clusU_i0", &b_SvU_clusU_i0); + m_ttree->Branch("SvU_clusU_i1", &b_SvU_clusU_i1); + m_ttree->Branch("SvU_clusU_layer", &b_SvU_clusU_layer); + m_ttree->Branch("SvU_clusU_x", &b_SvU_clusU_x); + m_ttree->Branch("SvU_clusU_y", &b_SvU_clusU_y); + m_ttree->Branch("SvU_clusU_z", &b_SvU_clusU_z); + m_ttree->Branch("SvU_clusU_r", &b_SvU_clusU_r); + } + } + } @@ -137,7 +143,10 @@ FillTruthRecoMatchTree::~FillTruthRecoMatchTree() //____________________________________________________________________________.. int FillTruthRecoMatchTree::Init(PHCompositeNode *topNode) { - if (Verbosity()>1) topNode->print(); + if (Verbosity()>1) { + std::cout << " Beginning FillTruthRecoMatchTree " << std::endl; + topNode->print(); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -145,6 +154,9 @@ int FillTruthRecoMatchTree::Init(PHCompositeNode *topNode) //____________________________________________________________________________.. int FillTruthRecoMatchTree::InitRun(PHCompositeNode *topNode) { + auto init_status = m_cluster_comp.init(topNode); + if (init_status == Fun4AllReturnCodes::ABORTRUN) return init_status; + if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) { return Fun4AllReturnCodes::ABORTEVENT; @@ -197,22 +209,22 @@ int FillTruthRecoMatchTree::createNodes(PHCompositeNode *topNode) } - m_TruthClusterContainer = findNode::getClass(topNode, - "TRKR_TRUTHCLUSTERCONTAINER"); - if (!m_TruthClusterContainer) - { - std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when running " - << "\"TruthRecoTrackMatching\" module." << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } + /* m_TruthClusterContainer = findNode::getClass(topNode, */ + /* "TRKR_TRUTHCLUSTERCONTAINER"); */ + /* if (!m_TruthClusterContainer) */ + /* { */ + /* std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when running " */ + /* << "\"TruthRecoTrackMatching\" module." << std::endl; */ + /* return Fun4AllReturnCodes::ABORTEVENT; */ + /* } */ - m_RecoClusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); - if (!m_RecoClusterContainer) - { - std::cout << "Could not locate TRKR_CLUSTER node when running " - << "\"TruthRecoTrackMatching\" module." << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } + /* m_RecoClusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); */ + /* if (!m_RecoClusterContainer) */ + /* { */ + /* std::cout << "Could not locate TRKR_CLUSTER node when running " */ + /* << "\"TruthRecoTrackMatching\" module." << std::endl; */ + /* return Fun4AllReturnCodes::ABORTEVENT; */ + /* } */ m_TrkrTruthTrackContainer = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); @@ -251,48 +263,155 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) // (1) fill unmatched phg4 // (2) fill unmatched svtx // (3) fill matched phg4 and svtx + clear_vectors(); + int index_G4M_clusU {0}; + int index_SvM_clusU {0}; + int i_matched {0}; + int index_G4U_clusU {0}; + int index_SvU_clusU {0}; + for (auto& match : m_EmbRecoMatchContainer->getMatches()) { - if (match) cout << "waste" << endl; - // every match is a unique match from truth to embedded particles - /* const int gtrackID = match->idTruthTrack() ; */ - /* const unsigned int id_reco = match->idRecoTrack() ; */ - /* const unsigned short n_match = match->nClustersMatched() ; */ - /* const unsigned short n_truth = match->nClustersTruth() ; */ - /* const unsigned short n_reco = match->nClustersReco() ; */ - - /* // fill the map_TtoR */ - /* /1* PHG4ParticleSvtxMap::WeightedRecoTrackMap* entry_TtoR; *1/ */ - /* if (map_TtoR.find(gtrackID) == map_TtoR.end()) { */ - /* map_TtoR[gtrackID] = PHG4ParticleSvtxMap::WeightedRecoTrackMap{}; */ - /* } */ - /* auto& entry_TtoR = map_TtoR[gtrackID]; */ - /* float weight_TtoR = (float)n_match + (float)n_truth/100.; */ - /* if (entry_TtoR.find(weight_TtoR) == entry_TtoR.end()) { */ - /* entry_TtoR[weight_TtoR] = { id_reco }; // i.e. std::set { id_reco }; */ - /* } else { */ - /* entry_TtoR[weight_TtoR].insert(id_reco); */ - /* } */ - - /* // fill the map_RtoT */ - /* /1* SvtxPHG4ParticleMap::WeightedTruthTrackMap* entry_RtoT; *1/ */ - /* if (map_RtoT.find(id_reco) == map_RtoT.end()) { */ - /* map_RtoT[id_reco] = SvtxPHG4ParticleMap::WeightedTruthTrackMap{}; */ - /* } */ - /* auto& entry_RtoT = map_RtoT[id_reco]; */ - /* float weight_RtoT = (float)n_match + (float)n_reco/100.; */ - /* if (entry_RtoT.find(weight_RtoT) == entry_RtoT.end()) { */ - /* entry_RtoT[weight_RtoT] = { gtrackID }; // i.e. std::set { gtrackID } */ - /* } else { */ - /* entry_RtoT[weight_RtoT].insert(gtrackID); */ - /* } */ - - /* if (Verbosity() > 20) { */ - /* printf("EmbRecoMatch: gtrackID(%2i) id_reco(%2i) nclusters:match(%i),gtrack(%2i),reco(%2i)\n", */ - /* gtrackID, (int)id_reco, (int)n_match, (int)n_truth, (int)n_reco); */ - /* printf(" -> in SvtxPHG4ParticleMap {id_reco->{weight->id_true}} = {%2i->{%5.2f->%2i}}\n", */ - /* (int)id_reco, weight_RtoT, (int)gtrackID); */ - /* printf(" -> in PHG4ParticleSvtxMap {id_true->{weight->id_reco}} = {%2i->{%5.2f->%2i}}\n", */ - /* gtrackID, weight_TtoR, (int)id_reco ); */ + + unsigned int g4_trkid = match->idTruthTrack(); + int sv_trkid = match->idRecoTrack(); + + auto g4trk = m_TrkrTruthTrackContainer->getTruthTrack(g4_trkid); + auto svtrk = m_SvtxTrackMap->get(sv_trkid); + + b_G4M_trackid .push_back(g4_trkid); + b_G4M_pt .push_back(g4trk->getPt()); + b_G4M_eta .push_back(g4trk->getPseudoRapidity()); + b_G4M_phi .push_back(g4trk->getPhi()); + + b_SvM_trackid .push_back(sv_trkid); + b_SvM_pt .push_back(svtrk->get_pt()); + b_SvM_eta .push_back(svtrk->get_eta()); + b_SvM_phi .push_back(svtrk->get_phi()); + + m_cluscntr.addClusKeys( g4trk ); + m_cluscntr.addClusKeys( svtrk ); + m_cluscntr.find_matches(); + + auto cnt = m_cluscntr.phg4_cntclus(); + b_G4M_nclus .push_back( cnt[4] ); + b_G4M_nclusmvtx .push_back( cnt[0] ); + b_G4M_nclusintt .push_back( cnt[1] ); + b_G4M_nclustpc .push_back( cnt[2] ); + auto cnt_match = m_cluscntr.phg4_cnt_matchedclus(); + b_G4M_nclus_matchrat .push_back( (float)cnt_match[4] / cnt[4] ); + b_G4M_nclusmvtx_matchrat .push_back( (float)cnt_match[0] / cnt[0] ); + b_G4M_nclusintt_matchrat .push_back( (float)cnt_match[1] / cnt[1] ); + b_G4M_nclustpc_matchrat .push_back( (float)cnt_match[2] / cnt[2] ); + + cnt = m_cluscntr.svtx_cntclus(); + b_SvM_nclus .push_back( cnt[4] ); + b_SvM_nclusmvtx .push_back( cnt[0] ); + b_SvM_nclusintt .push_back( cnt[1] ); + b_SvM_nclustpc .push_back( cnt[2] ); + cnt_match = m_cluscntr.svtx_cnt_matchedclus(); + b_SvM_nclus_matchrat .push_back( (float)cnt_match[4] / cnt[4] ); + b_SvM_nclusmvtx_matchrat .push_back( (float)cnt_match[0] / cnt[0] ); + b_SvM_nclusintt_matchrat .push_back( (float)cnt_match[1] / cnt[1] ); + b_SvM_nclustpc_matchrat .push_back( (float)cnt_match[2] / cnt[2] ); + + if (m_fill_clusters) { + // clusters only in G4 matched tracks (i.e. by definition, unmatched clusters) + auto clusters = m_cluscntr.phg4_clusloc_unmatched(); + b_G4M_clusU_i0.push_back(index_G4M_clusU); + index_G4M_clusU += clusters.size(); + b_G4M_clusU_i1.push_back(index_G4M_clusU); + for (auto& loc : clusters) { + b_G4M_clusU_layer.push_back(loc.first); + b_G4M_clusU_x.push_back(loc.second[0]); + b_G4M_clusU_y.push_back(loc.second[1]); + b_G4M_clusU_z.push_back(loc.second[2]); + b_G4M_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + } + + // Svtx only (i.e. unmatched) clusters + clusters = m_cluscntr.svtx_clusloc_unmatched(); + b_SvM_clusU_i0.push_back(index_SvM_clusU); + index_SvM_clusU += clusters.size(); + b_SvM_clusU_i1.push_back(index_SvM_clusU); + for (auto& loc : clusters) { + b_SvM_clusU_layer.push_back(loc.first); + b_SvM_clusU_x.push_back(loc.second[0]); + b_SvM_clusU_y.push_back(loc.second[1]); + b_SvM_clusU_z.push_back(loc.second[2]); + b_SvM_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + } + + // Matched clusters + clusters = m_cluscntr.clusloc_matched(); + b_clusM_i0.push_back(i_matched); + i_matched += clusters.size(); + b_clusM_i1.push_back(i_matched); + for (auto& loc : clusters) { + b_clusM_layer.push_back(loc.first); + b_clusM_x.push_back(loc.second[0]); + b_clusM_y.push_back(loc.second[1]); + b_clusM_z.push_back(loc.second[2]); + b_clusM_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + } + } + } + + // fill in un-matched PHG4 tracks + for (auto& g4_trkid : m_EmbRecoMatchContainer->ids_TruthUnmatched()) { + auto g4trk = m_TrkrTruthTrackContainer->getTruthTrack(g4_trkid); + b_G4U_trackid .push_back(g4_trkid); + b_G4U_pt .push_back(g4trk->getPt()); + b_G4U_eta .push_back(g4trk->getPseudoRapidity()); + b_G4U_phi .push_back(g4trk->getPhi()); + + m_cluscntr.addClusKeys( g4trk ); + auto cnt = m_cluscntr.phg4_cntclus(); + b_G4U_nclus .push_back( cnt[4] ); + b_G4U_nclusmvtx .push_back( cnt[0] ); + b_G4U_nclusintt .push_back( cnt[1] ); + b_G4U_nclustpc .push_back( cnt[2] ); + if (m_fill_clusters) { + auto clusters = m_cluscntr.phg4_clusloc_all(); + b_G4U_clusU_i0.push_back(index_G4U_clusU); + index_G4U_clusU += clusters.size(); + b_G4U_clusU_i1.push_back(index_G4U_clusU); + for (auto& loc : clusters) { + b_G4U_clusU_layer.push_back(loc.first); + b_G4U_clusU_x.push_back(loc.second[0]); + b_G4U_clusU_y.push_back(loc.second[1]); + b_G4U_clusU_z.push_back(loc.second[2]); + b_G4U_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + } + } + } + + if (m_fill_SvU) { + for (auto sv_trkid : G4Eval::unmatchedSvtxTrkIds(m_EmbRecoMatchContainer, m_SvtxTrackMap)) { + auto svtrk = m_SvtxTrackMap->get(sv_trkid); + b_SvU_trackid .push_back(sv_trkid); + b_SvU_pt .push_back(svtrk->get_pt()); + b_SvU_eta .push_back(svtrk->get_eta()); + b_SvU_phi .push_back(svtrk->get_phi()); + m_cluscntr.addClusKeys( svtrk ); + auto cnt = m_cluscntr.svtx_cntclus(); + b_SvU_nclus .push_back( cnt[4] ); + b_SvU_nclusmvtx .push_back( cnt[0] ); + b_SvU_nclusintt .push_back( cnt[1] ); + b_SvU_nclustpc .push_back( cnt[2] ); + } + if (m_fill_clusters) { + auto clusters = m_cluscntr.svtx_clusloc_all(); + b_SvU_clusU_i0.push_back (index_SvU_clusU); + index_SvU_clusU += clusters.size(); + b_SvU_clusU_i1.push_back (index_SvU_clusU); + for (auto& loc : clusters) { + b_SvU_clusU_layer.push_back(loc.first); + b_SvU_clusU_x.push_back(loc.second[0]); + b_SvU_clusU_y.push_back(loc.second[1]); + b_SvU_clusU_z.push_back(loc.second[2]); + b_SvU_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + } + } } m_ttree->Fill(); @@ -302,108 +421,101 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) int FillTruthRecoMatchTree::End(PHCompositeNode *) { + if (Verbosity()>2) std::cout << PHWHERE << ": ending FillTruthRecoMatchTree" << std::endl; + m_tfile->cd(); + m_ttree->Write(); + m_tfile->Save(); + m_tfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } void FillTruthRecoMatchTree::clear_vectors() { // Tracks and clustes - // - // lables: - // tracks: - // g4M : phg4track matched - // svM : svtx_track matched - // g4U : phg4track not-matched - // svU : svtx_track not-matched - // clusters: - // clusM : matched - // clusU : unmatched - b_g4M_trackid .clear(); - b_g4M_nclus .clear(); - b_g4M_nclusmvtx .clear(); - b_g4M_nclusintt .clear(); - b_g4M_nclustpc .clear(); - b_g4M_nclusmvtx_matchrat .clear(); - b_g4M_nclusintt_matchrat .clear(); - b_g4M_nclustpc_matchrat .clear(); - b_g4M_pt .clear(); - b_g4M_px .clear(); - b_g4M_py .clear(); - b_g4M_pz .clear(); - b_g4M_clusM_i0 .clear(); - b_g4M_clusM_i1 .clear(); - b_g4M_clusM_layer .clear(); - b_g4M_clusM_x .clear(); - b_g4M_clusM_y .clear(); - b_g4M_clusM_z .clear(); - b_g4M_clusM_r .clear(); - b_g4M_clusU_i0 .clear(); - b_g4M_clusU_i1 .clear(); - b_g4M_clusU_layer .clear(); - b_g4M_clusU_x .clear(); - b_g4M_clusU_y .clear(); - b_g4M_clusU_z .clear(); - b_g4M_clusU_r .clear(); - b_svM_trackid .clear(); - b_svM_nclus .clear(); - b_svM_nclusmvtx .clear(); - b_svM_nclusintt .clear(); - b_svM_nclustpc .clear(); - b_svM_nclusmvtx_matchrat .clear(); - b_svM_nclusintt_matchrat .clear(); - b_svM_nclustpc_matchrat .clear(); - b_svM_pt .clear(); - b_svM_px .clear(); - b_svM_py .clear(); - b_svM_pz .clear(); - b_svM_clusM_i0 .clear(); - b_svM_clusM_i1 .clear(); - b_svM_clusM_layer .clear(); - b_svM_clusM_x .clear(); - b_svM_clusM_y .clear(); - b_svM_clusM_z .clear(); - b_svM_clusM_r .clear(); - b_svM_clusU_i0 .clear(); - b_svM_clusU_i1 .clear(); - b_svM_clusU_layer .clear(); - b_svM_clusU_x .clear(); - b_svM_clusU_y .clear(); - b_svM_clusU_z .clear(); - b_svM_clusU_r .clear(); - b_nclus_match .clear(); - b_g4svmatch_nclusmvtx .clear(); - b_g4svmatch_nclusintt .clear(); - b_g4svmatch_nclustpc .clear(); - b_g4U_trackid .clear(); - b_g4U_nclus .clear(); - b_g4U_nclusmvtx .clear(); - b_g4U_nclusintt .clear(); - b_g4U_nclustpc .clear(); - b_g4U_pt .clear(); - b_g4U_px .clear(); - b_g4U_py .clear(); - b_g4U_pz .clear(); - b_g4U_clusU_i0 .clear(); - b_g4U_clusU_i1 .clear(); - b_g4U_clusU_layer .clear(); - b_g4U_clusU_x .clear(); - b_g4U_clusU_y .clear(); - b_g4U_clusU_z .clear(); - b_g4U_clusU_r .clear(); - b_svU_trackid .clear(); - b_svU_nclus .clear(); - b_svU_nclusmvtx .clear(); - b_svU_nclusintt .clear(); - b_svU_nclustpc .clear(); - b_svU_pt .clear(); - b_svU_px .clear(); - b_svU_py .clear(); - b_svU_pz .clear(); - b_svU_clusU_i0 .clear(); - b_svU_clusU_i1 .clear(); - b_svU_clusU_layer .clear(); - b_svU_clusU_x .clear(); - b_svU_clusU_y .clear(); - b_svU_clusU_z .clear(); - b_svU_clusU_r .clear(); - + + b_G4M_trackid .clear(); + b_G4M_nclus .clear(); + b_G4M_nclusmvtx .clear(); + b_G4M_nclusintt .clear(); + b_G4M_nclustpc .clear(); + b_G4M_nclus_matchrat .clear(); + b_G4M_nclusmvtx_matchrat .clear(); + b_G4M_nclusintt_matchrat .clear(); + b_G4M_nclustpc_matchrat .clear(); + b_G4M_pt .clear(); + b_G4M_phi .clear(); + b_G4M_eta .clear(); + b_SvM_trackid .clear(); + b_SvM_nclus .clear(); + b_SvM_nclusmvtx .clear(); + b_SvM_nclusintt .clear(); + b_SvM_nclustpc .clear(); + b_SvM_nclus_matchrat .clear(); + b_SvM_nclusmvtx_matchrat .clear(); + b_SvM_nclusintt_matchrat .clear(); + b_SvM_nclustpc_matchrat .clear(); + b_SvM_pt .clear(); + b_SvM_phi .clear(); + b_SvM_eta .clear(); + if (m_fill_clusters) { + b_clusM_i0 .clear(); + b_clusM_i1 .clear(); + b_clusM_layer .clear(); + b_clusM_x .clear(); + b_clusM_y .clear(); + b_clusM_z .clear(); + b_clusM_r .clear(); + b_G4M_clusU_i0 .clear(); + b_G4M_clusU_i1 .clear(); + b_G4M_clusU_layer .clear(); + b_G4M_clusU_x .clear(); + b_G4M_clusU_y .clear(); + b_G4M_clusU_z .clear(); + b_G4M_clusU_r .clear(); + b_SvM_clusU_i0 .clear(); + b_SvM_clusU_i1 .clear(); + b_SvM_clusU_layer .clear(); + b_SvM_clusU_x .clear(); + b_SvM_clusU_y .clear(); + b_SvM_clusU_z .clear(); + b_SvM_clusU_r .clear(); + } + b_G4U_trackid .clear(); + b_G4U_nclus .clear(); + b_G4U_nclusmvtx .clear(); + b_G4U_nclusintt .clear(); + b_G4U_nclustpc .clear(); + b_G4U_pt .clear(); + b_G4U_phi .clear(); + b_G4U_eta .clear(); + if (m_fill_SvU) { + b_SvU_trackid .clear(); + b_SvU_nclus .clear(); + b_SvU_nclusmvtx .clear(); + b_SvU_nclusintt .clear(); + b_SvU_nclustpc .clear(); + b_SvU_pt .clear(); + b_SvU_phi .clear(); + b_SvU_eta .clear(); + } + if (m_fill_clusters) { + b_G4U_clusU_i0 .clear(); + b_G4U_clusU_i1 .clear(); + b_G4U_clusU_layer .clear(); + b_G4U_clusU_x .clear(); + b_G4U_clusU_y .clear(); + b_G4U_clusU_z .clear(); + b_G4U_clusU_r .clear(); + if (m_fill_SvU) { + b_SvU_clusU_i0 .clear(); + b_SvU_clusU_i1 .clear(); + b_SvU_clusU_layer .clear(); + b_SvU_clusU_x .clear(); + b_SvU_clusU_y .clear(); + b_SvU_clusU_z .clear(); + b_SvU_clusU_r .clear(); + } + } + + + } diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index bc13b54437..74a80c8b4a 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -6,28 +6,45 @@ * @author D. Stewart * @date February 2023 * @brief Write a TFile with a TTree with the matched tracks and (optionall) clusters + * This module takes the matching done in TruthRecoTrackMatching in the + * EmbRecoMatchContainer objects, and writes out the tracks kinematics to TTree + * in a TFile. + * The following data is always written out: + * For each track type: + * G4M : PHG4 matched + * G4U : PHG4 unmatched + * SvM : Svtx (reco) matched + * SvU : SVtx (reco) unmatched + * The following is stored: + * trackid, nclus, nclus{mvtx,intt,tpc}, pt, phi, eta + * For matched tracks (G4M and SvM): + * nclus_matchrat, nclus{mvtx,intt,tpc}_matchrat + * For matched tracks, the numbers of matched clusters (these are shared by G4M and SvM): + * nclusM, nclusM_{mvtx,intt,tpc} + * + * If the option is passed to save clusteres (default is on), then the cluster + * locations are saved too, as unmatched clusters (in all types of tracks), + * and the mutually matched clusters (shared by the G4M and SvM tracks): + * {G4U,G4M,SvU,SvM}_clusU_{i0,i1,x,y,z,r} + * For matche clusters, these are simply: + * clusM_{i0,i1,x,y,z,r,layer} + * The vectors of x,y,z,r are stoped in each branch with each tracks' data sequentially + * following the last. The branch i0 and i1 index where the one starts and the other stops. + * for each track. * - * read out the matched tracks from the node tree, - * look at the matched (and un-matched) tracks and plot out their - * kinematics and the locations (potentially) of the matched clusters. + * Data for matched tracks positionally align with each other (i.e. 1st entry in each + * correlate, then the 2nd, etc...) * - * An entry in SvtxPHG4ParticleMap could be: - * 12 -> 41.46 -> { 2, 4 } - * -> 18.46 -> { 7 } - * which is to say, reco track id 12 has matches to truth tracks 2, 4, and - * 7. Matches 12->2 and 12->4 weighting key (41.46) indicate that there were - * 41 matched clusters, that the reco track had 46 clusters. Match 12->7 key - * (18.46) indicates that there were 18 matched clusters (and, again, the reco track had 46 clusters) - * - * Assuming that truth tracks 2, 4, and 7, were matched only to reco track 12, and - * each had 45, 44, and 47 clusters, respectively, then the corresponding entries - * in PHG4ParticleSvtxMap would be: - * 2 -> 41.45 { 12 } - * 4 -> 41.44 { 12 } - * 7 -> 18.47 { 12 } + * A track is only an unmatched track is it has no matches (the options in + * TruthRecoTrackMatching can allow multiply matches for the same track...) * + * options: + * save cluster locations = true + * save un-matched Svtx tracks = false */ +#include "Tools.h" + #include #include #include @@ -54,8 +71,13 @@ class TFile; class FillTruthRecoMatchTree : public SubsysReco { public: - FillTruthRecoMatchTree(const std::string &name = "FillTruthRecoMatchTree", - bool _fill_clusters = false, const std::string tfile_name="trackclusmatch.root"); + FillTruthRecoMatchTree( + bool _fill_clusters = true + , bool _fill_svtxnomatch = false + , float _cluster_nzwidths = 0.5 + , float _cluster_nphiwidths = 0.5 + , const std::string tfile_name="trackclusmatch.root" + ); virtual ~FillTruthRecoMatchTree(); @@ -75,19 +97,23 @@ class FillTruthRecoMatchTree : public SubsysReco double _cluster_nzwidths { 0.5 }; double _cluster_nphiwidths { 0.5 }; - + G4Eval::TrkrClusterComparer m_cluster_comp; + G4Eval::ClusCntr m_cluscntr; + // contianer used to fill the other track matches - EmbRecoMatchContainer *m_EmbRecoMatchContainer {nullptr}; + EmbRecoMatchContainer *m_EmbRecoMatchContainer {nullptr}; PHG4TruthInfoContainer *m_PHG4TruthInfoContainer {nullptr}; SvtxTrackMap *m_SvtxTrackMap {nullptr}; - TrkrClusterContainer *m_TruthClusterContainer {nullptr}; - TrkrClusterContainer *m_RecoClusterContainer {nullptr}; + /* TrkrClusterContainer *m_TruthClusterContainer {nullptr}; */ + /* TrkrClusterContainer *m_RecoClusterContainer {nullptr}; */ TrkrTruthTrackContainer *m_TrkrTruthTrackContainer {nullptr}; - PHG4TpcCylinderGeomContainer *m_PHG4TpcCylinderGeomContainer {nullptr}; + /* PHG4TpcCylinderGeomContainer *m_PHG4TpcCylinderGeomContainer {nullptr}; */ + TFile* m_tfile; TTree* m_ttree; - bool m_fill_clusters { false }; + bool m_fill_clusters; + bool m_fill_SvU; // unmatched Svtx tracks // Tree Branch members: int nevent {-1}; @@ -110,94 +136,84 @@ class FillTruthRecoMatchTree : public SubsysReco // U : unmatched // TRACKS WHICH ARE MATCHED - std::vector b_g4M_trackid {}; // g4-track-matched - std::vector b_g4M_nclus {}; - std::vector b_g4M_nclusmvtx {}; - std::vector b_g4M_nclusintt {}; - std::vector b_g4M_nclustpc {}; - std::vector b_g4M_nclusmvtx_matchrat {}; - std::vector b_g4M_nclusintt_matchrat {}; - std::vector b_g4M_nclustpc_matchrat {}; - std::vector b_g4M_pt {}; - std::vector b_g4M_px {}; - std::vector b_g4M_py {}; - std::vector b_g4M_pz {}; - std::vector b_g4M_clusM_i0 {}; // g4-track-cluster-matched - std::vector b_g4M_clusM_i1 {}; - std::vector b_g4M_clusM_layer {}; - std::vector b_g4M_clusM_x {}; - std::vector b_g4M_clusM_y {}; - std::vector b_g4M_clusM_z {}; - std::vector b_g4M_clusM_r {}; - std::vector b_g4M_clusU_i0 {}; // g4-track-cluster-unmatched - std::vector b_g4M_clusU_i1 {}; - std::vector b_g4M_clusU_layer {}; - std::vector b_g4M_clusU_x {}; - std::vector b_g4M_clusU_y {}; - std::vector b_g4M_clusU_z {}; - std::vector b_g4M_clusU_r {}; - std::vector b_svM_trackid {}; //svtx-track-matched - std::vector b_svM_nclus {}; - std::vector b_svM_nclusmvtx {}; - std::vector b_svM_nclusintt {}; - std::vector b_svM_nclustpc {}; - std::vector b_svM_nclusmvtx_matchrat {}; - std::vector b_svM_nclusintt_matchrat {}; - std::vector b_svM_nclustpc_matchrat {}; - std::vector b_svM_pt {}; - std::vector b_svM_px {}; - std::vector b_svM_py {}; - std::vector b_svM_pz {}; - std::vector b_svM_clusM_i0 {}; // svtx-track-matched-cluster-matched - std::vector b_svM_clusM_i1 {}; - std::vector b_svM_clusM_layer {}; - std::vector b_svM_clusM_x {}; - std::vector b_svM_clusM_y {}; - std::vector b_svM_clusM_z {}; - std::vector b_svM_clusM_r {}; - std::vector b_svM_clusU_i0 {}; - std::vector b_svM_clusU_i1 {}; - std::vector b_svM_clusU_layer {}; - std::vector b_svM_clusU_x {}; - std::vector b_svM_clusU_y {}; - std::vector b_svM_clusU_z {}; - std::vector b_svM_clusU_r {}; - std::vector b_nclus_match {}; // Ratios for clusters for matched tracks - std::vector b_g4svmatch_nclusmvtx {}; - std::vector b_g4svmatch_nclusintt {}; - std::vector b_g4svmatch_nclustpc {}; - std::vector b_g4U_trackid {}; // g4-track-unmatched- - std::vector b_g4U_nclus {}; - std::vector b_g4U_nclusmvtx {}; - std::vector b_g4U_nclusintt {}; - std::vector b_g4U_nclustpc {}; - std::vector b_g4U_pt {}; - std::vector b_g4U_px {}; - std::vector b_g4U_py {}; - std::vector b_g4U_pz {}; - std::vector b_g4U_clusU_i0 {}; // g4-track-unmatched-clust-unmatched - std::vector b_g4U_clusU_i1 {}; - std::vector b_g4U_clusU_layer {}; - std::vector b_g4U_clusU_x {}; - std::vector b_g4U_clusU_y {}; - std::vector b_g4U_clusU_z {}; - std::vector b_g4U_clusU_r {}; - std::vector b_svU_trackid {}; // svtx-track-unmatched - std::vector b_svU_nclus {}; - std::vector b_svU_nclusmvtx {}; - std::vector b_svU_nclusintt {}; - std::vector b_svU_nclustpc {}; - std::vector b_svU_pt {}; - std::vector b_svU_px {}; - std::vector b_svU_py {}; - std::vector b_svU_pz {}; - std::vector b_svU_clusU_i0 {}; // svtx-track-unmatched-cluster-unmatched - std::vector b_svU_clusU_i1 {}; - std::vector b_svU_clusU_layer {}; - std::vector b_svU_clusU_x {}; - std::vector b_svU_clusU_y {}; - std::vector b_svU_clusU_z {}; - std::vector b_svU_clusU_r {}; + std::vector b_G4M_trackid {}; // g4-track-matched + std::vector b_G4M_nclus {}; + std::vector b_G4M_nclusmvtx {}; + std::vector b_G4M_nclusintt {}; + std::vector b_G4M_nclustpc {}; + std::vector b_G4M_nclus_matchrat {}; + std::vector b_G4M_nclusmvtx_matchrat {}; + std::vector b_G4M_nclusintt_matchrat {}; + std::vector b_G4M_nclustpc_matchrat {}; + std::vector b_G4M_pt {}; + std::vector b_G4M_phi {}; + std::vector b_G4M_eta {}; + std::vector b_SvM_trackid {}; // Svtx-track-matched + std::vector b_SvM_nclus {}; + std::vector b_SvM_nclusmvtx {}; + std::vector b_SvM_nclusintt {}; + std::vector b_SvM_nclustpc {}; + std::vector b_SvM_nclus_matchrat {}; + std::vector b_SvM_nclusmvtx_matchrat {}; + std::vector b_SvM_nclusintt_matchrat {}; + std::vector b_SvM_nclustpc_matchrat {}; + std::vector b_SvM_pt {}; + std::vector b_SvM_phi {}; + std::vector b_SvM_eta {}; + std::vector b_clusM_i0 {}; // if storing clusters -- matched clusters + std::vector b_clusM_i1 {}; + std::vector b_clusM_layer {}; + std::vector b_clusM_x {}; + std::vector b_clusM_y {}; + std::vector b_clusM_z {}; + std::vector b_clusM_r {}; + std::vector b_G4M_clusU_i0 {}; // matched phg4 unmatched clusters + std::vector b_G4M_clusU_i1 {}; + std::vector b_G4M_clusU_layer {}; + std::vector b_G4M_clusU_x {}; + std::vector b_G4M_clusU_y {}; + std::vector b_G4M_clusU_z {}; + std::vector b_G4M_clusU_r {}; + std::vector b_SvM_clusU_i0 {}; // matched phg4 unmatched clusters + std::vector b_SvM_clusU_i1 {}; + std::vector b_SvM_clusU_layer {}; + std::vector b_SvM_clusU_x {}; + std::vector b_SvM_clusU_y {}; + std::vector b_SvM_clusU_z {}; + std::vector b_SvM_clusU_r {}; + std::vector b_G4U_trackid {}; // unmatched tracks + std::vector b_G4U_nclus {}; + std::vector b_G4U_nclusmvtx {}; + std::vector b_G4U_nclusintt {}; + std::vector b_G4U_nclustpc {}; + std::vector b_G4U_pt {}; + std::vector b_G4U_phi {}; + std::vector b_G4U_eta {}; + std::vector b_SvU_trackid {}; // Svtx-track-matched + std::vector b_SvU_nclus {}; + std::vector b_SvU_nclusmvtx {}; + std::vector b_SvU_nclusintt {}; + std::vector b_SvU_nclustpc {}; + std::vector b_SvU_pt {}; + std::vector b_SvU_phi {}; + std::vector b_SvU_eta {}; + std::vector b_G4U_clusU_i0 {}; // unmatched phg4 unmatched clusters + std::vector b_G4U_clusU_i1 {}; + std::vector b_G4U_clusU_layer {}; + std::vector b_G4U_clusU_x {}; + std::vector b_G4U_clusU_y {}; + std::vector b_G4U_clusU_z {}; + std::vector b_G4U_clusU_r {}; + std::vector b_SvU_clusU_i0 {}; // unmatched phg4 unmatched clusters + std::vector b_SvU_clusU_i1 {}; + std::vector b_SvU_clusU_layer {}; + std::vector b_SvU_clusU_x {}; + std::vector b_SvU_clusU_y {}; + std::vector b_SvU_clusU_z {}; + std::vector b_SvU_clusU_r {}; + + + }; #endif // FILLTRUTHRECOMATCHTREE_H diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc index e6f9a553d1..002b40e35f 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -14,12 +14,62 @@ #include #include #include // for PHObject +#include +#include #include +#include +#include +#include using std::cout; using std::endl; namespace G4Eval { + std::vector unmatchedSvtxTrkIds(EmbRecoMatchContainer* matches, SvtxTrackMap* m_SvtxTrackMap) { + std::set ids_matched{}; + for (auto trkid : matches->ids_RecoMatched()) { + ids_matched.insert(trkid); + } + + std::set ids_unmatched; + for (auto reco = m_SvtxTrackMap->begin(); reco != m_SvtxTrackMap->end(); ++reco) { + auto trkid = reco->first; + if (ids_matched.count(trkid)==0) ids_unmatched.insert(trkid); + } + std::vector ids_vec; + for (auto id : ids_unmatched) ids_vec.push_back((int)id); + std::sort(ids_vec.begin(), ids_vec.end()); + return ids_vec; + } + + +// function implementation mostly from +// https://root-forum.cern.ch/t/is-it-possible-to-save-plain-text-in-a-root-file/27674/4 +// Note that there is also the code there to read it back from a TFile + void write_StringToTFile(std::string msg_name + , std::string msg) + { + //the string is either written to the current file, or to a new file + //that is named f_outname + TFile* s_current = gDirectory->GetFile(); + if (s_current == nullptr) { + std::cout << PHWHERE << " Error no TFile open to which to wrote the " + << std::endl << " TObjString mesaged." << std::endl; + return; + } + TObjString obj( msg.c_str() ); + s_current->WriteObject( &obj, msg_name.c_str() ); + return; + } + + // return the layer of the hit: 0:Mvtx 1:Intt 2:Tpc 3:Tpot + int trklayer_0123(TrkrDefs::hitsetkey key) { + auto layer = TrkrDefs::getLayer(key); + if (layer < 3) return 0; + if (layer < 7) return 1; + if (layer < 55) return 2; + return 3; + } //Implementation of Cluster comparator TrkrClusterComparer::TrkrClusterComparer (float _nphi_widths, float _nz_widths ) @@ -92,6 +142,12 @@ namespace G4Eval { return Fun4AllReturnCodes::ABORTRUN; } + m_ActsGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (!m_ActsGeometry) { + std::cout << PHWHERE << " Could not locate ActsGeometry node" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -144,6 +200,20 @@ namespace G4Eval { return { is_match, fit_statistic }; } + std::pair TrkrClusterComparer::clusloc_PHG4( + std::pair input) { + auto cluster = m_TruthClusters->findCluster(input.second); + Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster); + return {TrkrDefs::getLayer(input.first),gloc}; + } + + std::pair TrkrClusterComparer::clusloc_SVTX( + std::pair input) { + auto cluster = m_RecoClusters->findCluster(input.second); + Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster); + return {TrkrDefs::getLayer(input.first),gloc}; + } + // Implementation of the iterable struct to get cluster keys from // a SvtxTrack. It is used like: // for (auto& cluskey : ClusKeyIter(svtx_track)) { @@ -197,4 +267,188 @@ namespace G4Eval { TrkrDefs::cluskey ClusKeyIter::operator*() { return *iter; } + + std::array ClusCntr::cntclus(Vector& keys) { + std::array cnt { 0, 0, 0, 0, 0 }; + for (auto& it : keys) { + cnt[trklayer_0123(it.first)] += 1; + } + for (int i=0;i<4;++i) cnt[4] += cnt[i]; + return cnt; + } + + std::array ClusCntr::cnt_matchedclus + (Vector& keys, std::vector& matches) + { + std::array cnt { 0, 0, 0, 0, 0 }; + if (keys.size() != matches.size()) { + std::cout << PHWHERE << " matching and key vector not the same size. " + << std::endl << " run find_matches() first." << std::endl; + return cnt; + } + for (unsigned int i=0; igetClusters().size() << std::endl; + int i {0}; + for (auto ckey : track->getClusters()) { + phg4_keys.push_back( {TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey} ); + std::cout << " i("< ClusCntr::find_matches() { + if (comp == nullptr) { + std::cout << PHWHERE + << " Won't compare tracks because of missing TrkrClusterComparer" << std::endl; + return {0,0,0}; + } + // find the matches between the svtx_keys and phg4_keys + // also keep track of the sum of the comparison between then + + // --------------------------------- + // set aliases for notation cleaness + // use A for PHG4 and B for SVTX + auto& vA = phg4_keys; + auto& vB = svtx_keys; + + auto& matchesA = phg4_matches; + auto& matchesB = svtx_matches; + + match_stat = 0.; + + // matches will say, cluster by cluster, which clusters are matched + matchesA = std::vector(vA.size(),false); + matchesB = std::vector(vB.size(),false); + + // user iterators to access the vectors + auto iA0 = vA.begin(); + auto iA1 = vA.end(); + + auto iB0 = vB.begin(); + auto iB1 = vB.end(); + + auto iA = iA0; + auto iB = iB0; + + int n_match {0}; + + while (iA != iA1 && iB != iB1) { + if (iA->first == iB->first) { + auto hitset = iA->first; + + // must compare ALL sets of iA and iB with this same hitset + auto sAend = iA+1; // search A end + while (sAend != iA1 && sAend->first == hitset) ++sAend; + + auto sBend = iB+1; // search B end + while (sBend != iB1 && sBend->first == hitset) ++sBend; + + for (auto _A = iA; _A!=sAend; ++_A) { + for (auto _B = iB; _B!=sBend; ++_B) { + auto comp_val = comp->operator()(_A->second,_B->second); + if (comp_val.first) { + matchesA[_A-iA0] = true; + matchesB[_B-iB0] = true; + match_stat += comp_val.second; + ++n_match; + } + }} + iA = sAend; + iB = sBend; + } else if (iA->first < iB->first) { + ++iA; + } else { + ++iB; + } + } + return { n_match, (int)phg4_keys.size(), (int)svtx_keys.size() }; + } + + std::array ClusCntr::find_matches(TrkrTruthTrack* g4_track, SvtxTrack* sv_track) { + addClusKeys(sv_track); + addClusKeys(g4_track); + return find_matches(); + } + + int ClusCntr::phg4_n_matched() { + return std::accumulate(phg4_matches.begin(), phg4_matches.end(), 0); } + + int ClusCntr::svtx_n_matched() { + return std::accumulate(svtx_matches.begin(), svtx_matches.end(), 0); } + + std::vector ClusCntr::phg4_clusloc_all() { + std::vector vec{}; + for (auto& cluspair : phg4_keys) vec.push_back(comp->clusloc_PHG4(cluspair)); + return vec; + } + + std::vector ClusCntr::phg4_clusloc_unmatched() { + std::vector vec{}; + auto cnt = phg4_keys.size(); + for (unsigned int i = 0; iclusloc_PHG4(phg4_keys[i])); + } + return vec; + } + + std::vector ClusCntr::svtx_clusloc_all() { + std::vector vec{}; + for (auto& cluspair : svtx_keys) vec.push_back(comp->clusloc_SVTX(cluspair)); + return vec; + } + + std::vector ClusCntr::svtx_clusloc_unmatched() { + std::vector vec{}; + auto cnt = svtx_keys.size(); + for (unsigned int i = 0; iclusloc_SVTX(svtx_keys[i])); + } + return vec; + } + + std::vector ClusCntr::clusloc_matched() { + std::vector vec{}; + auto cnt = phg4_keys.size(); + for (unsigned int i = 0; iclusloc_PHG4(phg4_keys[i])); + } + return vec; + } + + /* ClusCntr::layer_xyzLoc ClusCntr::xyzLoc(std::pairgetGlobalPosition(reco_ckey, cluster); */ + /* } */ + } diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h index 04e44baa9a..b658ad8ec0 100644 --- a/simulation/g4simulation/g4eval/Tools.h +++ b/simulation/g4simulation/g4eval/Tools.h @@ -6,16 +6,29 @@ #include #include #include +#include +#include /* #include */ -class TrkrClusterContainer; +class ActsGeometry; +class EmbRecoMatchContainer; class PHCompositeNode; -class TrkrCluster; class SvtxTrack; +class SvtxTrackMap; +class TrkrCluster; +class TrkrClusterContainer; +class TrkrTruthTrack; namespace G4Eval { - class TrkrClusterComparer { + // Following function writes msg to the currently active TFile + // if f_outname is provided, then it will write the message to a new + // TFiles of that name and close it again. + void write_StringToTFile(std::string msg_name, std::string msg); + + std::vector unmatchedSvtxTrkIds(EmbRecoMatchContainer*, SvtxTrackMap*); + + class TrkrClusterComparer { // most members are public for easy access after the node has been used public: TrkrClusterComparer (float _nphi_widths=0.5, float _nz_widths=0.5 ); @@ -51,6 +64,9 @@ namespace G4Eval { void set_nz_widths(float val) { m_nz_widths = val; }; void set_nphi_widths(float val) { m_nphi_widths = val; }; + + std::pair clusloc_PHG4(std::pair); + std::pair clusloc_SVTX(std::pair); private: //phi pixel sizes, got for the geometries from the topNode std::array m_phistep {0.}; // the phistep squared @@ -59,6 +75,8 @@ namespace G4Eval { TrkrClusterContainer* m_TruthClusters {nullptr}; TrkrClusterContainer* m_RecoClusters {nullptr}; + ActsGeometry* m_ActsGeometry {nullptr}; + }; // The following is a struct to iterate over the cluster keys for a given @@ -88,41 +106,59 @@ namespace G4Eval { bool operator!=(const ClusKeyIter& rhs); }; - struct HitSetClusKeyVec { + int trklayer_0123(TrkrDefs::hitsetkey); // 0:Mvtx 1:Intt 2:Tpc 3:Tpot + + class ClusCntr { + private: using Vector = std::vector>; using Iter = Vector::iterator; - vector keys_svtx; - vector keys_phg4; + TrkrClusterComparer* comp; + std::array cntclus(Vector& keys); + std::array cnt_matchedclus(Vector& keys, std::vector& matches); + ActsGeometry* geom {nullptr}; + + public: + ClusCntr(TrkrClusterComparer*_=nullptr) : comp{_} {}; + + Vector svtx_keys {}; + Vector phg4_keys {}; - vector bool matches_svtx; - vector bool matches_phg4; + double match_stat {0}; - double find_matches(TrkrClusterCommparer&); + void reset(); + std::array find_matches();// populated matches_{svtx,phg4}; + // return's {n-matched, n-phg4, n-svtx} + std::array find_matches(TrkrTruthTrack* g4_track, SvtxTrack* sv_track); - int addSvtxClusters(SvtxTrack*); - int addPHG4Clusters(TrkrTruthTrack*); + int phg4_n_matched(); // also same as phg4_cnt_matchedclus()[4] + int svtx_n_matched(); // should be almost always the same + // which is ALMOST guaranteed to be same as svtx_cnt_matchedclus()[4] + int phg4_nclus() { return (int) phg4_keys.size(); } + int svtx_nclus() { return (int) svtx_keys.size(); } - std::array svtx_cntclus_allMvtxInttTpc(); - std::array phg4_cntclus_allMvtxInttTpc(); + std::vector svtx_matches; + std::vector phg4_matches; - std::array svtx_cntmatchclus_allMvtxInttTpc(); - std::array phg4_cntmatchclus_allMvtxInttTpc(); + int addClusKeys(SvtxTrack*); // return number of clusters + int addClusKeys(TrkrTruthTrack*); // return number of clusters + std::array svtx_cntclus() { return cntclus(svtx_keys); }; // Mvtx Intt Tpc TPOT Sum + std::array phg4_cntclus() { return cntclus(phg4_keys); }; - // Does the following: - // for a given SvtxTrack or TrkrTruthTrack, - // - makes a vector of pairs: {hitsetkey, cluskey}, and sort it - // - can return pointers to first and last pair with a given hitsetkey - // - can keep track of which one's are matched and which are not - HitSetClusKeyVec(SvtxTrack*); - HitSetClusKeyVec(TrkrTruthTrack*); - std::vector< std::pair> data; - int cnt(TrkrDefs::hitsetkey); // count how many pairs have - vector svtx_cnt_matchedclus() {return cnt_matchedclus(svtx_keys, svtx_matches); }; + std::array phg4_cnt_matchedclus() {return cnt_matchedclus(phg4_keys, phg4_matches); }; - } + using LayerLoc = std::pair; + std::vector phg4_clusloc_all(); + std::vector phg4_clusloc_unmatched(); + std::vector svtx_clusloc_all(); + std::vector svtx_clusloc_unmatched(); + std::vector clusloc_matched(); + void set_comparer(TrkrClusterComparer* _comp) { comp = _comp; }; + + }; } #endif diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc index 259513adf3..2f7263ceb3 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc @@ -77,12 +77,13 @@ TruthRecoTrackMatching::TruthRecoTrackMatching , m_nmatched_id_reco {nullptr} , m_nmatched_id_true {nullptr} { + m_cluscntr.set_comparer(&m_cluster_comp); if (Verbosity() > 50) cout << " Starting TruthRecoTrackMatching.cc " << endl; } int TruthRecoTrackMatching::InitRun(PHCompositeNode *topNode) //` { - topNode->print(); + if (Verbosity() > 10) topNode->print(); auto init_status = m_cluster_comp.init(topNode); if (init_status == Fun4AllReturnCodes::ABORTRUN) return init_status; @@ -250,9 +251,29 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) int TruthRecoTrackMatching::End(PHCompositeNode * /*topNode*/) { + TFile *s_current = gDirectory->GetFile(); if (m_write_diag) { - TFile *s_current = gDirectory->GetFile(); m_diag_file->cd(); + G4Eval::write_StringToTFile( + "trk_match_sel", + Form(" Matching criteria:\n" + " min. clusters to match: %i\n" + " min. clust. match ratio: %4.2f" + " dphi small window: %4.2f" + " dphi large windows: %4.2f" + " deta small window: %4.2f" + " deta large window: %4.2f" + " nmax phg4 matches per svtx: %i" + " nmax svtx matches per phg4: %i" + , m_nmincluster_match + , m_nmincluster_ratio + , m_same_dphi + , m_cutoff_dphi + , m_same_deta + , m_cutoff_deta + , m_max_ntruth_per_reco + , m_max_nreco_per_truth + )); m_diag_tree ->Write(); m_diag_file ->Save(); m_diag_file ->Close(); @@ -500,12 +521,15 @@ void TruthRecoTrackMatching::match_tracks_in_box( } // make all possible reco matches matched for this track - std::map truth_keys; - auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); - for (auto& key : truth_track->getClusters()) { - truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; - } - unsigned short nclus_true = truth_keys.size(); + /* std::map truth_keys; */ + m_cluscntr.addClusKeys(m_TrkrTruthTrackContainer->getTruthTrack(id_true)); + std::cout << " FIXME NCLUS TRUE: " << (int)m_cluscntr.phg4_nclus() << std::endl; + // add the truth keys into the track counter + /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); */ + /* for (auto& key : truth_track->getClusters()) { */ + /* truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; */ + /* } */ + /* unsigned short nclus_true = truth_keys.size(); */ while (ipair != box_pairs.end()) { // Loop over all possible matches only for this index_true //(subsequent true tracks will be caught on following loops) @@ -515,25 +539,32 @@ void TruthRecoTrackMatching::match_tracks_in_box( continue; }// make sure the reco-track isn't alread matched // ok, make a possible match: compare the clusters in the truth track and the reco track - unsigned short nclus_match = 0; // fill in the comparison loop - unsigned short nclus_nomatch = 0; // number of reco and truth cluster that share a hitsetkey, but still fair matching criteria - unsigned short nclus_reco = 0; // count in the comparison loop SvtxTrack* reco_track = m_SvtxTrackMap->get(ipair->second); - - - for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { - ++nclus_reco; - auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); - if (truth_keys.count(hitsetkey) != 0) { - // reco and truth cluster are in same hitsetkey-indexed subsurface. - // See if they match (++nclus_match) or not (++nclus_nomatch) - if (m_cluster_comp(truth_keys[hitsetkey], reco_ckey).first) { - ++nclus_match; - } else { - ++nclus_nomatch; - } - } - } + m_cluscntr.addClusKeys(reco_track); + m_cluscntr.find_matches(); + + /* unsigned short nclus_match = 0; // fill in the comparison loop */ + /* unsigned short nclus_nomatch = 0; // number of reco and truth cluster + * // that share a hitsetkey, but still fair matching criteria */ + /* unsigned short nclus_reco = 0; // count in the comparison loop */ + //do the comparison of the tracks + /* for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { */ + /* ++nclus_reco; */ + /* auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); */ + /* if (truth_keys.count(hitsetkey) != 0) { */ + /* // reco and truth cluster are in same hitsetkey-indexed subsurface. */ + /* // See if they match (++nclus_match) or not (++nclus_nomatch) */ + /* if (m_cluster_comp(truth_keys[hitsetkey], reco_ckey).first) { */ + /* ++nclus_match; */ + /* } else { */ + /* ++nclus_nomatch; */ + /* } */ + /* } */ + /* } */ + unsigned short nclus_match = m_cluscntr.phg4_n_matched(); + unsigned short nclus_true = m_cluscntr.phg4_nclus(); + unsigned short nclus_reco = m_cluscntr.svtx_nclus(); + unsigned short nclus_nomatch = (int) (m_cluscntr.svtx_keys.size()-nclus_match); if (Verbosity()>100) { auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); @@ -548,7 +579,8 @@ void TruthRecoTrackMatching::match_tracks_in_box( if ( nclus_match >= m_nmincluster_match && ( static_cast(nclus_match)/nclus_true >= m_nmincluster_ratio) ) { - poss_matches.push_back( {nclus_match, nclus_true, nclus_reco, + poss_matches.push_back( + {nclus_match, nclus_true, nclus_reco, ipair->first, ipair->second} ); } ++ipair; @@ -626,7 +658,7 @@ void TruthRecoTrackMatching::match_tracks_in_box( // ---------------------------------------- inline float TruthRecoTrackMatching::abs_dphi (float phi0, float phi1) { float dphi = fabs(phi0-phi1); - while (dphi > M_PI) dphi -= fabs(2*M_PI); + while (dphi > M_PI) dphi = fabs(dphi-2*M_PI); return dphi; } @@ -634,34 +666,43 @@ float TruthRecoTrackMatching::sigma_CompMatchClusters(PossibleMatch& match) { auto id_true = match[PM_idtrue]; auto id_reco = match[PM_idreco]; - auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); - if (!truth_track) return std::numeric_limits::max(); - std::map truth_keys; // truth cluster keys - for (auto& key : truth_track->getClusters()) - truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; - + m_cluscntr.addClusKeys( m_TrkrTruthTrackContainer->getTruthTrack(id_true) ); + m_cluscntr.addClusKeys( m_SvtxTrackMap->get(id_reco)); - SvtxTrack* reco_track = m_SvtxTrackMap->get(id_reco); - if (!reco_track) return std::numeric_limits::max(); + m_cluscntr.find_matches(); - auto tpcseed = reco_track->get_tpc_seed(); - if (!tpcseed) return std::numeric_limits::max(); + int n_matched = m_cluscntr.phg4_n_matched(); - double n_matches = 0.; // get the mean match values - double sum_diff = 0.; - - for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { - auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); - if (truth_keys.count(hitsetkey) == 0) continue; - auto comp_val = m_cluster_comp(truth_keys[hitsetkey], reco_ckey); - - if (comp_val.first) { - n_matches += 1.; - sum_diff += comp_val.second; - } - } - return sum_diff/n_matches; + if (n_matched) return std::numeric_limits::max(); + else return m_cluscntr.match_stat / n_matched; } + /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); */ + /* if (!truth_track) return std::numeric_limits::max(); */ + /* std::map truth_keys; // truth cluster keys */ + /* for (auto& key : truth_track->getClusters()) */ + /* truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; */ + + /* SvtxTrack* reco_track = m_SvtxTrackMap->get(id_reco); */ + /* if (!reco_track) return std::numeric_limits::max(); */ + + /* auto tpcseed = reco_track->get_tpc_seed(); */ + /* if (!tpcseed) return std::numeric_limits::max(); */ + + /* double n_matches = 0.; // get the mean match values */ + /* double sum_diff = 0.; */ + + /* for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { */ + /* auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); */ + /* if (truth_keys.count(hitsetkey) == 0) continue; */ + /* auto comp_val = m_cluster_comp(truth_keys[hitsetkey], reco_ckey); */ + + /* if (comp_val.first) { */ + /* n_matches += 1.; */ + /* sum_diff += comp_val.second; */ + /* } */ + /* } */ + /* return sum_diff/n_matches; */ +/* } */ inline bool TruthRecoTrackMatching::skip_match( PossibleMatch& match ) { @@ -702,6 +743,7 @@ void TruthRecoTrackMatching::set_diagnostic_file(std::string file_name) { m_write_diag = true; TFile *s_current = gDirectory->GetFile(); m_diag_file = new TFile(file_name.c_str(),"recreate"); + // write out the cuts on this set of data m_diag_file->cd(); m_diag_tree = new TTree("T", "Tree of Reco and True Clusters"); @@ -792,7 +834,7 @@ void TruthRecoTrackMatching::fill_tree() { for (auto& ckey : track->getClusters()) { auto cluster = m_TruthClusterContainer->findCluster(ckey); m_cnt_true_notmatched.push_back(itrk); - Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(ckey, cluster); + Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(ckey, cluster); m_layer_true_notmatched .push_back(TrkrDefs::getLayer(ckey)); m_x_true_notmatched .push_back(gloc[0]); m_y_true_notmatched .push_back(gloc[1]); diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h index e420c71489..bbfd6c98af 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h @@ -74,6 +74,7 @@ class TruthRecoTrackMatching : public SubsysReco int End(PHCompositeNode *) override; G4Eval::TrkrClusterComparer m_cluster_comp; + G4Eval::ClusCntr m_cluscntr; int createNodes(PHCompositeNode* topNode); From c07d9479edb59c28f44a2dafc5461e655b43a4fc Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Tue, 21 Mar 2023 10:40:15 -0400 Subject: [PATCH 025/468] currently debugging the mvtx in phg4 track hits --- offline/packages/mvtx/MvtxClusterizer.cc | 8 +++ .../g4eval/FillTruthRecoMatchTree.cc | 59 +++++++++++++++++++ .../g4eval/FillTruthRecoMatchTree.h | 2 + simulation/g4simulation/g4eval/Tools.cc | 10 ++++ simulation/g4simulation/g4eval/Tools.h | 7 ++- 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 2539aa8e11..5e3dcddcf9 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -210,6 +210,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) int MvtxClusterizer::process_event(PHCompositeNode *topNode) { + cout << " FIXME y0 : new event in MvtxClusterizer " << endl; // get node containing the digitized hits if(!do_read_raw){ m_hits = findNode::getClass(topNode, "TRKR_HITSET"); @@ -346,6 +347,9 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) } // cout << "found cluster #: "<< clusters.size()<< endl; // loop over the componenets and make clusters + cout << PHWHERE << endl; + cout << " -- z0 -- starting loop over clusters -- " << endl; + int total_clusters = 0; for (set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) { int clusid = *clusiter; @@ -354,6 +358,10 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl; // make the cluster directly in the node tree + /* cout << PHWHERE << endl; */ + cout << " --> --> --> " << clusid << endl; + ++total_clusters; + /* cout << " FIXME z: component clusid " << clusid << endl; */ auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); // determine the size of the cluster in phi and z diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index 71a3b25150..678156d772 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -17,6 +17,7 @@ #include // for PHObject #include #include // for PHWHERE +#include #include #include #include @@ -240,6 +241,9 @@ int FillTruthRecoMatchTree::createNodes(PHCompositeNode *topNode) int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) { + print_mvtx_diagnostics(); + return 0; + if (Verbosity()>5) cout << " FillTruthRecoMatchTree::process_event() " << endl; // fill in the event data @@ -419,6 +423,61 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +void FillTruthRecoMatchTree::print_mvtx_diagnostics() { + std::cout << "To do: " + << " (1) number of truth tracks and total number of mvtx and ratio " << std::endl + << " (2) ditto for reco tracks " << std::endl; + + double n_PHG4_tracks = m_TrkrTruthTrackContainer->getMap().size(); + // count how many mvtx clusters in the phg4 tracks + double n_in_PHG4_tracks {0.}; + for (auto& pair : m_TrkrTruthTrackContainer->getMap()) { + m_cluscntr.addClusKeys( pair.second ); + n_in_PHG4_tracks += m_cluscntr.phg4_cntclus()[0]; + } + // count how mant mvtx clusters in truth container (should be the same) + double n_in_PHG4_clusters {0.}; + for (auto hitsetkey : m_cluscntr.get_PHG4_clusters()->getHitSetKeys()) { + if (TrkrDefs::getLayer(hitsetkey) > 2) continue; + auto range = m_cluscntr.get_PHG4_clusters()->getClusters(hitsetkey); + for (auto r = range.first; r != range.second; ++r) { + n_in_PHG4_clusters += 1.; + } + } + + // count how many svtx tracks + double n_SVTX_tracks = m_SvtxTrackMap->size(); + // count how many mvtx clusters in svtx tracks + double n_in_SVTX_tracks {0.}; + for (auto entry = m_SvtxTrackMap->begin(); entry != m_SvtxTrackMap->end(); ++entry) { + m_cluscntr.addClusKeys(entry->second); + n_in_SVTX_tracks += m_cluscntr.svtx_cntclus()[0]; + } + // count how many mvtx are total in the container + double n_in_SVTX_clusters {0.}; + for (auto hitsetkey : m_cluscntr.get_SVTX_clusters()->getHitSetKeys()) { + if (TrkrDefs::getLayer(hitsetkey) > 2) continue; + auto range = m_cluscntr.get_SVTX_clusters()->getClusters(hitsetkey); + for (auto r = range.first; r != range.second; ++r) { + n_in_SVTX_clusters += 1.; + } + } + + std::cout << Form("MVTX" + "\nPHG4: Tracks(%.0f) Clusters In tracks(%.0f) Total (%.0f)" + "\n ave. per track: %6.3f ratio in all tracks: %6.2f" + , n_PHG4_tracks, n_in_PHG4_tracks, n_in_PHG4_clusters + , (n_in_PHG4_tracks/n_PHG4_tracks), (n_in_PHG4_tracks/n_in_PHG4_clusters)) + << std::endl; + std::cout << Form( + "\nSVTX: Tracks(%.0f) Clusters In tracks(%.0f) Total (%.0f)" + "\n ave. per track: %6.3f ratio in all tracks: %6.2f" + , n_SVTX_tracks, n_in_SVTX_tracks, n_in_SVTX_clusters + , (n_in_SVTX_tracks/n_SVTX_tracks), (n_in_SVTX_tracks/n_in_SVTX_clusters)) + << std::endl; + +} + int FillTruthRecoMatchTree::End(PHCompositeNode *) { if (Verbosity()>2) std::cout << PHWHERE << ": ending FillTruthRecoMatchTree" << std::endl; diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index 74a80c8b4a..47e3114747 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -88,6 +88,8 @@ class FillTruthRecoMatchTree : public SubsysReco void clear_vectors(); + void print_mvtx_diagnostics(); + private: int createNodes(PHCompositeNode *topNode); diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc index 002b40e35f..916a86f849 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -268,6 +268,16 @@ namespace G4Eval { return *iter; } + TrkrClusterContainer* ClusCntr::get_PHG4_clusters() { + if (comp == nullptr) return nullptr; + else return comp->m_TruthClusters; + } + + TrkrClusterContainer* ClusCntr::get_SVTX_clusters() { + if (comp == nullptr) return nullptr; + else return comp->m_RecoClusters; + } + std::array ClusCntr::cntclus(Vector& keys) { std::array cnt { 0, 0, 0, 0, 0 }; for (auto& it : keys) { diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h index b658ad8ec0..87bd6c9dd3 100644 --- a/simulation/g4simulation/g4eval/Tools.h +++ b/simulation/g4simulation/g4eval/Tools.h @@ -67,14 +67,15 @@ namespace G4Eval { std::pair clusloc_PHG4(std::pair); std::pair clusloc_SVTX(std::pair); + + TrkrClusterContainer* m_TruthClusters {nullptr}; + TrkrClusterContainer* m_RecoClusters {nullptr}; private: //phi pixel sizes, got for the geometries from the topNode std::array m_phistep {0.}; // the phistep squared float m_nphi_widths; float m_nz_widths; - TrkrClusterContainer* m_TruthClusters {nullptr}; - TrkrClusterContainer* m_RecoClusters {nullptr}; ActsGeometry* m_ActsGeometry {nullptr}; }; @@ -120,6 +121,8 @@ namespace G4Eval { public: ClusCntr(TrkrClusterComparer*_=nullptr) : comp{_} {}; + TrkrClusterContainer* get_PHG4_clusters(); + TrkrClusterContainer* get_SVTX_clusters(); Vector svtx_keys {}; Vector phg4_keys {}; From 1d7fd5b7a1b444dd47ea213094f128f5dc699f71 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Tue, 21 Mar 2023 17:10:12 -0400 Subject: [PATCH 026/468] Fix clustering in the mvtx to user the MvtxHitPruner. Expand to allow output of TTree for clusters in truth and reco. --- offline/packages/mvtx/MvtxClusterizer.cc | 13 +----- offline/packages/mvtx/MvtxHitPruner.cc | 16 +++---- offline/packages/mvtx/MvtxHitPruner.h | 3 ++ simulation/g4simulation/g4eval/Tools.cc | 4 -- .../g4eval/TruthRecoTrackMatching.cc | 1 - simulation/g4simulation/g4mvtx/Makefile.am | 1 + .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 3 ++ .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 6 +++ .../g4mvtx/TruthMvtxClusterBuilder.cc | 42 ++++++++++--------- .../g4mvtx/TruthMvtxClusterBuilder.h | 19 +++++++++ 10 files changed, 65 insertions(+), 43 deletions(-) diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 5e3dcddcf9..e34860869f 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -210,7 +210,6 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) int MvtxClusterizer::process_event(PHCompositeNode *topNode) { - cout << " FIXME y0 : new event in MvtxClusterizer " << endl; // get node containing the digitized hits if(!do_read_raw){ m_hits = findNode::getClass(topNode, "TRKR_HITSET"); @@ -345,10 +344,6 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) cluster_ids.insert(component[i]); clusters.insert(make_pair(component[i], hitvec[i])); } - // cout << "found cluster #: "<< clusters.size()<< endl; - // loop over the componenets and make clusters - cout << PHWHERE << endl; - cout << " -- z0 -- starting loop over clusters -- " << endl; int total_clusters = 0; for (set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) { @@ -357,11 +352,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl; - // make the cluster directly in the node tree - /* cout << PHWHERE << endl; */ - cout << " --> --> --> " << clusid << endl; - ++total_clusters; - /* cout << " FIXME z: component clusid " << clusid << endl; */ + ++total_clusters; auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); // determine the size of the cluster in phi and z @@ -413,9 +404,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) locclusz = loczsum / nhits; const double pitch = layergeom->get_pixel_x(); - // std::cout << " pitch: " << pitch << std::endl; const double length = layergeom->get_pixel_z(); - // std::cout << " length: " << length << std::endl; const double phisize = phibins.size() * pitch; const double zsize = zbins.size() * length; diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index 8183ac24c4..b1a2a52f7c 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -79,16 +79,18 @@ int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } -int MvtxHitPruner::process_event(PHCompositeNode *topNode) -{ - // get node containing the digitized hits +int MvtxHitPruner::process_event(PHCompositeNode *topNode) { m_hits = findNode::getClass(topNode, "TRKR_HITSET"); if (!m_hits) { cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl; return Fun4AllReturnCodes::ABORTRUN; } + return process_TrkrHitSetContainer(m_hits); +} +int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) +{ // We want to combine all strobe values for a given hitset // Start by looping over all MVTX hitsets and making a map of physical sensor to hitsetkey-with-strobe //============================================================================= @@ -96,7 +98,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) std::set bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero) TrkrHitSetContainer::ConstRange hitsetrange = - m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); + _m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr) @@ -120,7 +122,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it) { auto bare_hitsetkey = *bare_it; - TrkrHitSet* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; + TrkrHitSet* bare_hitset = (_m_hits->findOrAddHitSet(bare_hitsetkey))->second; if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl; auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey); @@ -134,7 +136,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) if(Verbosity() > 0) cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; // copy all hits to the hitset with strobe 0 - TrkrHitSet* hitset = m_hits->findHitSet(hitsetkey); + TrkrHitSet* hitset = _m_hits->findHitSet(hitsetkey); if(Verbosity() > 0) std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl; @@ -163,7 +165,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) } // all hits are copied over to the strobe zero hitset, remove this hitset - m_hits->removeHitSet(hitsetkey); + _m_hits->removeHitSet(hitsetkey); } } } diff --git a/offline/packages/mvtx/MvtxHitPruner.h b/offline/packages/mvtx/MvtxHitPruner.h index f62ef39473..11743b4d66 100644 --- a/offline/packages/mvtx/MvtxHitPruner.h +++ b/offline/packages/mvtx/MvtxHitPruner.h @@ -39,6 +39,9 @@ class MvtxHitPruner : public SubsysReco //! end of process int End(PHCompositeNode */*topNode*/) override { return 0; } + // will run process event on the container that is passed in + int process_TrkrHitSetContainer(TrkrHitSetContainer*); + private: // node tree storage pointers diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc index 916a86f849..f94f606950 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -316,13 +316,9 @@ namespace G4Eval { int ClusCntr::addClusKeys(TrkrTruthTrack* track) { phg4_keys.clear(); - std::cout << "FIXME z0: nclusters: " << track->getClusters().size() << std::endl; - int i {0}; for (auto ckey : track->getClusters()) { phg4_keys.push_back( {TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey} ); - std::cout << " i("< truth_keys; */ m_cluscntr.addClusKeys(m_TrkrTruthTrackContainer->getTruthTrack(id_true)); - std::cout << " FIXME NCLUS TRUE: " << (int)m_cluscntr.phg4_nclus() << std::endl; // add the truth keys into the track counter /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); */ /* for (auto& key : truth_track->getClusters()) { */ diff --git a/simulation/g4simulation/g4mvtx/Makefile.am b/simulation/g4simulation/g4mvtx/Makefile.am index 554e7315f2..2e1caf2eb7 100644 --- a/simulation/g4simulation/g4mvtx/Makefile.am +++ b/simulation/g4simulation/g4mvtx/Makefile.am @@ -23,6 +23,7 @@ libg4mvtx_la_LIBADD = \ -lg4detectors \ -ltrack_io \ -lg4tracking_io \ + -lmvtx \ -lmvtx_io pkginclude_HEADERS = \ diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 0d5e292ffe..c7b0ed8eec 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -3,6 +3,7 @@ #include "PHG4MvtxHitReco.h" #include +#include #include #include @@ -178,6 +179,7 @@ int PHG4MvtxHitReco::InitRun(PHCompositeNode *topNode) } m_truth_clusterer = new TruthMvtxClusterBuilder(m_truthclusters, m_truthtracks, Verbosity()); m_truth_clusterer->set_verbosity(Verbosity()); + m_truth_clusterer->set_HitPruner(m_hit_pruner); return Fun4AllReturnCodes::EVENT_OK; } @@ -744,3 +746,4 @@ TrkrDefs::hitsetkey PHG4MvtxHitReco::zero_strobe_bits(TrkrDefs::hitsetkey hitset PHG4MvtxHitReco::~PHG4MvtxHitReco() { delete m_truth_clusterer; } + diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 3f7d751947..42c46c2228 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -17,6 +17,7 @@ class PHCompositeNode; class TrkrTruthTrackContainer; class TrkrClusterContainer; +class MvtxHitPruner; class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface { @@ -42,7 +43,12 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface //! parameters void SetDefaultParameters() override; + //void set_HitPruner(MvtxHitPruner* + void set_HitPruner(MvtxHitPruner* _) { m_hit_pruner = _; }; + private: + MvtxHitPruner* m_hit_pruner; + std::pair generate_alpide_pulse(const double energy_deposited); double generate_strobe_zero_tm_start(); diff --git a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.cc b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.cc index 2cb212fa4c..44c1d5db3a 100644 --- a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.cc +++ b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include // for PHWHERE #include #include @@ -116,6 +117,10 @@ void TruthMvtxClusterBuilder::cluster_hits() { if (m_verbosity > 0) cout << "Entering MvtxClusterizer::ClusterMvtx " << endl; + if (m_MvtxHitPruner) { + m_MvtxHitPruner->process_TrkrHitSetContainer(m_hits); + } + auto track = m_truthtracks->getTruthTrack(trkid, m_truthinfo); //----------- @@ -351,33 +356,32 @@ void TruthMvtxClusterBuilder::cluster_hits() { /* } */ } // clusitr loop } // loop over hitsets + if (m_verbosity>3) std::cout << "track " << track->getTrackid() << " has " << track->getClusters().size() << " mvtx clusters" << std::endl; - - return; - m_hits->Reset(); + return; }; bool TruthMvtxClusterBuilder::are_adjacent(const std::pair &lhs, const std::pair &rhs) { - /* if (GetZClustering()) */ - /* { */ - /* // column is first, row is second */ - /* if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) <= 1) */ - /* { */ - /* if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) */ - /* { */ - /* return true; */ - /* } */ - /* } */ - /* } */ - /* else */ - //{ default to always used - if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) == 0) + if (GetZClustering()) { - if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) + if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) <= 1) { - return true; + if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) + { + return true; + } + } + } + else + { + if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) == 0) + { + if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) + { + return true; + } } } //} diff --git a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h index 1ad6ceba22..2bd53eaea5 100644 --- a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h +++ b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h @@ -38,12 +38,15 @@ class TrkrTruthTrack; class PHG4TruthInfoContainer; class PHG4Hit; +class MvtxHitPruner; + class TruthMvtxClusterBuilder { // member data int trkid {-1}; bool is_emb {false}; PHG4TruthInfoContainer *m_truthinfo {nullptr}; + MvtxHitPruner *m_MvtxHitPruner { nullptr }; // intermediary hits, used to cluster Truth hits TrkrHitSetContainer *m_hits {}; // save the hits as they come along @@ -68,15 +71,31 @@ class TruthMvtxClusterBuilder { void set_verbosity(int _verbosity) { m_verbosity = _verbosity; }; void set_geom_container (PHG4CylinderGeomContainer *_geom_container) { m_geom_container = _geom_container; }; + void set_HitPruner(MvtxHitPruner* _) { m_MvtxHitPruner = _; }; void print_clusters(int nclusters=-1); + //! option to turn off z-dimension clustering + void SetZClustering(const bool make_z_clustering) + { + m_makeZClustering = make_z_clustering; + } + bool GetZClustering() const + { + return m_makeZClustering; + } + private: void cluster_hits(); int m_verbosity {0}; /* bool are_adjacent(RawHit* lhs, RawHit* rhs); */ bool are_adjacent(const std::pair &lhs, const std::pair &rhs); PHG4CylinderGeomContainer* m_geom_container { nullptr }; + + bool m_makeZClustering {true}; // z_clustering_option + bool do_hit_assoc = true; + bool do_read_raw = false; + int m_cluster_version = 4; }; #endif From 98b5d7234109652538a18b1d5e79e825a6f9b62e Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Tue, 21 Mar 2023 20:08:33 -0400 Subject: [PATCH 027/468] Minor update, remove cout statement --- simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index 678156d772..dd6b59cab1 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -38,7 +38,7 @@ FillTruthRecoMatchTree::FillTruthRecoMatchTree( , m_fill_SvU { _fill_SvUnMatched } { m_cluscntr.set_comparer(&m_cluster_comp); - m_tfile = new TFile(_tfile_name.c_str(), "recreate"); + m_tfile = new TFile(_tfile_name.c_str(), "recreate"); m_tfile->cd(); m_ttree = new TTree("T", "Tracks (and sometimes clusters)"); @@ -241,8 +241,6 @@ int FillTruthRecoMatchTree::createNodes(PHCompositeNode *topNode) int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) { - print_mvtx_diagnostics(); - return 0; if (Verbosity()>5) cout << " FillTruthRecoMatchTree::process_event() " << endl; @@ -274,6 +272,7 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) int index_G4U_clusU {0}; int index_SvU_clusU {0}; + if (Verbosity() > 2) std::cout << " getting" << (int) m_EmbRecoMatchContainer->getMatches().size() << std::endl; for (auto& match : m_EmbRecoMatchContainer->getMatches()) { unsigned int g4_trkid = match->idTruthTrack(); @@ -420,6 +419,7 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) m_ttree->Fill(); clear_vectors(); + if (Verbosity()>100) print_mvtx_diagnostics(); return Fun4AllReturnCodes::EVENT_OK; } From c41eb8b7f644f190b243b11b88cd8127c92c8bea Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Wed, 22 Mar 2023 11:51:28 -0400 Subject: [PATCH 028/468] Small updates, comply with gcc and Jenkins --- .../g4eval/FillTruthRecoMatchTree.cc | 2 +- .../g4simulation/g4eval/FillTruthRecoMatchTree.h | 2 +- simulation/g4simulation/g4eval/Tools.cc | 7 +++---- simulation/g4simulation/g4eval/Tools.h | 16 +++++++++------- simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h | 2 +- .../g4mvtx/TruthMvtxClusterBuilder.h | 6 +++--- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index dd6b59cab1..6800907ef7 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -30,7 +30,7 @@ FillTruthRecoMatchTree::FillTruthRecoMatchTree( , bool _fill_SvUnMatched , float _cluster_nzwidths , float _cluster_nphiwidths - , const std::string _tfile_name + , const std::string& _tfile_name ) : m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index 47e3114747..8005af8612 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -76,7 +76,7 @@ class FillTruthRecoMatchTree : public SubsysReco , bool _fill_svtxnomatch = false , float _cluster_nzwidths = 0.5 , float _cluster_nphiwidths = 0.5 - , const std::string tfile_name="trackclusmatch.root" + , const std::string& tfile_name="trackclusmatch.root" ); virtual ~FillTruthRecoMatchTree(); diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc index f94f606950..07e38fa726 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -46,8 +46,7 @@ namespace G4Eval { // function implementation mostly from // https://root-forum.cern.ch/t/is-it-possible-to-save-plain-text-in-a-root-file/27674/4 // Note that there is also the code there to read it back from a TFile - void write_StringToTFile(std::string msg_name - , std::string msg) + void write_StringToTFile(const std::string& msg_name, const std::string& msg) { //the string is either written to the current file, or to a new file //that is named f_outname @@ -77,8 +76,8 @@ namespace G4Eval { m_nz_widths { _nz_widths } {}; int TrkrClusterComparer::init(PHCompositeNode* topNode, - std::string name_phg4_clusters, - std::string name_reco_clusters) + const std::string& name_phg4_clusters, + const std::string& name_reco_clusters) { // fill bin/pixel sizes // ------ MVTX data ------ diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h index 87bd6c9dd3..04b2f2e83a 100644 --- a/simulation/g4simulation/g4eval/Tools.h +++ b/simulation/g4simulation/g4eval/Tools.h @@ -8,6 +8,7 @@ #include #include #include +#include /* #include */ class ActsGeometry; @@ -24,7 +25,7 @@ namespace G4Eval { // Following function writes msg to the currently active TFile // if f_outname is provided, then it will write the message to a new // TFiles of that name and close it again. - void write_StringToTFile(std::string msg_name, std::string msg); + void write_StringToTFile(const std::string& msg_name, const std::string& msg); std::vector unmatchedSvtxTrkIds(EmbRecoMatchContainer*, SvtxTrackMap*); @@ -33,8 +34,8 @@ namespace G4Eval { public: TrkrClusterComparer (float _nphi_widths=0.5, float _nz_widths=0.5 ); int init(PHCompositeNode* topNode, - std::string name_truth_clusters="TRKR_TRUTHCLUSTERCONTAINER", - std::string name_reco_clusters="TRKR_CLUSTER"); + const std::string& name_truth_clusters="TRKR_TRUTHCLUSTERCONTAINER", + const std::string&name_reco_clusters="TRKR_CLUSTER"); bool status_good {false}; TrkrCluster* clus_T {nullptr}; @@ -47,10 +48,11 @@ namespace G4Eval { // Members that are set with each set of cluster keys that // are passed to it. // z and phi locations of phg4 hit (T) and Svtx hit (R) - float z_T, z_R, phi_T, phi_R; - float phisize_R, phisize_T, zsize_R, zsize_T; // sizes are in pixels/layers - float phi_delta; // abs(phi_T-phi_R) - float z_delta; // abs(z_T-z_R) + float z_T { FLT_MAX }, z_R { FLT_MAX }; + float phi_T { FLT_MAX }, phi_R { FLT_MAX }; + float phisize_R { FLT_MAX }, phisize_T { FLT_MAX }; + float zsize_R { FLT_MAX }, zsize_T { FLT_MAX }; + float phi_delta { FLT_MAX }, z_delta { FLT_MAX }; // abs(z_T-z_R) bool in_tpc {false}; bool in_mvtx {false}; diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 42c46c2228..74ea4d748c 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -47,7 +47,7 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface void set_HitPruner(MvtxHitPruner* _) { m_hit_pruner = _; }; private: - MvtxHitPruner* m_hit_pruner; + MvtxHitPruner* m_hit_pruner { nullptr }; std::pair generate_alpide_pulse(const double energy_deposited); diff --git a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h index 2bd53eaea5..7b5313a213 100644 --- a/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h +++ b/simulation/g4simulation/g4mvtx/TruthMvtxClusterBuilder.h @@ -93,9 +93,9 @@ class TruthMvtxClusterBuilder { PHG4CylinderGeomContainer* m_geom_container { nullptr }; bool m_makeZClustering {true}; // z_clustering_option - bool do_hit_assoc = true; - bool do_read_raw = false; - int m_cluster_version = 4; + /* bool do_hit_assoc = true; */ + /* bool do_read_raw = false; */ + /* int m_cluster_version = 4; */ }; #endif From cd825be14b09567ed579e40296ff03cbecc06de5 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Wed, 22 Mar 2023 11:58:35 -0400 Subject: [PATCH 029/468] Jenkins cpp check initialization --- simulation/g4simulation/g4eval/Tools.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h index 04b2f2e83a..569e17a138 100644 --- a/simulation/g4simulation/g4eval/Tools.h +++ b/simulation/g4simulation/g4eval/Tools.h @@ -37,10 +37,10 @@ namespace G4Eval { const std::string& name_truth_clusters="TRKR_TRUTHCLUSTERCONTAINER", const std::string&name_reco_clusters="TRKR_CLUSTER"); - bool status_good {false}; - TrkrCluster* clus_T {nullptr}; - TrkrCluster* clus_R {nullptr}; - int layer; + TrkrCluster* clus_T { nullptr }; + TrkrCluster* clus_R { nullptr }; + bool status_good { false }; + int layer { INT_MAX }; std::pair operator() // return pair(is_matched,how_good_match) (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R); From 2c0ec78a9a9b00e9c1dc3af52e9877338ef806ca Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Wed, 22 Mar 2023 14:35:01 -0400 Subject: [PATCH 030/468] update for Jenkins --- simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h | 5 ----- simulation/g4simulation/g4eval/Tools.h | 1 - 2 files changed, 6 deletions(-) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index 8005af8612..7142f2e108 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -93,11 +93,6 @@ class FillTruthRecoMatchTree : public SubsysReco private: int createNodes(PHCompositeNode *topNode); - // if looking for matched and un-matched clusters, need - // the matching criteria. - // This should match that in TruthRecoTrackMatching - double _cluster_nzwidths { 0.5 }; - double _cluster_nphiwidths { 0.5 }; G4Eval::TrkrClusterComparer m_cluster_comp; G4Eval::ClusCntr m_cluscntr; diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/Tools.h index 569e17a138..44bd78069f 100644 --- a/simulation/g4simulation/g4eval/Tools.h +++ b/simulation/g4simulation/g4eval/Tools.h @@ -119,7 +119,6 @@ namespace G4Eval { TrkrClusterComparer* comp; std::array cntclus(Vector& keys); std::array cnt_matchedclus(Vector& keys, std::vector& matches); - ActsGeometry* geom {nullptr}; public: ClusCntr(TrkrClusterComparer*_=nullptr) : comp{_} {}; From 0d4fe73e02e8120e7c6dcd4f4b1c2dedf251f9da Mon Sep 17 00:00:00 2001 From: bogui56 Date: Thu, 23 Mar 2023 12:34:45 -0400 Subject: [PATCH 031/468] add proper dynamic cast to use cluster v5 --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 6 ++++-- offline/packages/trackreco/PHActsTrkFitter.cc | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index f99f154bb5..b77d6c102d 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -571,8 +572,9 @@ SpacePointPtr PHActsSiliconSeeding::makeSpacePoint( localCov(0,0) = para_errors.first* Acts::UnitConstants::cm2; localCov(1,1) = para_errors.second* Acts::UnitConstants::cm2; }else if(m_cluster_version==5){ - localCov(0,0) = pow(clus->getRPhiError(),2) * Acts::UnitConstants::cm2; - localCov(1,1) = pow(clus->getZError(),2) * Acts::UnitConstants::cm2; + TrkrClusterv5 *clusterv5 = dynamic_cast (clus); + localCov(0,0) = pow(clusterv5->getRPhiError(),2) * Acts::UnitConstants::cm2; + localCov(1,1) = pow(clusterv5->getZError(),2) * Acts::UnitConstants::cm2; } float x = globalPos.x(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 2f514bcace..0d3e88b29e 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -10,6 +10,7 @@ /// Tracking includes #include #include +#include #include #include #include @@ -704,10 +705,11 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; }else if(m_cluster_version==5){ - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(cluster->getRPhiError(),2) * Acts::UnitConstants::cm2; + TrkrClusterv5 *clusterv5 = dynamic_cast (cluster); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(clusterv5->getRPhiError(),2) * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(cluster->getZError(),2) * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(clusterv5->getZError(),2) * Acts::UnitConstants::cm2; } ActsSourceLink::Index index = measurements.size(); From 31a7199aa7446c3687543b07b3240abbdd48b9d4 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 23 Mar 2023 15:10:01 -0400 Subject: [PATCH 032/468] Added background subtraction to clusters before meta-clustering. New radial matching method. --- .../PHTpcCentralMembraneClusterizer.cc | 204 ++++++++++++++++-- .../PHTpcCentralMembraneClusterizer.h | 28 +++ .../tpccalib/PHTpcCentralMembraneMatcher.cc | 138 +++++++++--- 3 files changed, 330 insertions(+), 40 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index f9052d1de5..f201c1906f 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -59,6 +59,9 @@ int PHTpcCentralMembraneClusterizer::InitRun(PHCompositeNode *topNode) henergy = new TH1F("henergy", "cluster energy", 200, 0, 2000); hxy = new TH2F("hxy","cluster x:y",800,-100,100,800,-80,80); hz = new TH1F("hz","cluster z", 220, -2,2); + + hz_pos = new TH1F("hz_pos","cluster z>0", 400, 0,110); + hz_neg = new TH1F("hz_neg","cluster z<0", 400, -110,0); hClustE[0]= new TH1F("hRawClusterEnergy","Cluster Energy Before Merging;E[?]",200,0,2000); hClustE[1] = new TH1F("hMatchedClusterEnergy","Pair Cluster Energy After Merging;E[?]",200,0,2000); @@ -70,6 +73,27 @@ int PHTpcCentralMembraneClusterizer::InitRun(PHCompositeNode *topNode) hDistRowAdj=new TH2F("hDistRowAdj","phi distance to nearby clusters vs (lower)row;dist[rad];(lower) padrow",100,-0.001,0.01,60,-0.5,59.5); hDist2Adj=new TH1F("hDist2Adj","phi distance to nearby clusters on adjacent padrow;dist[rad]",100,-0.001,0.01); } + + m_histogramfileMaps.reset( new TFile(m_histogramfilenameMaps.c_str(), "RECREATE")); + m_histogramfileMaps->cd(); + + + hrPhi_reco_pos = new TH2F("hrPhi_reco_pos","Reco R vs #phi Z > 0;#phi;R (cm)",400,-M_PI,M_PI,400,20,78); + hrPhi_reco_neg = new TH2F("hrPhi_reco_neg","Reco R vs #phi Z < 0;#phi;R (cm)",400,-M_PI,M_PI,400,20,78); + + hrPhi_reco_petalModulo_pos = new TH2F("hrPhi_reco_petalModulo_pos","Reco R vs #phi Z > 0;#phi;R (cm)",50,0.0,M_PI/9,400,20,78); + hrPhi_reco_petalModulo_neg = new TH2F("hrPhi_reco_petalModulo_neg","Reco R vs #phi;#phi Z < 0;R (cm)",50,0.0,M_PI/9,400,20,78); + + for(int i=0; i<48; i++){ + hphi_reco_pos[i] = new TH1F(Form("hphi_reco_pos_layer%02d",7+i),Form("Reco #phi for Layer %02d Z > 0;#phi;counts",7+i),50,0.0,M_PI/9); + hphi_reco_neg[i] = new TH1F(Form("hphi_reco_neg_layer%02d",7+i),Form("Reco #phi for Layer %02d Z < 0;#phi;counts",7+i),50,0.0,M_PI/9); + + if(i<47){ + hphi_reco_pair_pos[i] = new TH1F(Form("hphi_reco_pair_pos_layers%02d_%02d",7+i,8+i),Form("Reco #phi for Layers %02d and %02d Z > 0;#phi;counts",7+i,8+i),50,0.0,M_PI/9); + hphi_reco_pair_neg[i] = new TH1F(Form("hphi_reco_pair_neg_layers%02d_%02d",7+i,8+i),Form("Reco #phi for Layers %02d and %02d Z < 0;#phi;counts",7+i,8+i),50,0.0,M_PI/9); + + } + } return ret; } @@ -93,8 +117,67 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vector side; // cluster side std::vectori_pair; //vector for pair matching std::vectorenergy;//vector for energy values of clusters + std::vectorisAcrossGap; int nTpcClust = 0; + + for(const auto& hitsetkey:_cluster_map->getHitSetKeys(TrkrDefs::TrkrId::tpcId)) + { + auto clusRange = _cluster_map->getClusters(hitsetkey); + for (auto clusiter = clusRange.first; + clusiter != clusRange.second; ++clusiter) + { + + const auto& [cluskey, cluster] = *clusiter; + auto glob = tgeometry->getGlobalPosition(cluskey, cluster); + TVector3 tmp_pos(glob(0),glob(1),glob(2)); + + unsigned int layer = TrkrDefs::getLayer(cluskey); + + double phi = tmp_pos.Phi(); + + double phiMod = phi; + + while(phiMod < 0.0 || phiMod > M_PI/9){ + if(phiMod < 0.0) phiMod += M_PI/9; + else if(phiMod > M_PI/9) phiMod -= M_PI/9; + } + + if(tmp_pos.Z() >= 0.0){ + + hz_pos->Fill(tmp_pos.Z()); + + hrPhi_reco_petalModulo_pos->Fill(phiMod, tmp_pos.Perp()); + hphi_reco_pos[layer-7]->Fill(phiMod); + if(layer < 54) hphi_reco_pair_pos[layer-7]->Fill(phiMod); + if(layer > 7) hphi_reco_pair_pos[layer-8]->Fill(phiMod); + }else{ + + hz_neg->Fill(tmp_pos.Z()); + + hrPhi_reco_petalModulo_neg->Fill(phiMod, tmp_pos.Perp()); + hphi_reco_neg[layer-7]->Fill(phiMod); + if(layer < 54) hphi_reco_pair_neg[layer-7]->Fill(phiMod); + if(layer > 7) hphi_reco_pair_neg[layer-8]->Fill(phiMod); + } + + } + } + + + for(int i=0; i<47; i++){ + for(int j=1; jGetNbinsX(); j++){ + if(hphi_reco_pair_pos[i]->GetBinContent(j) > m_metaClusterThreshold){ + nPairAbove_pos[i]++; + pairAboveContent_pos[i] += (hphi_reco_pair_pos[i]->GetBinContent(j)-m_metaClusterThreshold); + } + if(hphi_reco_pair_neg[i]->GetBinContent(j) > m_metaClusterThreshold){ + nPairAbove_neg[i]++; + pairAboveContent_neg[i] += (hphi_reco_pair_neg[i]->GetBinContent(j)-m_metaClusterThreshold); + } + } + } + for(const auto& hitsetkey:_cluster_map->getHitSetKeys(TrkrDefs::TrkrId::tpcId)) { auto clusRange = _cluster_map->getClusters(hitsetkey); @@ -106,7 +189,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) const auto& [cluskey, cluster] = *clusiter; auto glob = tgeometry->getGlobalPosition(cluskey, cluster); - // std::cout << "PHTpcCentralMembraneClusterizer::process_event - key: " << cluskey << "z: " << glob.z() << std::endl; + // std::cout << "PHTpcCentralMembraneClusterizer::process_event - key: " << cluskey << "z: " << glob.z() << std::endl; float x = glob(0); float y = glob(1); @@ -118,13 +201,45 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) unsigned short side = TpcDefs::getSide(cluskey); std::cout << " z " << z << " side " << side << " layer " << lyr << " Adc " << cluster->getAdc() << " x " << x << " y " << y << std::endl; } + + TVector3 tmp_pos(x,y,z); + + unsigned int lay = TrkrDefs::getLayer(cluskey); + + double phi = tmp_pos.Phi(); + double phiMod = phi; + + while(phiMod < 0.0 || phiMod > M_PI/9){ + if(phiMod < 0.0) phiMod += M_PI/9; + else if(phiMod > M_PI/9) phiMod -= M_PI/9; + } + + int phiBin = -1; + + bool aboveThreshold = true; + + if(z >= 0){ + phiBin = hphi_reco_pos[lay-7]->GetXaxis()->FindBin(phiMod); + if(hphi_reco_pos[lay-7]->GetBinContent(phiBin) < 5) aboveThreshold = false; + }else{ + phiBin = hphi_reco_neg[lay-7]->GetXaxis()->FindBin(phiMod); + if(hphi_reco_neg[lay-7]->GetBinContent(phiBin) < 5) aboveThreshold = false; + } + + if( !aboveThreshold ) continue; if(cluster->getAdc() < _min_adc_value) continue; if( std::abs(z) < _min_z_value) continue; + if( (z>=0 && std::abs(z - hz_pos->GetBinCenter(hz_pos->GetMaximumBin())) > 1.0) || (z<0 && std::abs(z - hz_neg->GetBinCenter(hz_neg->GetMaximumBin())) > 1.0) ) continue; + // if(removeSector && TpcDefs::getSide(cluskey) > 0 && TpcDefs::getSectorId(cluskey) == 1 && TrkrDefs::getLayer(cluskey) < 38) continue; if(removeSector && TpcDefs::getSide(cluskey) > 0 && TrkrDefs::getLayer(cluskey) < 38) continue; + + if(z >= 0) hrPhi_reco_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + else hrPhi_reco_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + ++m_accepted_clusters; i_pair.push_back(-1); @@ -133,7 +248,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) pos.push_back(TVector3(x,y,z)); layer.push_back((int)(TrkrDefs::getLayer(cluskey))); side.push_back(TpcDefs::getSide(cluskey)); - + isAcrossGap.push_back(false); if(Verbosity() > 0) std::cout << ":\t" << x << "\t" << y << "\t" << z <= 0 ){ + if(layer[i] == 7){ + if(nPairAbove_pos[layer[i]-7] >= 3) layerMatch = layer[i]+1; + }else if(layer[i] == 54){ + if(nPairAbove_pos[layer[i]-8] >= 3) layerMatch = layer[i]-1; + }else{ + if(nPairAbove_pos[layer[i]-7] >=3 && nPairAbove_pos[layer[i]-8] >=3){ + if(pairAboveContent_pos[layer[i]-7]/nPairAbove_pos[layer[i]-7] > pairAboveContent_pos[layer[i]-8]/nPairAbove_pos[layer[i]-8]) layerMatch = layer[i]+1; + else layerMatch = layer[i]-1; + }else if(nPairAbove_pos[layer[i]-7] >=3) layerMatch = layer[i]+1; + else if(nPairAbove_pos[layer[i]-8] >=3) layerMatch = layer[i]-1; + } + }else{ + if(layer[i] == 7){ + if(nPairAbove_neg[layer[i]-7] >= 3) layerMatch = layer[i]+1; + }else if(layer[i] == 54){ + if(nPairAbove_neg[layer[i]-8] >= 3) layerMatch = layer[i]-1; + }else{ + if(nPairAbove_neg[layer[i]-7] >=3 && nPairAbove_neg[layer[i]-8] >=3){ + if(pairAboveContent_neg[layer[i]-7]/nPairAbove_neg[layer[i]-7] > pairAboveContent_neg[layer[i]-8]/nPairAbove_neg[layer[i]-8]) layerMatch = layer[i]+1; + else layerMatch = layer[i]-1; + }else if(nPairAbove_neg[layer[i]-7] >=3) layerMatch = layer[i]+1; + else if(nPairAbove_neg[layer[i]-8] >=3) layerMatch = layer[i]-1; + } + } + + + if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39) ) isAcrossGap[i] = true; + float bestphidist=maxphidist; for (int j=0;j 0.5) continue; @@ -194,6 +346,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) { i_pair[i]=j; bestphidist=newphidist; + } } } @@ -241,11 +394,11 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vector nclusters; std::vector isREdge; - int nR2 = 0; - int nR3 = 0; + // int nR2 = 0; + //int nR3 = 0; - double R2AveE = 0.0; - double R3AveE = 0.0; + // double R2AveE = 0.0; + //double R3AveE = 0.0; for (int i=0;i 0) @@ -334,9 +486,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); nclusters.push_back(1); - if( (layer[i] == 22 && layer[i_pair[i]] == 23) || (layer[i] == 23 && layer[i_pair[i]] == 22) || (layer[i] == 38 && layer[i_pair[i]] == 39) || (layer[i] == 39 || layer[i_pair[i]] == 38) ) isREdge.push_back(true); - else isREdge.push_back(false); - } + isREdge.push_back(isAcrossGap[i]); + } } // Loop over the vectors and put the clusters on the node tree @@ -402,6 +553,9 @@ int PHTpcCentralMembraneClusterizer::End(PHCompositeNode * /*topNode*/ ) hxy->Write(); hz->Write(); + hz_pos->Write(); + hz_neg->Write(); + hClustE[0]->Write(); hClustE[1]->Write(); hClustE[2]->Write(); @@ -413,6 +567,28 @@ int PHTpcCentralMembraneClusterizer::End(PHCompositeNode * /*topNode*/ ) m_histogramfile->Close(); } + + m_histogramfileMaps->cd(); + + hrPhi_reco_pos->Write(); + hrPhi_reco_neg->Write(); + + hrPhi_reco_petalModulo_pos->Write(); + hrPhi_reco_petalModulo_neg->Write(); + + for(int i=0; i<48; i++){ + hphi_reco_pos[i]->Write(); + hphi_reco_neg[i]->Write(); + + if(i<47){ + hphi_reco_pair_pos[i]->Write(); + hphi_reco_pair_neg[i]->Write(); + } + } + + m_histogramfileMaps->Close(); + + // print statistics if( Verbosity() ) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h index e962a4f0b7..6b86b00756 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h @@ -47,6 +47,8 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco void set_removeSector(bool a_removeSector){ removeSector = a_removeSector; } + void set_metaCluster_threshold( int val ) { m_metaClusterThreshold = val; } + //! run initialization int InitRun(PHCompositeNode *topNode); @@ -80,10 +82,14 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco int m_cm_clusters_size1 = 0; int m_cm_clusters_size2 = 0; //@} + + int m_metaClusterThreshold = 18; bool _histos = false; TH1F *henergy = nullptr; TH1F *hz = nullptr; + TH1F *hz_pos = nullptr; + TH1F *hz_neg = nullptr; TH2F *hxy = nullptr; TH1F *hDist = nullptr; TH2F *hDistRow = nullptr; @@ -91,9 +97,31 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco TH2F *hDistRowAdj = nullptr; TH1F *hDist2Adj = nullptr; TH1F *hClustE[3] = {nullptr}; + + TH2F *hrPhi_reco_pos = nullptr; + TH2F *hrPhi_reco_neg = nullptr; + + TH2F *hrPhi_reco_petalModulo_pos = nullptr; + TH2F *hrPhi_reco_petalModulo_neg = nullptr; + TH1F *hphi_reco_pos[48] = {nullptr}; + TH1F *hphi_reco_neg[48] = {nullptr}; + + TH1F *hphi_reco_pair_pos[47] = {nullptr}; + TH1F *hphi_reco_pair_neg[47] = {nullptr}; + + int nPairAbove_pos[47] = {0}; + int nPairAbove_neg[47] = {0}; + + double pairAboveContent_pos[47] = {0.0}; + double pairAboveContent_neg[47] = {0.0}; + std::string m_histogramfilename = "PHTpcCentralMembraneClusterizer.root"; std::unique_ptr m_histogramfile; + + + std::string m_histogramfilenameMaps = "CentralMembraneClusterizer_reco_maps.root"; + std::unique_ptr m_histogramfileMaps; unsigned int _min_adc_value = 0; double _min_z_value = 0.0; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index f4704ff964..934f836024 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -174,14 +174,16 @@ double PHTpcCentralMembraneMatcher::getPhiRotation_smoothed(TH1D *hitHist, TH1D gStyle->SetOptFit(1); hitHist->Smooth(); - // clustHist->Smooth(); + clustHist->Smooth(); TF1 *f1 = new TF1("f1",[&](double *x, double *p){ return p[0] * hitHist->GetBinContent(hitHist->FindBin(x[0] - p[1])); }, -M_PI, M_PI, 2); f1->SetParNames("A","shift"); f1->SetParameters(1.0,0.0); // f1->SetParLimits(1,-M_PI/18,M_PI/18); - clustHist->Fit("f1","IL"); + f1->SetNpx(500); + + clustHist->Fit("f1","I"); clustHist->Draw(); f1->Draw("same"); @@ -264,7 +266,7 @@ std::vector PHTpcCentralMembraneMatcher::getAverageRotation(std::vector< std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ - TH1D *proj = r_phi->ProjectionY("R_proj",1,360); + TH1D *proj = r_phi->ProjectionY("R_proj"); std::vector rPeaks; @@ -274,8 +276,8 @@ std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ for(int i=0; i<(int)rPeaks.size()-1; i++){ if(rPeaks[i+1]-rPeaks[i] > 0.75) continue; - if(proj->GetBinContent(proj->FindBin(rPeaks[i])) > proj->GetBinContent(proj->FindBin(rPeaks[i+1]))) rPeaks.erase(std::next(rPeaks.begin(), i+1)); - else rPeaks.erase(std::next(rPeaks.begin(), i)); + if(proj->GetBinContent(proj->FindBin(rPeaks[i])) > proj->GetBinContent(proj->FindBin(rPeaks[i+1]))) rPeaks.erase(rPeaks.begin()+i+1); + else rPeaks.erase(rPeaks.begin()+i); i--; } return rPeaks; @@ -537,8 +539,12 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) // std::cout << "cmkey " << cmkey << " R: " << tmp_pos.Perp() << " isgap: " << isRGap << std::endl; - if(isRGap) continue; + // if(isRGap && Verbosity() > 2) std::cout << "here!" << std::endl; + // if(isRGap && nclus == 1) continue; + + if(isRGap) continue; + reco_pos.push_back(tmp_pos); reco_nclusters.push_back(nclus); @@ -652,35 +658,78 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) std::vector clust_RPeaks_neg = getRPeaks(clust_r_phi_neg); std::vector clust_RGaps_pos; + int R12Gap_pos = -1; int R23Gap_pos = -1; - for(int i=0; i<(int)clust_RPeaks_pos.size()-1; i++){ - clust_RGaps_pos.push_back(clust_RPeaks_pos[i+1] - clust_RPeaks_pos[i]); - if(clust_RGaps_pos[i] >= 2.5) R23Gap_pos = i; + for(int i=0; i<(int)clust_RPeaks_pos.size()-1; i++) clust_RGaps_pos.push_back(clust_RPeaks_pos[i+1] - clust_RPeaks_pos[i]); + int tmpGap_pos = std::distance(clust_RGaps_pos.begin(),std::max_element(clust_RGaps_pos.begin(),clust_RGaps_pos.end())); + if(tmpGap_pos > (int)clust_RGaps_pos.size()/2){ + R23Gap_pos = tmpGap_pos; + R12Gap_pos = std::distance(clust_RGaps_pos.begin(),std::max_element(clust_RGaps_pos.begin(),clust_RGaps_pos.begin()+R23Gap_pos)); + }else{ + R12Gap_pos = tmpGap_pos; + R23Gap_pos = std::distance(clust_RGaps_pos.begin(),std::max_element(clust_RGaps_pos.begin()+R12Gap_pos+1,clust_RGaps_pos.end())); } + std::cout << "R12Gap_pos: " << R12Gap_pos << std::endl; std::cout << "R23Gap_pos: " << R23Gap_pos << std::endl; + + std::cout << "pos region sizes R1: " << R12Gap_pos+1 << " R2: " << R23Gap_pos-R12Gap_pos << " R3: " << (int)clust_RGaps_pos.size()-R23Gap_pos << std::endl; + std::vector clust_RGaps_neg; + int R12Gap_neg = -1; int R23Gap_neg = -1; - for(int i=0; i<(int)clust_RPeaks_neg.size()-1; i++){ - clust_RGaps_neg.push_back(clust_RPeaks_neg[i+1] - clust_RPeaks_neg[i]); - if(clust_RGaps_neg[i] >= 2.5) R23Gap_neg = i; + for(int i=0; i<(int)clust_RPeaks_neg.size()-1; i++) clust_RGaps_neg.push_back(clust_RPeaks_neg[i+1] - clust_RPeaks_neg[i]); + int tmpGap_neg = std::distance(clust_RGaps_neg.begin(),std::max_element(clust_RGaps_neg.begin(),clust_RGaps_neg.end())); + if(tmpGap_neg > (int)clust_RGaps_neg.size()/2){ + R23Gap_neg = tmpGap_neg; + R12Gap_neg = std::distance(clust_RGaps_neg.begin(),std::max_element(clust_RGaps_neg.begin(),clust_RGaps_neg.begin()+R23Gap_neg)); + }else{ + R12Gap_neg = tmpGap_neg; + R23Gap_neg = std::distance(clust_RGaps_neg.begin(),std::max_element(clust_RGaps_neg.begin()+R12Gap_neg+1,clust_RGaps_neg.end())); } + std::cout << "R12Gap_neg: " << R12Gap_neg << std::endl; std::cout << "R23Gap_neg: " << R23Gap_neg << std::endl; + std::cout << "neg region sizes R1: " << R12Gap_neg+1 << " R2: " << R23Gap_neg-R12Gap_neg << " R3: " << (int)clust_RGaps_neg.size()-R23Gap_neg << std::endl; + + std::cout << "hit matches pos = {"; std::vector hitMatches_pos; for(int i=0; i<(int)clust_RPeaks_pos.size(); i++){ - hitMatches_pos.push_back(i + 23 - R23Gap_pos); - if(i<(int)clust_RPeaks_pos.size()-1) std::cout << " " << i + 23 - R23Gap_pos << ","; - else std::cout << " " << i + 23 - R23Gap_pos << "}" << std::endl; + + if(i < (R12Gap_pos+1)){ + hitMatches_pos.push_back(15 + i - R12Gap_pos ); + if(clust_RGaps_pos[R12Gap_pos] > 3.6) hitMatches_pos[i] -= 1; + if(clust_RGaps_pos[R12Gap_pos] > 4.6) hitMatches_pos[i] -= 1; + if(clust_RGaps_pos[R12Gap_pos] > 5.8) hitMatches_pos[i] -= 1; + + } + else if(i < (R23Gap_pos+1) && i >= (R12Gap_pos+1)) hitMatches_pos.push_back(15+1 + i - (R12Gap_pos+1)); + else if(i >= R23Gap_pos+1) hitMatches_pos.push_back(23+1 + i - (R23Gap_pos+1)); + + + // hitMatches_pos.push_back(i + 23 - R23Gap_pos); + if(i<(int)clust_RPeaks_pos.size()-1) std::cout << " " << hitMatches_pos[i] << ","; + else std::cout << " " << hitMatches_pos[i] << "}" << std::endl; } std::cout << "hit matches neg = {"; std::vector hitMatches_neg; for(int i=0; i<(int)clust_RPeaks_neg.size(); i++){ - hitMatches_neg.push_back(i + 23 - R23Gap_neg); - if(i<(int)clust_RPeaks_neg.size()-1) std::cout << " " << i + 23 - R23Gap_neg << ","; - else std::cout << " " << i + 23 - R23Gap_neg << "}" << std::endl; + + if(i < (R12Gap_neg+1)){ + + hitMatches_neg.push_back(15 + i - R12Gap_neg ); + if(clust_RGaps_neg[R12Gap_neg] > 3.6) hitMatches_neg[i] -= 1; + if(clust_RGaps_neg[R12Gap_neg] > 4.6) hitMatches_neg[i] -= 1; + if(clust_RGaps_neg[R12Gap_neg] > 5.8) hitMatches_neg[i] -= 1; + } + else if(i < (R23Gap_neg+1) && i >= (R12Gap_neg+1)) hitMatches_neg.push_back(15+1 + i - (R12Gap_neg+1)); + else if(i >= R23Gap_neg+1) hitMatches_neg.push_back(23+1 + i - (R23Gap_neg+1)); + + // hitMatches_neg.push_back(i + 23 - R23Gap_neg); + if(i<(int)clust_RPeaks_neg.size()-1) std::cout << " " << hitMatches_neg[i] << ","; + else std::cout << " " << hitMatches_neg[i] << "}" << std::endl; } @@ -1082,11 +1131,42 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) m_dcc_out_aggregated.reset( new TpcDistortionCorrectionContainer ); // compute axis limits to include guarding bins, needed for TH2::Interpolate to work - const float phiMin = m_phiMin - (m_phiMax-m_phiMin)/m_phibins; - const float phiMax = m_phiMax + (m_phiMax-m_phiMin)/m_phibins; + // const float phiMin = m_phiMin - (m_phiMax-m_phiMin)/m_phibins; + // const float phiMax = m_phiMax + (m_phiMax-m_phiMin)/m_phibins; - const float rMin = m_rMin - (m_rMax-m_rMin)/m_rbins; - const float rMax = m_rMax + (m_rMax-m_rMin)/m_rbins; + // const float rMin = m_rMin - (m_rMax-m_rMin)/m_rbins; + // const float rMax = m_rMax + (m_rMax-m_rMin)/m_rbins; + + double r_bins_mm[69] = {217.83-2,217.83, + 223.83, 229.83, 235.83, 241.83, 247.83, 253.83, 259.83, 265.83, 271.83, 277.83, 283.83, 289.83, 295.83, 301.83, 306.83, + 311.05, 317.92, 323.31, 329.27, 334.63, 340.59, 345.95, 351.91, 357.27, 363.23, 368.59, 374.55, 379.91, 385.87, 391.23, 397.19, 402.49, + 411.53, 421.70, 431.90, 442.11, 452.32, 462.52, 472.73, 482.94, 493.14, 503.35, 513.56, 523.76, 533.97, 544.18, 554.39, 564.59, 574.76, + 583.67, 594.59, 605.57, 616.54, 627.51, 638.48, 649.45, 660.42, 671.39, 682.36, 693.33, 704.30, 715.27, 726.24, 737.21, 748.18, 759.11, 759.11+2}; + + double r_bins[69]; + + for(int i=0; i<69; i++){ + r_bins[i] = r_bins_mm[i]/10.0; + } + + + + double phiBins[206] = { 0., 6.3083-2 * M_PI, 6.3401-2 * M_PI, 6.372-2 * M_PI, 6.4039-2 * M_PI, 6.4358-2 * M_PI, 6.4676-2 * M_PI, 6.4995-2 * M_PI, 6.5314-2 * M_PI, + 0.2618, 0.2937, 0.3256, 0.3574, 0.3893, 0.4212, 0.453, 0.4849, 0.5168, 0.5487, 0.5805, 0.6124, 0.6443, 0.6762, 0.7081, + 0.7399, 0.7718, 0.7854, 0.8173, 0.8491, 0.881, 0.9129, 0.9448, 0.9767, 1.0085, 1.0404, 1.0723, 1.1041, 1.136, 1.1679, + 1.1998, 1.2317, 1.2635, 1.2954, 1.309, 1.3409, 1.3727, 1.4046, 1.4365, 1.4684, 1.5002, 1.5321, 1.564, 1.5959, 1.6277, + 1.6596, 1.6915, 1.7234, 1.7552, 1.7871, 1.819, 1.8326, 1.8645, 1.8963, 1.9282, 1.9601, 1.992, 2.0238, 2.0557, 2.0876, + 2.1195, 2.1513, 2.1832, 2.2151, 2.247, 2.2788, 2.3107, 2.3426, 2.3562, 2.3881, 2.42, 2.4518, 2.4837, 2.5156, 2.5474, + 2.5793, 2.6112, 2.6431, 2.6749, 2.7068, 2.7387, 2.7706, 2.8024, 2.8343, 2.8662, 2.8798, 2.9117, 2.9436, 2.9754, 3.0073, + 3.0392, 3.0711, 3.1029, 3.1348, 3.1667, 3.1986, 3.2304, 3.2623, 3.2942, 3.326, 3.3579, 3.3898, 3.4034, 3.4353, 3.4671, + 3.499, 3.5309, 3.5628, 3.5946, 3.6265, 3.6584, 3.6903, 3.7221, 3.754, 3.7859, 3.8178, 3.8496, 3.8815, 3.9134, 3.927, + 3.9589, 3.9907, 4.0226, 4.0545, 4.0864, 4.1182, 4.1501, 4.182, 4.2139, 4.2457, 4.2776, 4.3095, 4.3414, 4.3732, 4.4051, + 4.437, 4.4506, 4.4825, 4.5143, 4.5462, 4.5781, 4.61, 4.6418, 4.6737, 4.7056, 4.7375, 4.7693, 4.8012, 4.8331, 4.865, + 4.8968, 4.9287, 4.9606, 4.9742, 5.0061, 5.0379, 5.0698, 5.1017, 5.1336, 5.1654, 5.1973, 5.2292, 5.2611, 5.2929, 5.3248, + 5.3567, 5.3886, 5.4204, 5.4523, 5.4842, 5.4978, 5.5297, 5.5615, 5.5934, 5.6253, 5.6572, 5.689, 5.7209, 5.7528, 5.7847, + 5.8165, 5.8484, 5.8803, 5.9122, 5.944, 5.9759, 6.0078, 6.0214, 6.0533, 6.0851, 6.117, 6.1489, 6.1808, 6.2127, 6.2445, + 6.2764, 2 * M_PI}; + // reset all output distortion container so that they match the requested grid size const std::array extension = {{ "_negz", "_posz" }}; @@ -1098,10 +1178,16 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) // create all histograms for( int i =0; i < 2; ++i ) { - delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + // delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + // delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + // delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + // delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + + + delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), 205, phiBins, 68, r_bins); } } From 2b48d22462ee7a674d469dad58504f420a4d8349 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 24 Mar 2023 09:53:30 -0400 Subject: [PATCH 033/468] test change --- simulation/g4simulation/g4tracking/EmbRecoMatchv1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tracking/EmbRecoMatchv1.h b/simulation/g4simulation/g4tracking/EmbRecoMatchv1.h index bf20563619..6b0548c5da 100644 --- a/simulation/g4simulation/g4tracking/EmbRecoMatchv1.h +++ b/simulation/g4simulation/g4tracking/EmbRecoMatchv1.h @@ -7,7 +7,7 @@ #include #include #include - + /* class VtxPoint; */ class EmbRecoMatchv1 : public EmbRecoMatch { From 795802fa050a5a3a461706aa3bd04b8b276fcce2 Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 24 Mar 2023 11:13:51 -0400 Subject: [PATCH 034/468] Revert "add proper dynamic cast to use cluster v5" This reverts commit 0d4fe73e02e8120e7c6dcd4f4b1c2dedf251f9da. --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 6 ++---- offline/packages/trackreco/PHActsTrkFitter.cc | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index b77d6c102d..f99f154bb5 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -572,9 +571,8 @@ SpacePointPtr PHActsSiliconSeeding::makeSpacePoint( localCov(0,0) = para_errors.first* Acts::UnitConstants::cm2; localCov(1,1) = para_errors.second* Acts::UnitConstants::cm2; }else if(m_cluster_version==5){ - TrkrClusterv5 *clusterv5 = dynamic_cast (clus); - localCov(0,0) = pow(clusterv5->getRPhiError(),2) * Acts::UnitConstants::cm2; - localCov(1,1) = pow(clusterv5->getZError(),2) * Acts::UnitConstants::cm2; + localCov(0,0) = pow(clus->getRPhiError(),2) * Acts::UnitConstants::cm2; + localCov(1,1) = pow(clus->getZError(),2) * Acts::UnitConstants::cm2; } float x = globalPos.x(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 0d3e88b29e..2f514bcace 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -10,7 +10,6 @@ /// Tracking includes #include #include -#include #include #include #include @@ -705,11 +704,10 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; }else if(m_cluster_version==5){ - TrkrClusterv5 *clusterv5 = dynamic_cast (cluster); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(clusterv5->getRPhiError(),2) * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(cluster->getRPhiError(),2) * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(clusterv5->getZError(),2) * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(cluster->getZError(),2) * Acts::UnitConstants::cm2; } ActsSourceLink::Index index = measurements.size(); From 4a7b002901f2e86a4ddba7dc7f9b60cc9502652e Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 27 Mar 2023 11:01:41 -0400 Subject: [PATCH 035/468] Adding tool which generates Digital Current Ion Back Flow maps --- .../tpc/fillDigitalCurrentMaps/Makefile.am | 49 ++ .../tpc/fillDigitalCurrentMaps/README.md | 80 +++ .../tpc/fillDigitalCurrentMaps/autogen.sh | 8 + .../tpc/fillDigitalCurrentMaps/configure.ac | 16 + .../macros/Fun4All_FillDCMap.C | 63 ++ .../macros/run_files_AA.sh | 26 + .../readDigitalCurrents.cc | 564 ++++++++++++++++++ .../readDigitalCurrents.h | 116 ++++ .../scripts/generate_files_AA.py | 93 +++ .../fillSpaceChargeMaps.cc | 10 +- .../fillSpaceChargeMaps/fillSpaceChargeMaps.h | 8 +- .../macros/run_files_300evts_AA_MDC2.sh | 2 +- 12 files changed, 1025 insertions(+), 10 deletions(-) create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/Makefile.am create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/README.md create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/autogen.sh create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/configure.ac create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py diff --git a/calibrations/tpc/fillDigitalCurrentMaps/Makefile.am b/calibrations/tpc/fillDigitalCurrentMaps/Makefile.am new file mode 100644 index 0000000000..f725870c48 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/Makefile.am @@ -0,0 +1,49 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + readDigitalCurrents.h + +lib_LTLIBRARIES = \ + libreadDigitalCurrents.la + +libreadDigitalCurrents_la_SOURCES = \ + readDigitalCurrents.cc + +libreadDigitalCurrents_la_LIBADD = \ + -lphool \ + -lfun4all \ + -lphg4hit \ + -ltrackbase_historic_io \ + -ltrack_io \ + -ltpc_io \ + -lg4detectors \ + -lg4testbench \ + -lSubsysReco + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libreadDigitalCurrents.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/README.md b/calibrations/tpc/fillDigitalCurrentMaps/README.md new file mode 100644 index 0000000000..51f4426d0f --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/README.md @@ -0,0 +1,80 @@ +# SetUp +Start here for setting up environment: [Example_of_using_DST_nodes (Wiki)](https://wiki.bnl.gov/sPHENIX/index.php/Example_of_using_DST_nodes#Building%20a%20package) +- Setup local compilation for bash shel: + +``` +source /opt/sphenix/core/bin/sphenix_setup.sh -n +export MYINSTALL=/sphenix/user/shulga/tpc2019_install +source /opt/sphenix/core/bin/setup_local.sh $MYINSTALL +``` +**Do not forget to change the line:** ```export MYINSTALL=/sphenix/user/shulga/tpc2019_install``` + + + +- Compilation of the package: +``` +mkdir build +cd build +../autogen.sh --prefix=$MYINSTALL +make -j 4 +make install +``` +- reading first file: + + + + +# Workflow: +- DST files with TrkrHitSet containing ADCs from Hijing events used for the analysis: + - DST_TRKR_HIT_sHijing_0_20fm-0000000006--* + +- To get list of the files: +``` +CreateFileList.pl --run 6 --type 4 --nopileup DST_TRKR_HIT G4Hits +``` + +- File with bunchcrossing id and time (ns) assuming 106ns between bunches and 50kHz collision rate: __timestamps_50kHz.txt__. The file is used to mimic the bunchcrossing; + +- Running over containers in the files is performed with Fun4All environment. Main code is Fun4All_FillDCMap.C, it is run with run_files_AA.sh, which takes as an input the first and last file number: +``` +#This will run first 5 files with G4Hits (100 events per file in the MDC2) and create files +#with histograms: +source macros/run_files_AA.sh 1 2 1508071.0 +``` + +- As soon as files are available the histograms are inside; +- To create bunch of bash files and condor job files to start condor jobs scripts are available: +``` +#Creating folders to store all the files: + +mkdir Out +mkdir Files +mkdir condor_macros + +#Creating 1000s job files to run over G4Hits: +scripts/generate_files_AA.py +``` +**Do not forget to change the path to your repositories:** + +```export MYINSTALL=/sphenix/user/shulga/tpc2019_install``` + +```/sphenix/user/shulga/Work/...``` + +- Scripts above will also generate bash files to submit all jobs, *_all bash scripts created above should be provided executable rights before that_*: +``` +../run_all_jobs* +``` + +# Adding histograms from all files: +The files contain histograms for 100 events each. Full map is ~10000 events. Thus, maps have to be integrated. +To make files smaller the Sumw2 arrays/matrices for histograms should not be stored. +The tool to provide this functionality: +``` +add_histos.py +``` diff --git a/calibrations/tpc/fillDigitalCurrentMaps/autogen.sh b/calibrations/tpc/fillDigitalCurrentMaps/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/tpc/fillDigitalCurrentMaps/configure.ac b/calibrations/tpc/fillDigitalCurrentMaps/configure.ac new file mode 100644 index 0000000000..130d2b1b11 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(readdigitalcurrents,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT \ No newline at end of file diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C new file mode 100644 index 0000000000..6b613bcd18 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include + +#include + +#include +//#include +#include + +#include + + +R__LOAD_LIBRARY(libfun4all.so) +R__LOAD_LIBRARY(libreadDigitalCurrents.so) +R__LOAD_LIBRARY(libg4dst.so) + +void Fun4All_FillDCMap( const int nEvents = 1000, const int eventsInFileStart = 0, const int eventsBeamCrossing = 1508071, const string &fname = "/sphenix/user/shulga/Work/IBF/macros/detectors/sPHENIX/Files/DST_G4Hits_sHijing_0-12fm_005000_006000.root", const string &foutputname = "./Files/hists_G4Hits_sHijing_0-12fm_000000_001000.root" )//DST_G4sPHENIX_1000evt.root")//G4sPHENIX.root" ) +{ + // /sphenix/user/frawley/new_macros_april27/macros/detectors/sPHENIX/Reconstructed_DST_Hijing_50kHz_00000.root + + /////////////////////////////////////////// + // Make the Server + ////////////////////////////////////////// + + Fun4AllServer *se = Fun4AllServer::instance(); + string cd_name = "readDigitalCurrents"+std::to_string(eventsInFileStart); + //cout<registerSubsystem(dist_calc); + dist_calc->SetEvtStart(eventsInFileStart); + dist_calc->SetBeamXing(eventsBeamCrossing); // Set beam crosssing bias + dist_calc->SetCollSyst(0); //setting pp with = 1 + dist_calc->SetIBF(0.004); + dist_calc->SetCCGC(1);//to use PHG4CylinderCellGeom + + gSystem->Load("libFROG"); + FROG *fr = new FROG(); + string inputFileName = fr->location(fname); + cout << "Next file:" << inputFileName << endl; + // this (DST) input manager just drives the event loop + Fun4AllInputManager *in = new Fun4AllDstInputManager("DSTin"); + in->fileopen(inputFileName);//fname); + se->registerInputManager(in); + // events = 0 => run till end of input file + if (nEvents <= 0) + { + return; + } + cout << endl << "Running over " << nEvents << " Events" << endl; + se->run(nEvents); + //} + cout << endl << "Calling End in Fun4All_readDigitalCurrents.C" << endl; + se->End(); + + cout << endl << "All done, calling delete Fun4AllServer" << endl; + delete se; + + cout << endl << "gSystem->Exit(0)" << endl; + gSystem->Exit(0); +} \ No newline at end of file diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh new file mode 100755 index 0000000000..930fc3fc8b --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh @@ -0,0 +1,26 @@ +#!/usr/bin/bash +start=${1?Error: no start file \# given} +stop=${2?Error: no stop file \# given} +bX=${3?Error: no beamX \# given} +source /opt/sphenix/core/bin/sphenix_setup.sh -n new +export MYINSTALL=/sphenix/user/shulga/tpc2019_install +source /opt/sphenix/core/bin/setup_local.sh $MYINSTALL + +for (( f=$start; f<$stop; f++ )); +do + #let Xstart=f*1000 Xend=(f+1)*1000; + #A=$( printf '%06d' $Xstart ) + #B=$( printf '%06d' $Xend ) + let Xstart=f*100 Xend=(f+1)*100; + A=$( printf '%05d' $f ) + B=$( printf '%06d' $Xend ) + #fname="/sphenix/user/shulga/Work/IBF/macros/detectors/sPHENIX/Files/DST_NoW_G4Hits_sHijing_0-12fm_"$A"_"$B".root" ; + #fname="DST_TRKR_HIT_sHijing_0_20fm_50kHz_bkg_0_20fm-0000000062-"$A".root" ; + fname="DST_TRKR_HIT_sHijing_0_20fm-0000000006-"$A".root" ; + foutputname="./Files/hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A"_"$B".root" ; + echo $fname ; + echo $foutputname ; + root -l -b -q ./macros/Fun4All_FillDCMap.C\(10,$Xstart,$bX,\"$fname\",\"$foutputname\"\) +done + +echo all done diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc new file mode 100644 index 0000000000..4eb08318e4 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc @@ -0,0 +1,564 @@ + +#include "readDigitalCurrents.h" + +#include +#include +#include // for SubsysReco + +//#include "SvtxEvaluator.h" +#include "trackbase/TpcDefs.h" +#include "trackbase/ActsGeometry.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +double pi = 2 * acos(0.0); + +using namespace std; + +bool IsOverFrame(double r, double phi); + +bool IsOverFrame(double r, double phi){ + //these parameters are taken from Feb 12 drawings of frames. + double tpc_frame_side_gap=0.8;//mm //space between radial line and start of frame + double tpc_frame_side_width=2.6;//mm //thickness of frame + double tpc_margin=0.0;//mm // extra gap between edge of frame and start of GEM holes + + double tpc_frame_r3_outer=758.4;//mm inner edge of larger-r frame of r3 + double tpc_frame_r3_inner=583.5;//mm outer edge of smaller-r frame of r3 + + double tpc_frame_r2_outer=574.9;//mm inner edge of larger-r frame of r2 + double tpc_frame_r2_inner=411.4;//mm outer edge of smaller-r frame of r2 + + double tpc_frame_r1_outer=402.6;//mm inner edge of larger-r frame of r1 + double tpc_frame_r1_inner=221.0;//mm outer edge of smaller-r frame of r1 + + //double tpc_sec0_phi=0.0;//get_double_param("tpc_sec0_phi"); + + //if the coordinate is in the radial spaces of the frames, return true: + if (rtpc_frame_r1_outer-tpc_margin && rtpc_frame_r2_outer-tpc_margin && rtpc_frame_r3_outer-tpc_margin) + return true; + + //if the coordinate is within gap+width of a sector boundary, return true: + //note that this is not a line of constant radius, but a linear distance from a radius. + + //find the two spokes we're between: + + float sectorangle=(pi/6); + float nsectors=phi/sectorangle; + int nsec=floor(nsectors); + float reduced_phi=phi-nsec*sectorangle; //between zero and sixty degrees. + float dist_to_previous=r*sin(reduced_phi); + float dist_to_next=r*sin(sectorangle-reduced_phi); + if (dist_to_previousregisterHisto(_h_R ); + hm->registerHisto(_h_hits ); + hm->registerHisto(_h_DC_SC ); + hm->registerHisto(_h_DC_SC_XY ); + hm->registerHisto(_h_hit_XY ); + hm->registerHisto(_h_DC_E ); + hm->registerHisto(_h_SC_ibf ); + //outfile = new TFile(_filename.c_str(), "RECREATE"); + _event_timestamp = 0; + + myCSVFile.open ("./Files/example_1ms_120evts_AA.csv"); + myCSVFile << "Event," + << "T," + << "Pad," + << "Radius," + << "ADC" + <<"\n"; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::InitRun(PHCompositeNode *topNode) +{ + std::cout << "readDigitalCurrents::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << std::endl; + std::string line; + //AA collisions timestamps + //std::string txt_file = "/sphenix/user/shulga/Work/IBF/DistortionMap/timestamps_50kHz.txt"; + std::string txt_file = "/sphenix/user/shulga/Work/TpcPadPlane_phi_coresoftware/coresoftware/calibrations/tpc/fillSpaceChargeMaps/data/timestamps_50kHz_1M.txt"; + int start_line = 3; + if(_collSyst==1){ + //pp collisions timestamps + txt_file = "/phenix/u/hpereira/sphenix/work/g4simulations/timestamps_3MHz.txt"; + //txt_file = "/sphenix/user/shulga/Work/IBF/DistortionMap/timestamps_50kHz.txt"; + start_line = 2; + } + ifstream InputFile (txt_file); + if (InputFile.is_open()){ + int n_line=0; + while ( getline (InputFile,line) ) + { + n_line++; + if(n_line>start_line){ + std::istringstream is( line ); + double n[2] = {0,0}; + int i = 0; + while( is >> n[i] ) { + i++; + } + _timestamps[n[0]]=n[1]; + if(n_line<10){ + cout<IsOpen() ) printf("Gain/IBF Maps File opened successfully\n"); + //_h_modules_anode = (TH2F*)MapsFile ->Get("h_modules_anode") ->Clone("_h_modules_anode"); + _h_modules_measuredibf = (TH2F*)MapsFile ->Get("h_modules_measuredibf")->Clone("_h_modules_measuredibf"); + //} + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::process_event(PHCompositeNode *topNode) +{ + double bX = _beamxing; + //float bX = 1508071; + //double z_bias_avg = 0; + //if (_fAvg==1){ + // z_bias_avg=1.05*(float) rand()/RAND_MAX; + //} + int bemxingsInFile = _keys.size(); + if (_evtstart>= bemxingsInFile) _evtstart=_evtstart-bemxingsInFile; + int key = _keys.at(_evtstart); + _event_timestamp = (float)_timestamps[key]*ns;//units in seconds + _event_bunchXing = key; + if(_evtstart%100==0) cout<<"_evtstart = "<<_evtstart<::const_iterator iter; + // //nodename << "G4HIT_TPC"; + nodename << "TRKR_HITSET"; + + // // SvtxEvaluator + // SvtxEvaluator *hits = findNode::getClass(topNode, nodename.str().c_str()); + // //int n_hits = 0; + // if (hits){ + // PHG4HitContainer::ConstRange hit_range = hits->getHits(); + // } + //=================================== + // get node containing the digitized hits + TrkrHitSetContainer* _hitmap = findNode::getClass(topNode, nodename.str().c_str()); + if (!_hitmap) + { + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + ostringstream geo_nodename; + geo_nodename << "CYLINDERCELLGEOM_SVTX"; + + PHG4TpcCylinderGeomContainer* _geom_container_ccgc = nullptr; + PHG4CylinderCellGeomContainer* _geom_container_cgc = nullptr; + if(_f_ccgc==1){ + _geom_container_ccgc = findNode::getClass(topNode, geo_nodename.str().c_str()); + if (!_geom_container_ccgc) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + }else{ + _geom_container_cgc = findNode::getClass(topNode, geo_nodename.str().c_str()); + + if (!_geom_container_cgc) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + } + + + // loop over all the hits + // hits are stored in hitsets, so have to get the hitset first + int n_hits = 0; + //float _event_bunchXing = 1508071; + TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first;iter != all_hitsets.second; ++iter){ + //checking that the object is inside TPC + if(TrkrDefs::getTrkrId(iter->first) == TrkrDefs::tpcId){ + TrkrDefs::hitsetkey hitsetkey = iter->first; + const unsigned int zside = TpcDefs::getSide(hitsetkey); + TrkrHitSet::ConstRange range = iter->second->getHits(); + unsigned int layer = TrkrDefs::getLayer(iter->first); + //if(layer>6){ + PHG4TpcCylinderGeom *layergeom_ccgc = nullptr; + PHG4CylinderCellGeom *layergeom_cgc = nullptr; + double radius = 0; + if(_f_ccgc==1){ + layergeom_ccgc = _geom_container_ccgc->GetLayerCellGeom(layer); + radius = layergeom_ccgc->get_radius()*cm; + }else{ + layergeom_cgc = _geom_container_cgc->GetLayerCellGeom(layer); + radius = layergeom_cgc->get_radius()*cm; + } + //PHG4TpcCylinderGeom *layergeom = _geom_container->GetLayerCellGeom(layer); + //double radius = layergeom->get_radius()*cm; // returns center of the layer + int min_phiBin=1e5; + int max_phiBin=-1; + for(TrkrHitSet::ConstIterator hit_iter = range.first; hit_iter != range.second; ++hit_iter){ + int f_fill_ibf=0; + + + unsigned short phibin = TpcDefs::getPad(hit_iter->first); + unsigned short zbin = TpcDefs::getTBin(hit_iter->first); + double _drift_velocity = 8.0e-3;//ActsGeometry::get_drift_velocity(); + double phi_center = 0; + if(_f_ccgc==1){ + phi_center = layergeom_ccgc->get_phicenter(phibin); + }else{ + phi_center = layergeom_cgc->get_phicenter(phibin); + } + if (phi_center<0) phi_center+=2*pi; + if(phi_centerpi/2-pi/12){ + if(min_phiBin>phibin)min_phiBin=phibin; + if(max_phiBinget_zcenter(zbin)*cm; + if(_f_ccgc==1){ + z = layergeom_ccgc->get_zcenter(zbin)*_drift_velocity*cm;//*cm/ns; + if(zside==0){ + z = -z; + } + }else{ + z = layergeom_cgc->get_zcenter(zbin)*cm; + } + TrkrHit *hit = hit_iter->second; + unsigned short adc = hit->getAdc()-adc_pedestal; + float E = hit->getEnergy(); + //double z = 0; + //double z_prim = -1*1e10; + double z_ibf = -1*1e10; + + int RBin=_h_R->GetXaxis()->FindBin(radius); + if((RBin>33 && RBin<50) && z>0){ + int nRBins = layergeom_ccgc->get_phibins(); + if(phibinget_zcenter(zbin) << "," + << phibin<<"," + << RBin-34<< "," + << adc <<"\n"; + _h_hit_XY->Fill( x, y); + } + + } + //if(!IsOverFrame(radius/mm,phi_center)){ + + + if(z>=0 && z<1.055*m){ + if(adc>=0)n_hits++; + if(adc>=0)_h_DC_E->Fill(adc,E); + + //z_prim = z-(bX-_event_bunchXing)*106*vIon*ns; + z_ibf = 1.055*m-(bX-_event_bunchXing)*106*vIon*ns; + //if(n_hits%100==0)cout<<"z_ibf = "<0 && z_ibf<1.055*m){ + f_fill_ibf=1; + } + } + if(z<0 && z>-1.055*m){ + if(adc>=0)n_hits++; + if(adc>=0)_h_DC_E->Fill(adc,E); + + //z_prim = z+(bX-_event_bunchXing)*106*vIon*ns; + z_ibf = -1.055*m+(bX-_event_bunchXing)*106*vIon*ns; + if( z_ibf<0 && z_ibf>-1.055*m){ + f_fill_ibf=1; + } + } + + //Reading IBF and Gain weights according to X-Y position + float w_ibf = 1.; + //float w_gain = 1.; + //if(_fUseIBFMap){ + int bin_x = _h_modules_measuredibf ->GetXaxis()->FindBin(x/mm); + int bin_y = _h_modules_measuredibf ->GetYaxis()->FindBin(y/mm); + w_ibf = _h_modules_measuredibf->GetBinContent(bin_x,bin_y); + //w_gain = _h_modules_anode->GetBinContent(bin_x,bin_y); + w_ibf = 1.; + //} + float w_adc = adc*w_ibf; + _h_DC_SC->Fill(phi_center,radius,z,w_adc); + _h_DC_SC_XY->Fill(x,y,w_adc); + if(f_fill_ibf==1){ + _h_SC_ibf ->Fill(phi_center,radius,z_ibf,w_adc); + _h_R->Fill(radius); + } + //} + //if(n_hits%100==0) std::cout<Fill(n_hits); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::ResetEvent(PHCompositeNode *topNode) +{ + //std::cout << "readDigitalCurrents::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::EndRun(const int runnumber) +{ + std::cout << "readDigitalCurrents::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::End(PHCompositeNode *topNode) +{ + std::cout << "readDigitalCurrents::End(PHCompositeNode *topNode) This is the End..." << std::endl; + _h_R ->Sumw2( false ); + _h_hits ->Sumw2( false ); + _h_DC_E ->Sumw2( false ); + _h_DC_SC ->Sumw2( false ); + _h_hit_XY ->Sumw2( false ); + _h_DC_SC_XY ->Sumw2( false ); + _h_SC_ibf ->Sumw2( false ); + hm->dumpHistos(_filename, "RECREATE"); + myCSVFile.close(); + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int readDigitalCurrents::Reset(PHCompositeNode *topNode) +{ + std::cout << "readDigitalCurrents::Reset(PHCompositeNode *topNode) being Reset" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +void readDigitalCurrents::Print(const std::string &what) const +{ + std::cout << "readDigitalCurrents::Print(const std::string &what) const Printing info for " << what << std::endl; +} + +void readDigitalCurrents::SetEvtStart(int newEvtStart){ + _evtstart = newEvtStart; + cout<<"Start event is set to: "< + +#include +#include +#include +#include + +#pragma once +//#include + +class Fun4AllHistoManager; +class PHCompositeNode; + +//class PHG4CylinderCellGeom; + +//class TFile; +class TH1; +class TH2; +class TH3; + + +class readDigitalCurrents : public SubsysReco +{ + public: + + readDigitalCurrents(const std::string &name = "readDigitalCurrents", const std::string &filename = "DC_Hist_OnPlane_WIBF.root"); + + virtual ~readDigitalCurrents(); + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. A place + to book histograms which have to know the run number. + */ + int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode *topNode) override; + + /// Called at the end of each run. + int EndRun(const int runnumber) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + /// Reset + int Reset(PHCompositeNode * /*topNode*/) override; + + void Print(const std::string &what = "ALL") const override; + + void SetBeamXing(int newBeamXing); + void SetEvtStart(int newEvtStart); + void SetCollSyst(int coll_syst=0); + void SetIBF(float ampIBFfrac=0.004); + void SetCCGC(float f_ccgc=0); + + //double pi = 3.14159265358979323846;//2 * acos(0.0); + + protected: + Fun4AllHistoManager *hm; + std::string _filename; + //TFile *outfile; + std::map _timestamps; + std::vector _keys; + float _ampIBFfrac; + int _collSyst; + std::ofstream myCSVFile; + + private: + int _beamxing = 0; + int _evtstart = 0; + + int _f_ccgc = 0; + + TH2* _h_modules_measuredibf; + + TH1* _h_R; + TH1* _h_hits; + TH3* _h_DC_SC; + TH2* _h_DC_SC_XY; + TH2* _h_hit_XY; + TH2* _h_DC_E; + TH3* _h_SC_ibf; + float _event_timestamp; + float _event_bunchXing; + + //double pi = 2 * acos(0.0); + double adc_pedestal=0.;//74.4; + double cm=1e1,m=1e3, mm=1; //changed to make 'm' 1.0, for convenience. + float ns=1e-9,us=1e-6,ms=1e-3,s=1; + float V=1; + //float ionMobility=3.37*cm*cm/V/s; + float ionMobility=1.65*cm*cm/V/s; + float vIon=ionMobility*400*V/cm; + + float f=0.5;//for now, just pick the middle of the hit. Do better later. +}; + +#endif // READDIGITALCURRENTS_H diff --git a/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py new file mode 100755 index 0000000000..85f8c7782c --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# coding=utf-8 + +introduction = [ + "# All local jobs are part of the vanilla universe.", + "Universe = vanilla", + "", + "# The requirement line specifies which machines we want to", + "# run this job on. Any arbitrary classad expression can", + "# be used.", + "#Requirements = (CPU_Speed >= 1)", + "", + "# Rank is an expression that states how to rank machines which ", + "# have already met the requirements expression. Essentially, ", + "# rank expresses preference. A higher numeric value equals better ", + "# rank. Condor will give the job the machine with the highest rank.", + "# Rank = CPU_Speed", + "", + "# Jobs by default get 1.4Gb of RAM allocated, ask for more if needed", + "# but if a job needs more than 2Gb it will not be able to run on the", + "# older nodes", + "request_memory = 7.1GB", + "", + "# If you need multiple cores you can ask for them, but the scheduling", + "# may take longer the \"larger\" a job you ask for", + "request_cpus = 1", + "", + "# This flag is used to order only one's own submitted jobs ", + "# The jobs with the highest numbers get considered for ", + "# scheduling first.", + "#Priority = 4", + "", + "# Copy all of the user's current shell environment variables ", + "# at the time of job submission.", + "#GetEnv = True", + "", + "# Used to give jobs a directory with respect to file input ", + "# and output.", + "Initialdir = /sphenix/user/shulga/Work/IBF/readDigitalCurrents/", + "", + "# Input file given to the job.", + "#Input = /dev/null", + "", + "", + "# This should be the last command and tells condor to queue the", + "# job. If a number is placed after the command (i.e. Queue 15)", + "# then the job will be submitted N times. Use the $(Process)", + "# macro to make your input/output and log files unique.", + "Queue" +] + +ff= open("./run_all_AA_jobs.sh","w+") +ff.write("#!/usr/bin/bash"+"\n"), +#evt_start = [0,8,16,23,31,39,47,55,63,71,79,87] +#evt_end = [9,17,24,32,40,48,56,64,72,80,88,96] +evt_start = [0,80,160,230,310,390,470,550,630,710,790,870] +evt_end = [90,170,240,320,400,480,560,640,720,800,880,960] +evt_bX = [1508071.0, 3016509.0, 4524020.0, 6032112.0, 7540028.0, 9048092.0, 10556072.0, 12064371.0, 13572143.0, 15080178.0, 16588072.0, 18096105.0] +for j, (start,end) in enumerate(zip(evt_start,evt_end)): + for i in range(start,end): + filename = "./run_macros/run_files_AA_{}_{}.sh".format(j,i) + f= open(filename,"w+") + f.write("#!/usr/bin/bash"+"\n") + f.write("source macros/run_files_AA.sh {} {} {}".format(i,i+1,evt_bX[j])+"\n") + f.close + filename_job = "./run_macros/condor_run_files_AA_{}_{}.job".format(j,i) + ff.write("condor_submit {}".format(filename_job)+"\n") + f_job= open(filename_job,"w+") + n_line = 0 + for lines in introduction: + f_job.write(lines+"\n") + if n_line==3: + f_job.write("# The executable we want to run."+"\n") + f_job.write("Executable = run_macros/run_files_AA_{}_{}.sh".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write(""+"\n") + f_job.write("# The argument to pass to the executable."+"\n") + f_job.write("Arguments = \"run DST HISTO job AA {} {}\"".format(j,i)+"\n") + if n_line==38: + f_job.write("# The job's stdout is sent to this file."+"\n") + f_job.write("Output = /sphenix/user/shulga/Work/IBF/readDigitalCurrents/Out/myjob_AA_{}_{}.out".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write("# The job's stderr is sent to this file."+"\n") + f_job.write("Error = /sphenix/user/shulga/Work/IBF/readDigitalCurrents/Out/myjob_AA_{}_{}.err".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write("# The condor log file for this job, useful when debugging."+"\n") + f_job.write("Log = /sphenix/user/shulga/Work/IBF/readDigitalCurrents/Out/condor_AA_{}_{}.log".format(j,i)+"\n") + f_job.write(""+"\n") + + n_line+=1 + f_job.close +ff.close diff --git a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc index 09aee4578d..bcae25440b 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc +++ b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.cc @@ -12,8 +12,8 @@ #include #include -#include -#include +//#include +//#include #include // for TAxis #include @@ -140,8 +140,8 @@ int fillSpaceChargeMaps::Init(PHCompositeNode * /*topNode*/) _rawHits->Branch("event_timestamp", &_event_timestamp); _rawHits->Branch("event_bunchXing", &_event_bunchXing); } - padplane = new PHG4TpcPadPlaneReadout; - seggeo = new PHG4TpcCylinderGeomContainer(); + //padplane = new PHG4TpcPadPlaneReadout; + //seggeo = new PHG4TpcCylinderGeomContainer(); return 0; } @@ -200,7 +200,7 @@ int fillSpaceChargeMaps::InitRun(PHCompositeNode * /*topNode*/) _mbRate = _freqKhz * kHz; _xingRate = 9.383 * MHz; _mean = mbRate / xingRate; - padplane->CreateReadoutGeometry( PHCompositeNode *, seggeo); + //padplane->CreateReadoutGeometry( PHCompositeNode *, seggeo); return 0; } diff --git a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h index 4783bf9018..576034c74a 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h +++ b/calibrations/tpc/fillSpaceChargeMaps/fillSpaceChargeMaps.h @@ -5,8 +5,8 @@ #include -#include -#include +//#include +//#include #include #include @@ -110,8 +110,8 @@ class fillSpaceChargeMaps : public SubsysReco TH3 *_h_SC_prim[nFrames] = {nullptr}; TH3 *_h_SC_ibf[nFrames] = {nullptr}; - PHG4TpcPadPlaneReadout *padplane = nullptr; - PHG4TpcCylinderGeomContainer *seggeo = nullptr; + //PHG4TpcPadPlaneReadout *padplane = nullptr; + //PHG4TpcCylinderGeomContainer *seggeo = nullptr; float f = 0.5; //for now, just pick the middle of the hit. Do better later. float ns = 1e-9, s = 1.0; // us=1e-6,ms=1e-3, diff --git a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh index 39eb54951b..b0ccd770ae 100755 --- a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh +++ b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh @@ -12,7 +12,7 @@ do A=$( printf '%05d' $Xstart ) #B=$( printf '%06d' $Xend ) #fname="G4Hits_sHijing_0_20fm-0000000002-"$A".root" ; - fname="G4Hits_sHijing_0_20fm-0000000062-"$A".root" ; + fname="G4Hits_sHijing_0_20fm-0000000006-"$A".root" ; foutputname="./Files/mdc2_ADCBins_UseFieldMaps_hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A".root" ; #foutputname="./Files/mdc2_ADCBins_NoFieldMaps_hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A".root" ; echo $fname ; From 9f4ef9c2182aebcb6bae2489c80ccacd00782ed5 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 27 Mar 2023 12:44:22 -0400 Subject: [PATCH 036/468] Add flag for setting CVS file --- .../readDigitalCurrents.cc | 50 +++++++++---------- .../readDigitalCurrents.h | 3 ++ 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc index 4eb08318e4..f1b3a107bc 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc @@ -210,23 +210,10 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) _h_R = new TH1F("_h_R" ,"_h_R;R, [m]" ,r_bins_N ,r_bins); _h_hits = new TH1F("_h_hits" ,"_h_hits;N, [hit]" ,1e5,0-0.5,1e5-0.5); - //_h_SC_ibf = new TH3F("_h_SC_ibf" ,"_h_SC_ibf;#phi, [rad];R, [m];Z, [m]" ,nphi,0,6.28319,nr,rmin,rmax,2*nz,-z_rdo,z_rdo); - //_h_DC_SC = new TH3F("_h_DC_SC" ,"_h_DC_SC;#phi, [rad];R, [m];Z, [m]" ,nphi,0,6.28319,nr,rmin,rmax,2*nz,-z_rdo,z_rdo); _h_hit_XY = new TH2F("_h_hit_XY" ,"_h_hit_XY;X, [m];Y, [m]" ,4*nr,-1*rmax,rmax,4*nr,-1*rmax,rmax); - //_h_hit_XY = new TH2F("_h_hit_XY" ,"_h_hit_XY;X, [m];Y, [m]" ,2000,-1000,1000,2000,-1000,1000); - //_h_DC_E = new TH2F("_h_DC_E" ,"_h_DC_E;ADC;E" ,200,-100,2e3-100,500,-100,5e3-100); - //double phi_bins[nphi+1]; - //for (int p=0;p<=nphi;p++){ - // phi_bins[p]=6.28319/nphi*p; - //} - //double z_bins[2*nz+1]; - //for (int z=0;z<=2*nz;z++){ - // z_bins[z]=-z_rdo+z_rdo/nz*z; - //} _h_SC_ibf = new TH3F("_h_SC_ibf" ,"_h_SC_ibf;#phi, [rad];R, [mm];Z, [mm]" ,nphi,phi_bins,r_bins_N ,r_bins,2*nz,z_bins); _h_DC_SC = new TH3F("_h_DC_SC" ,"_h_DC_SC;#phi, [rad];R, [mm];Z, [mm]" ,nphi,phi_bins,r_bins_N ,r_bins,2*nz,z_bins); - //_h_DC_SC_XY = new TH3F("_h_DC_SC_XY" ,"_h_DC_SC_XY;X, [m];Y, [m];Z, [m]" ,4*nr,-1*rmax,rmax,4*nr,-1*rmax,rmax,2*nz,-z_rdo,z_rdo); _h_DC_SC_XY = new TH2F("_h_DC_SC_XY" ,"_h_DC_SC_XY;X, [mm];Y, [mm];ADC;" ,4*nr,-1*rmax,rmax,4*nr,-1*rmax,rmax); _h_DC_E = new TH2F("_h_DC_E" ,"_h_DC_E;ADC;E" ,200,-100,2e3-100,500,-100,5e3-100); hm->registerHisto(_h_R ); @@ -236,16 +223,18 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) hm->registerHisto(_h_hit_XY ); hm->registerHisto(_h_DC_E ); hm->registerHisto(_h_SC_ibf ); - //outfile = new TFile(_filename.c_str(), "RECREATE"); _event_timestamp = 0; - myCSVFile.open ("./Files/example_1ms_120evts_AA.csv"); - myCSVFile << "Event," - << "T," - << "Pad," - << "Radius," - << "ADC" - <<"\n"; + if(_fillCSVFile){ + myCSVFile.open ("./Files/example_1ms_120evts_AA.csv"); + myCSVFile << "Event," + << "T," + << "Pad," + << "Radius," + << "ADC" + <<"\n"; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -427,11 +416,13 @@ int readDigitalCurrents::process_event(PHCompositeNode *topNode) if((RBin>33 && RBin<50) && z>0){ int nRBins = layergeom_ccgc->get_phibins(); if(phibinget_zcenter(zbin) << "," - << phibin<<"," - << RBin-34<< "," - << adc <<"\n"; + if (_fillCSVFile){ + myCSVFile << _evtstart<<"," + << layergeom_ccgc->get_zcenter(zbin) << "," + << phibin<<"," + << RBin-34<< "," + << adc <<"\n"; + } _h_hit_XY->Fill( x, y); } @@ -517,7 +508,7 @@ int readDigitalCurrents::End(PHCompositeNode *topNode) _h_DC_SC_XY ->Sumw2( false ); _h_SC_ibf ->Sumw2( false ); hm->dumpHistos(_filename, "RECREATE"); - myCSVFile.close(); + if(_fillCSVFile)myCSVFile.close(); return Fun4AllReturnCodes::EVENT_OK; } @@ -539,6 +530,11 @@ void readDigitalCurrents::SetEvtStart(int newEvtStart){ cout<<"Start event is set to: "< Date: Mon, 27 Mar 2023 12:48:47 -0400 Subject: [PATCH 037/468] Add script for adding histos --- .../macros/add_histos.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos.py diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos.py b/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos.py new file mode 100755 index 0000000000..5d02f73dbe --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +from ROOT import TCanvas, TFile, TH1F,TH2F,TH3F, TF1, TGraph, gROOT +import os +import re + +gROOT.SetBatch(True) + +dirName = './Files/' +bXs = [1508071, 3016509, 4524020, 6032112, 7540028, 9048092, 10556072, 12064371, 13572143, 15080178, 16588072, 18096105] +h_names = ['_h_DC_E', + '_h_DC_SC', + '_h_DC_SC_XY', + '_h_R', + '_h_SC_ibf', + '_h_hits'] + +for bX in bXs: + print(bX) + name = 'hist_G4Hits_sHijing_0-12fm_bX{}'.format(bX) + outputName = './Files/Summary_ADC_NoW_hist_AA_event_0_bX{}.root'.format(bX) + files = [f for f in os.listdir(dirName) if re.match(name, f)] + n=0 + histos = [] + for file in files: + h=0 + f = TFile.Open(dirName+file) + for h_name in h_names: + newName=h_name+'_{}'.format(n) + if n==0: + newName=h_name + hist = f.Get(h_name).Clone() + hist.SetDirectory(0) + if n==0: + histos.append(hist) + if n>0: + histos[h].Add(hist) + h+=1 + n+=1 + + outfile = TFile(outputName, "RECREATE") + for hist in histos: + hist.Sumw2(False) + hist.Write() + outfile.Write() + outfile.Close() +#print(files) +# +# \ No newline at end of file From bcec28bb785e8831176d21f4391010b4ac33ee14 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 27 Mar 2023 13:57:57 -0400 Subject: [PATCH 038/468] Add gain map file --- .../Files/TPCGainMaps.root | Bin 0 -> 961352 bytes .../readDigitalCurrents.cc | 34 ++---------------- 2 files changed, 2 insertions(+), 32 deletions(-) create mode 100644 calibrations/tpc/fillDigitalCurrentMaps/Files/TPCGainMaps.root diff --git a/calibrations/tpc/fillDigitalCurrentMaps/Files/TPCGainMaps.root b/calibrations/tpc/fillDigitalCurrentMaps/Files/TPCGainMaps.root new file mode 100644 index 0000000000000000000000000000000000000000..178e6d1a322e87ae7c82526dd057548109fb49ef GIT binary patch literal 961352 zcma&O2{;sL*gsrHaVpCxN%m7tNeWrBP9>CWXfRSpl8|K2Hd9BDggTK@OcK*rD{Ho? zBun-+d)WqKpBZEJ|2^k@-|u^`_q*Qf``4vuEVt*m*WZ2r?wLS;|KLrVs7aePZMw2a zH2(~IY=QruhL6qgVb6c!xk>cV^-Y_kYBp^?^R@O=YtzofzZKduHgB(6hOho#{du&B zFUaxc`l#zB{eLB2;s4xLdo%Cro_kf*_zyv9_O>SG?%p@7-ERh|2J#Q~zkg-ZR=%u% z(=Q{^#QrA^TJALB5{BTitBk zubdMKhJ(48TW=EBv?-eZEx&KtB=!`3p0&x@>UTAPP4A*M-P*i3{5hcK#NJqUG2N;k z=gK!duobht?epq4huaswj0rzJGT1CkD*W?Kz_)*n9H_S#CmIKNj7iya+-xDM`CfP$ z!($iHsz=*B3gaqiK}QP|=8sO}DJYbj1q~Ig(u<^BWua=#7Ll|xG@@_cTLoWFj%~3k z$H|iHRW&Yg0nry>!ywZH`g{qPJX8)Q@5cb=)0h!1t$`e1E0@j8T0(J{%(D`#D%^PS zo{B{`R7Nnyr{E+DX^Sg-G4JG!%?q+e^mPq#ZH0<4d6Hzj1rcjJ$h9ZX+k$jM=p&q6 zRHjL4#ORZ1FFc2kl*1%kULKBEtoy5<6=$yoPi<^C_Ba(9%4ItoxB^7rIqwC@am=MY zq(tQS(YCs1e=k;tEnz_9$2m}~Dl|FL7VmpEJc%G|Cpy_j$e1*#|q%bK6_XB#5@J$5ri~ zZTHBorHbj4Y=hwGqh#ZaF7wi8w?_n@dZ^u~l7oH~nIm z1o=YTJpC<)z+IWg5B=cUM}l5-QkguKf9ULX&c%W*X4ZPYHEmxT{3=_cEi_bvvHy-m zo9OYjQPSJSJKEF59pjq4s4Pq#U*o+UE+1LfNpU{n!I-z}<%qt1CgB`HcV_8H4+B4h zXVW;6zNMJA_!Qz2vaAe~hwMkvKsnX>jcx~X3FUSi`xpE#r7~;nmToMtZ5Iz`DCBv8 zU~ACT7?WUp9DD~4AIE&KdC}k`88noU;3Be&0?G-U$6M6;XIA5`WAhmL=|0OLT!Qg= zM4v|vhi~TG!2y=2S7qF}HeGYPRL9{qV|Z@?D=l3vHJp5-Bx=9zX}Ny!uUz)}@G zYmca?C@s&4_(p-lNlW?4Jsuc86?v6$34g6OcBaKiQk5(R&Wn zsg7+#xk!zvMmxRGQ?BX`{qXh5D$SyCvEM6Cf|#q~qC6h=fP{)@d!gU^f?aJ>rh<$1 zo08#Z1-MS!qV`Y=O{-qx>UQWG2y)Ji`eWOIX7P8DNg-y4qdy;FA7Z4r4vBWN`0{$M zs7|EZz?jxaL`dzC%1xYJ^7zU@X3o&G@@VdTjOXRzJFXzj)TlfQH_Fui|Ht8hAzCS%xiRc7k1)Ne==MA;%nUxw2g z&>pds(<{Ntf&V}0s}O>tSSAF2wj!81&Pg3hfts@z|Z z+d3R{zQ8MS9#fKhnR8e`?EHJz)O{VSJ>S^gw?3N~sAGMGciHcy;FCNYB0RXgAtl42 zt+&(D$8N2a&ioon}nB>jYhD z79S4UO~w$GbPpp$Ia)VSara)dCX?Xd&+?tc7wvem{WUH^ z-Y@Y4(Y{*!FHug5*C?q8lYS%oC<#f4Eq+8vo5u(|XlC?$YC0Ck)tVX!*TecWtNzVU z@v{_5HAjRjSna)snb#K&{hiYrM0_d+%4bZTMSW%38RzfXqdZe+^}Q(Nkh}_|uFmfZ zJEzJmnd!L7Nxef!D{NqUH@%mX0F8yaEWdk3>@I&dc$JE3?C({6*R!dv(|H#E^zQu< za9q8x&{sHpo%C~^NS8R3zEcR=MHbT>qy^O`6iaei@L}5vC2LzsEwQ2}5pAr6;lWwB zt@YJX$#FNS<4cZ)Gf0zi2iaJR&qr--F;1_J#|nBDpVaq#CJR@!j;l<<%rjV~`#>O3 zRO{t_W-2nw@5`#&^H6o6MyzLM*b_spWe8E9n0NvqBKyyiWQ_EO+%`ih>U&Pxy-uXx z6N>(8oW5fUQ-af5R=uc5MRmA|w}8WQBzn)T_uzXhJvb^oI{lByxEY2~DjB@jfkBp} z_Iz62&JWKIx4zndFoI@T7t(LMBl00;-YNKw4&T`|mRj21K>}O(~5cYJH)MxiF(m!&Rtf)PY&L?Dm_F|B_uW>`)cJHKg zrzVA4%fG@^=_DTpE9+H790L13AIBH))hCf>_6nDqXwOvm1J6R03tq<)pMTE50XbZq?+n4t<38YJ=2Fx7ig=%foY2q58W8X0` z>*xI{CyEr(BLj8&#rincC8k!N2=?RlC*!oPOj(Ds-#kt9oL+r0B_) zc=3ZIr$8yLfWyMn^pv=%Bbo3GfsrZfO!mx_dN8iqos%eyU7%|1$wAcn5FJq14L$wSUpE4coLJA}ph2H^bMeDb~ zw!Qc6fFBnrOTujxcMO9c2T6xPR9xTtUX*igu@^0c>O|s7iGh~X!#$_2f1bsEj1f(P zSf)p>HAYZ-PK5pRg78ly>OH{tNL5$sF$snBy?iJBY>*F5oXcYgFbQ5|9cMvzPadCa z07IOeOER9t6XxW;GVbKIEApoo$42S>I>ID)uJk3r>H60n zgFH;gYlzt=tXgvf?TB0NUe39rGp63HZj9sfOf>Z{YSJ+UuG&X6gAl7jchm1fqN92{ zia{Dq9bhM7eB#e=1UbF^!99DaDD$s5ijbUE&tt%iO>tT#MEe8+%5A-;5lyULMLmyL zYTrcd8TruT^$LO_GoZp0A#%&$kWCcA^Gvh2Nhk7XhMXQ8Ew)bv%uq#RgJrZM*0mwR zI#}Bw!ZHpSDxNA(n4WA)zHC~o5#qKlAleKyqi<7u3Up`04%emj+?EW&W#eLZN2rT( zdb?joYy#cgxL$H-m1`-N;mZ4fyvWNcav$TpZlEd5KObC~oSb0B*c{~9-6S51UGBXa8xiFl0kWtz%8j8B)rvN@uxZ@%p&~*#Nhw_;q~AFpsxw6|-a3Zwf4a$TkOpo}o;wDi zdwZf9?ydc;|0JT!A-WqvqHBMY5|fZmm-GfLZj1KGcFU7H7U}Vootlhb;G8-@-j(0_ zpJG6NENN>+oO9)Te=u!Rh=Y8oA)e8$KM!QRw6Z&n~19 zFVf&Q@IYJp;orN8t(uy|iu0C-1M)FnL{+F`=Y4SYyD9k0&zYEKP{JvG z_BFHUg9Tz1kn4L}>~4TK(~NvRut>rZB{*7_A{(V=@iW82HrY7m*5#or+|YxRaPb37 zLbh2PSK9_!{Z_crCxZ3YUBveW}mu-_-~D}VxS#L3my zZqGYg?c_LG+OOtu6Yn+f%cH)09oEV`G(m_seb~Q=f}iP8OM^0=LvCnbr|LvfRP7*V zwIrTT0D&=ONVqv;CTeS|Ti#+cHI=VIQ^$sETyBk&0n*TMru1l)2;jU5U)(b2@T$2| zHZEQ4p0yc5B$DfLh)Fm~y`jR_Ve{>rXNZu#!eB|zq0M;I-wew##8s}X75HJ!9^9db zROJe>Q3z%N$3+lei+}#}s}L<`!yI4X(!(4MgLCiEjaC4G*Ur2@1gOO{jo!#6%7 zg)0x$+)4m}M$rYZj9N12Rj~;dQz0DOSga{ zdYp~oL!k?lD5n&_9Ge9mun*7VXqhJ+mQfiaUia4OtjY(LE^TRvdg>%or(7 zLi9TPvYS2=pePW^Cz}z^h-+OdqZ1MT_Uc&Z|}fr z8FN41mZyCID3eLtK)2#z(`%GU*`6ve^Bvz zJBt^kEDmKiunA;w9$^wnLT}Nn8y~>mhc!Y?jzNi;G8&Qvsn=|ysXYspkrDh%8F5$^ zGUYXmGN=RLBW)LE@$SPdG{Dhy-54l*&jd5!tP-x$fFuZ*8WAXe-zJ~)on7Hz-}pf= zyi59lY}{1^s~x70CPn-f|Gl@q%qq{pg7T=f@X4bwFj2p=XjW zML|~?9#|jP1rB9V7(|W-2cVrCZ%n{U*FPcg00$F@fBw$Viu7nh^7C4>`R+u36t66< z@18-njZ3iM2i+6mGQo>z?!{|o0i2Xzwb3ExA1+CGKs_F>hS0Rdg;tb60ZEZX?u z*me@4C1njAz|C&Wq#Lzk-!46Q|F(3M60QEK_ldw|SBs#uAwd7qI=-I~&k$u})`Lee zm>eTc_QPmE*r#L$Bq+8K77w2VT!g~tnK~xTFjj~Qh;x3w zO8fZ^YfIMYeioN&wK^B2coqzGpRRl`fSodLysCS(9RhH3`G@v108@$(-ji3~bG?5w z`KE>?Od`s-lN;r6v-ovV2$p4eivSyG6EkacQ$(54Mfub}nFLK;vhC}x zV(M`OE&M3B!mJ)L_dY{qQk=y=Yel3s>n=&`L?mlee?z)`eZa5`!6jq{e(Rv0L@oWC zJu=BsZkzT<--{?N5+*OzNU6>s3%&Ar`}j&O^6KB!h0Kr&(mE!V)A+%E#<>f*V~;}l zo3vH7eFB1+_rQ|cGbL`C@Bar!t9tfhc^5xdf9++K5NGkZQ;bBjc#Mzg`pVFiE@b^s zwEQu1D$2L@c|aSSeLNzlrf?SDo^on)#%ToYnM~QjL8kZTW`GB)4gdWf^OiD~<_FGUKwJ)dk4f3;*O2@44}eZ}>vuzD z@y$;%>rNxu9Sj;N`;9FHK?A{)6zx3L5u@_&8yiB_UJD^U z@ib)2_9Lt1hA{s*l;u?eg)5=8tC=EblM(8A*9`C;m1m@dZmT;c1-ZKJR`-qR1PRyir3Np76oDopQdHqng|(BKt*Pj|E4#p#u&A&}|d zxtipNtMQomIxNPrZWcc_CAEB&@4328npwEI<}-Rn&xJix5UbC$i+QfBtQ#z&*jk(Af8E zggJB}V=5{V02bDAF8ESWhOALg8RtoZSZSW0_4$zJJuw*R znk(ME)Sk|sczP$Y5D^sx=xe>fngS4OE+TKty|sLX_$tE zrNX$ZOmqMNhl%cgbrO(U(FLXu98f6P%bnXB`AcXLaVZf7MIDvy+bQ_s4(@}-mew9A zUB18tzYm>AYZ0AE?g7u0x7U^6e7TO5*t6bp8_D3-#@h4?R1_)iA0o7h^zySXK*`)T z_yB~3jknOCdNBuHe+H}?gf653Ry97UI053cJAQH?30^E$kQupera_{NE|Abt5($+Mjs)89o`I9wa2lJZc3Y@RnN zvf-gKgLKn997oyaIa4~B--#SoqVmKclTy#FoG8FbkJLp%ZI~@ZU|=qZF&dRU;7aT@ z*2p^w4|*h`MAyUya#SXIa)p^Q#xYlm2j|XkF^@i-yjB(_)=o-!ZW0~9i(lj9$jJd} zvCjO^1%7CKP!|xjT-c%@lTemDDOP~>Q8=f&gN)Pn67GbfN75#qJ0W_jtNXZ4@KZ~{ zAJyeKTFQi(y?|E-bGnFT$+=Njb!7=S=kB4)ppKgvG*!6yzPT6RiiNu700GCA*90JG zDtV=SVG|-7@Fw6sqw=KFFvFV+a#-(q^CZp_(N=&c(PYlC5>w4!4D=!@4(7KaMZ1E; zIa*W$v_I6$lKJzHBwWXRAnh!ZTEQr4Lt)!Ez187P8eo*g#Q-O@mN(P1_r@vDr#mLu zZVb%WTXV29SBetAEf!X#oyp|&bgF8@lTsbSAeiio9c4g|NP2c^99)K^Jp>~%7ZS?0 zHO{AESgG;8yl3~T9go3fdiYCG$2CxtM>YLj>zVkmRN{61z%unk;v`<&3j$T1cRAFK@>uZ~nceu!b#eVejf4aj4;1s?$* z-XgaWe+%PzjgcJ*rp0YdAX`^;k5$g2s3@-vd5JFMsE1eLNd&Fk``uP3hs4&uQQ&-i zU6n`RgyLgos6BL3{6G!V%xQ!qbmiLuXa9s@*(kt8$tp^QI%f$_T!Kh*_ zOyg>Mip`-F;8fII@uc>k6POoG5p6%lMCi*v7Ch_c_Z|wf4_Wk-lSoV>C$hzMAaaC= zFU9!0%zVH=vC`xMc$wXU?ix$us45|U_zsKZDdQ0EWUjAcn-GWUFrEfsAZ6JS+7xK8G6B$$V7xXS7Gy*P(W>Pq| zXM*{xs1(f|zYgl_2|>e+cS?>x3GG5OQ@jZ4%f)T)wS0DuFmS&GpNX#Lv*(Xj2?D$zY#w?f|iT`T6F$8?4gcz{@GxKIEKy9zJ3kWiW{;l za=H&7ZS)Bb;&^n!0VRk$7xK0*Q3N#3~}R`uaiA_dBEA!f%{-oU&?WR^(|xQc`L3g&Ha#qS2U zG4qQ7HZ}4gd857GptgNL|4?&6Xw^H;9b?9e2IrTAvdzyDpny)tr%#-@jR`bKv*!nygHG!i#Xg#NCNL? zNy@W$H50>IJcqjIz)uO7^zlls5Wbs;_N>y?T3*dn7@H%Gz9as|<(f)yZ}~)0QISor zu0Wnr`tAe3$QSnvI$l3oy(~0)GG*wmuW)tuFOVgYQ~ist#8Zr{pSy*dDDnm7UO4Q* z)w&k79ssr&zEA;Py|I`W)`?uq9pOM0-G3kmj;B4O1Eo#p=!zm_QQF6)xD99)SaW}Z{pZ*&cudIOA2;t?$Z*W|sdaG42So9vJ55E(MD)mSN z2L_l=QCFbF>lvHc0s=?go}i-qN4HlRTa}TuMLjr&+=7dD1HcMBX|LPtJB!lG}%T?gtOKxwX;DWaK%9>zXtE#!v2$6AzP(>zTF>wZ{0YMQq z!1krrmKYNR&CzcZdez0D0&*lM&-8>`{;h(j;p+HX#Qv0J8znM7%GRG&LlTg_{x$~V ze5rSM2XKrp(qTGYW<=DG=Jd|Jh~CTTb$NSN4Ses^%Nopqz9NS@B@z-hp7fcW>VKgP zh?Tlw2MIE6o_o?{nu$NDjcleNcL?A7PD9o!3cj6iZUe7?l|vFm0SCfm)OHGEu*Oh;+tGT@ReKqe=p2`ryvQT2Mjb^M|jy*hC7YE99KBDj(eQj$nLc>bgWb1 z4*m`(`2BLLWdN2eB!HqOO^jbS|7xS#{4(cI{jib3zW(Iy(6vcAe=auMCY?ab4$gU) zsRj^QyZGZi;82QEa0gl56E%4-K$|0GI6uHJRj;kcQ!NuYUZp3=SdjnPaplI z!THdi9jU0{UoL)p!uQ5ep!aI2)ybH7TCo#<+Pn6~Z|7xh%h&taeqG2O$*u9@NNrEo z7Wq}y2Q!d&Sk@dNQe#whfa$%N(q_Qte7}pF0M57bAnd}d$Eah^6)_l*iQVAf=3JIwBF8~_<2lx0epYwILg5maJ-Qgv* zzSJaQpmR2^YQpjexXYEYx;V(7gbfi7wy}bh7S90?LG5zQHEK^yiS~_GZaxbL%_u`4 zk>`G#fMI#?@;PeH$}STGU*7#nIM;DnkR25@kRh-UeP-@#^dI-2v8B(l_{`M#izR2e z@~!-Xly`Ep{5y_|GjqOiHHl6zq|8<*hB_Y3y|=-;;UeXF)0m67=so;$|B@OoXC4a8 zL1WX^ zi1vK}qwTM8u@}~Zzp{b-)fyqb4wfB}N@So0Qn3L>7v|1V{T{*?En#f`Dp!mcCOd5lX{prWvzKiMZMv93~q3#UDS_VN{4!l8%uI5u)97LEOx@Rd3J zV;9B{Kszj^(mO!pQ+a*noMsPY@HP7RQ`;@{AQg&qro@1X78n|}V}O`?r)TC@M1{tc zWs{3IwDT?>HjGAwUustJF3kN{x%wwe%;I)TU~cA+oa?P%VxEz(S8^W^xc9k&+6OS^QGAIia4n%@WPpG&dz9&7SxL|FQ`~*MWjf73mIiey(#0P8yw^MH zglNGVyC3Hs>e(OqeNwE=Xi%b20c<>}l8n%LhfxY=XYErAYnl`*yWW%rUy*SNRh$84 z*ub!nnN^hfB*5tG9K&PyIGDJhJnF^~1rMGqbLyL6fN`#JPdaf9K-Mwn6+Z0uzr5Bt@MS;O*+)tQYQKwkI$O(s}$v^!@&MA#HlY zCk^OhPr-`>nu!rHgC_(j*51O%1vXBshW?x(DEB zrZeszM|7rqjA7oVY~~xel`X>2>I|vSXL_HRw7>&}=;2ig`Kqw~(Jwwt{GA7;woVQQ zckC!uli_>K#ePgJc#Sem29_~;OKbQeui=325b96^%3FxU+&lX|Lb=)JR-W+?Xy=*( zz|i#{UfuWC?Zy^_IDR&;@)U z9pqjXfq}db3JG-cUEVO*@pW3{ZH!NT4oAwf0Fjfu_$iF_m8LQ;{jSumv=U=#gi7K? zUA%~R>|;(Gl~-e?CSTB&g65S_;{1TD2*s)UrI$a7uR@%+CRDynBz3(ggiZcm0 zX8DJq0OX++peCo2o}NO4&{XxnLYi4^7|7O&TD^w|(ZG2L zVml#qZAigcDes}_ZPOczd+p|}tQ&kBsPW6EjhTeWd>oN4@VGjx%TS0y1JGTG`cZVh z`7a<$#5IP@AGmt@RQL*XB7>4_o&hL)&ug712hzC_H^CLpVYH?3$$L}D7Ebot!qU|a zWf%$0-kavy0ZDvp31Jsu_ArHIezt7(srG|-jOUko7hpbzlBu3~jhkVIvUUG;!F3}* zmOm5>Wq~nm9ECxI^GhrntTC+AW5OrndXwh)6fBG92m>P#1p3g;# z7rOyb{L>OR4gB(iH|;AKohRp{F9JJl4>4MHumZ88a2HX*yXECJkw*SlShVfhLGbQN zeiR;1e04QNFvWGkIH%8|hYVlP_{3?dY6rMi{@H#{XcG4uhd`qD!xkEm8<=(nwd6Ws zmfjak+|2a08Gml{ud!EU`CPHao2^U&Be>O%+Vd_LjisVq)J6bJkUdgCgB1;tnN~9d zEvjUBJ2WR_k*k1kG_qEFYp}|wvEB7>dwg4X4b~2ljoSPxoM3Avb~C3}mh%=y);}m6 zIN%vhb;#}kvNYw)dIRLxs(b1D9YcL>=le9pKJGK0M%XVn_pMbk6N$=0VVTP*B@9D5|8&Yal$BkZa* z1#~aK#E8>^K2yA`GYM+QG?V(S zlrWiWKO9iue(V@_I{Vk17;w$~Dy1ffw)QGLdnyVljCdkY?-9p~vT*4nvHOt34MM5f zOoF!N2857ejWg_+723;DSoP%m#R_g{MA3v#GI;OCY(?ovv z8kZ|PSS`iTVx7~yh`>W+V=6I4!q>W`20Bt_0*I5$j~drsh!x>f3X5Ap)HB`C`c`si zfFkH$&0@asP_6nZ(mpfOd}Qco-8IPiv-RljH#w)Dck3-ei?{x{Z|)gimoq(=__TY- zx1*BdNN@SIux*nR`0h9Ez7G}~$Z5_vc~@BE=)kgJx4&f(oR8>kAO+nMWT=4Tjjyj7F$qR2 zEFfIfVdkGy6moD!A*3M3wveyDhAF5HZ{VO#r|{ezfy^1C7>@!Ilk=@klT&A{F;gsj zDCD@ZWh*Yd`Yuu{p3(E}eDtX=4Xbg^%VWM$z)qCmg;WDzdV{_;ZQu%h8UA#|gaY5_ z7uLI!_-yV?TgIMQymHZ`QWvtMah(Xu2jHR$Fn!#tFe(PK`-*}O5VhAQTDxIFhmFH% zx=~RqvV_c2pl-JtKHsYhTXB=<)P9(;m%p>jxC}DijV);a$eoxh@p}6V(U$asOBV)$ z7ka|=V}&q(xUD^2oDa@F;Lo#E;4|8Ri49@>00mJC~8Sl8S$Cg2Kni!3czG(_E; zSS|$i{>3qj1~XMmu1_T!caV6^2|!253!)EzI5_b=1Vq4Z2|A|`+E`;IG=@&Zpq+5y zgdN`?R>fZ@XXEsP#D6u%gF~5>@cv?YudN1MsDlNJ>e;3zil_OGcJTTS?=GZubM2aH0-qZu zjTk`pRHpJX8ukpeuhMD2e+~JMDr=pG+28}hKrlqbOh!Sc zy9i^hmqrhO{n}W`hI{@+T^+7*FvUK<#-+Pd{G9>9wTs@>0LRv^$h_=9l=t9C z5jf0O!wNv%MSU!AItIUhtHey(1vD`$F8o`B`a13o#M#lWv{JEyYTlE8-OqcU?~{hj zGynjL{g894!^(T_14AtPPc+b{J@3>mR8+(9X`c}Fpv^M37LKMh%&dC;S^fZ3j8x&5 z;!joCF?1?{zLS6agbOmA$R|oiWiC^_TM8;8N)qMywd-M>4&&ui=6|37mvZ+(#dO zb)IyvnWOs#V#ZQX8ZjCRZTLZ@y}!V816ky}5b z_LYtjB+dr3gVCL`YBTtL9rB%O$7j2fP369@)I!E;rYC{JTN=Pve`OVac-8TKED?B+ zNc9D)Ex__-_}?_LdtUa9C;2boZN;q!0{Yy#`nyrl0U%9d6wKpE=-7MXE8Z}N3aKrL zhfc|;YV2>H%N$!$-)3Dt=MZnXeE{tLVz_EVc#=U_|3nd6!aE#Hb1rGRg#p6@hy2Zs z&wpiWf;f!N&`6*?ki(yKbvC{}z(`+>sNPiU=HpVWL5qRW=|z%?Z5btD=hcbMP6@d;Mve@ddb6h`!^s?`_Xq%boC${&>`Z>+ZFm$Ok`kcf7{@4o*mvQr;1K}I~%7*V~YP4bC zkNl%nhbI_>P@?}K?${~DRcawnv*+(U6*&b71AEoQ1oC`rE+>Z3^RvvFsLf}&U0pL^ z^OBrAnGA@b?(&muz|D@PIfG;ldgd}>Py~FWjUdzt|0s$O1sR-uYBA!Yi;u$>gcDpDtz)NkHGnyL5oud;5*OrmM zAPZc?;fHEtOapi|Yu3Nwy7&b0_6ep;U$h0{D@`|tKqkTdpm3&<8S|Bf&0+lvy~smHs8N+A zRr-_dtG$W>cW|h*=V`Eit%)oiJjIwBm~Vd(&fo@|yf=07wnmf<@#DFS$$5cg(ePGNM=MB^JINktDurChyqZ z2uHlBUKcAtsXJh=<^}qxO0X;m-`9@`2wSmT48rRo!gmO3!}qw%7eQKDk_$^4VHn7S{*Z=uAhep zs*U(3mS$30?RyYyyRbDrjAJd6$Q9s6$k;cmF%7G+pJ1wEWcfIGBZt z71eWtRfhil9b8x&pc_m<7j0v+0c#Ys`>(?$co>Tj%cm~KkqUoCq?}cfgUx+SGP*>@ zD1D6+8;Q%}+otEzj(#zbq7SFobpIsHGA5me5P%*d~e zd}tIbi%t2gF#1oUg7nab*M?kMUn3WJ?Auz(B^VgByMLcrjjQs?eAK8g@4~2;=G&y@ zd^|k_T9~?yX{-< zl&kJH`!pf&b;Kn4({CSl{}I0Big@e2zy3U3uej~8$aAZInho1M+W)Fi4Z~uy^L=T> z3HiRG+Agf(4(5{jq(7(KfBB`R;>L@_!#j;}9m_=LlUF|u%7*ja=t)O~{}dK)FDDCc ztS;)MbS&a>6_L@tb+@1J99w_QDp~%e5jK0{3$@XBawQdE$iqUjKwJo0v*2M2r6QHp;!?sp4b&JR-$U&9{Kf26Mc9nY@<YaMxOaeAIU${Uq-)qFX^RMhsLWsH=07ws~IJ2y8q9KE#d>q-?fLg z7#=UjeIx+Ydk8U^|3f{B&kUP>>vU5Qol3BI+NT2qF3|HJ~;N2o6ZR zu462M+Vv3=&TBz= zOk?Ag^{#t@{ffW34i>bG+6)dIf1+6Z`KfflSlySqp|7iNcfCXjPJhH7FI`uYP?r_n zt8VOBET~vZ3c4op{b^H#!jRc{{x1%H*T>#FYtphf9zMEvUUYiQ+F7rs`Ie+*eU(e# z)B2U432#Pcj(%|OJ{HqYH2U)~-Lg7wOKEwM&ZT#4R}ur81x0I5tQqc@@>hSfNG54t zYumf8iGn?rmBAaoQhDL=!!>qz^kJ!O#HPm?56!KeBC$I(^5)YPZ8;UaZ1vWYd5doO z&6dA~#Fcx!=)_EFOn*I!7QW(jLMFb3cda^pO^l96b9C)}Cts(9Ji#LG7uOeH&Z}33 zoz+0reS2KnSJ-rdbAO8YX^I}{Slsg)qC(o&dsOx4WD~9DL-1a#uEjU!vVljV@!Go> z+@t@HaC}2k{xx**XhGp8+K%vM(m_)H_k$mFxvKFa%Pxq0^#k)#A3{6}w#kHJ1!8$? zUV<5QnjzONcv(4Bzg6@kts4sl)`S+^z9X%b)Hm9e>#P zWLZH4lWeDIc(z}7UHFOvaUL-PEd}z)x%BK#-)(ZsPXZ}CHAifHZ?o{g=h~{1pEibQ zf)Cl{C4!3&-Sumte$oXWmKXgw>FxR3;96$4`?VHnv+yVx(OM^QaltVkwa3_^pEerh zm$u?-)`L!BG*0j5Mat~CxmS`Cd@Uq8;bif;u|U6$>i$LSEb-qPXMt<47i;HPxvDa1 zdKUC!L|zzxN7M+#jg{fH@8ztqC|Q`eJ5k{Q>8HndTDzZhhKkB`&Zl;`XB^LH?NGbi zB%;Q#k8v*KVpWwD_RwARzU9Mxsw$JU- zYq30@4@O-`xdQ7IU68%BGNSv}8n@(Uv_Mrh;)?qFiDM$MSk#%px__dQd|plke(-3j#=$D0}3CefJJ^?9T{mQxW+mqoMn(yTPFD&9u&mz#d!V^T(s zkwm6uv(D;2l&qBPZ)I@9t^1H1TMn8M6a6@lRpD3 zjVv8YXl0$X8U}%qqrRtm&?_;d&`3tI#Ny(1Q?$%w$yU)?Shc;2p)5cFL^s?Xda}%!$ zm=zCXRcV=jQFcxmBFafp-K$Jh_4#K(#Q< z3NNsqoUQ{)zxr3>*F?`<=k+I#e6zdQX~|3x=5XS@!%=}wY&iUTK)_e@9|LHLLzyGFXz)2dgRwheW3b%#vd zvHJF2e!kBxF11HN{pTRVnbrg@6))Q9WvYC^E1xlZ)=(t(R#at{{h+U&R{S&-o{tD?g+@Kk5*AadwI_vOYy|nOoiZAHO=`UAn>@ z<2OTGPUw}4q^g)Ug_I38%h=hpPE#LkGUgC*=de*>7r>{j{WJ#WDx%TS!=2?pW55$A|iFPBc zN`z6kO~$Pi*VtCC;e&=ldW?@{c|2YP&!oI4C9R&Mpcx<-b3V*pGm8@!vkQlHM_I-Y zS;6u#FUHz;bw*!%F508^)ca=3g4_1v0nX)LNyuutiKwQUefv_H#e?03Ti>(#ReOb6aEAzgil zw_a|;$Xkke2Je{wjYa;pq|nP?bm$>=c#V5r;##;GHC%G19Mq?}W}IFOKS zH`Z9`5!pHMvWIT$f6S9_7~A%nV6pbzce9H*!mdqukD3PZnIY7yi!|KK$u^|Vq8o{T z#WO?}2fZ#ODXNXvUz+%$EIu?XqrEr$iZ;HcdWR=|QT$5u=RL6@UZ4DAW4plxliU8v zm@yJAPzwB~gV5(8P`WhAPW)6=+tlM8MUKC+l;OSqLeLXp@<{3J*aa&0S*hlYzQ={E z&>e5*(VRxvw~Vu0oa(xqJ7h`5c`@+_J>F;ci4jwgZ*j8wv%|d9udwPSuS8wTd3CWr zHt;e@PJg;VLb_md!#6&PbAQioI%6MfV?LKok)DkW`Uni3H}1VVcK7+;Yw@|e!s~>q zl0V<=8@QeH!t@)i^)C-0#I$iiK2wVMidj4(6!a*N6?R_be7PZZWISLtY5D4>uVgVF z^|7ljPh*NpDd;yw8xLa_FQ+3+q4nrIgLbb2!MYqSvF>Kr?fK^AiK z_Kjh+;I)a2zgvAgzc`KVxH8co8GNO&^3|Lf*p3YRsNwy2E=zZ1{TCW^$C}vQm{VFZ;)Cp2lk*Iia+Ov0}slY@cv1I;8I-=8~^7V?-|X{IzcbA=nhn2EWLz?$}mz<5$D8j2Gq@z-XM4-e#)T#AOv0uq!ul-vlqPz3g>IZ<^DO~0mJ<2Q8>J4@FiRnEa-!Tl!NNh0X6(X$FRax^ zM&EEoC^mxPVPz!sx}zp>t_wz+7famIr}Cr)#eEHY)n}GZN1(Y)j~34>%&PZ?X5Y3U zUH|aD#?CC97j#9~vyq36U9eZsc@?s3kr;LC$fYaiRAb`vaJHfAY)6wDO>^ES$m_1V z!jlM0ZR$yyTbtO-pVRBhKmDzG{VHC%f7+NMT1?f+ud2t4okzy(al3Y^x<(~#tnYfu zElZb-^y40mbS3q>I1pz{5DvVp%%5)=kNwVMaL6?;M(FQLH{q+$)?VtE zjzi))!p>HDYkhRm_s;Orr3|OnlO*@$yxZ+#f;KaIH1_Hlw7-e^D=~0lN<}d6)12R_ zFy8i-c2aJvY`*Ze**(ZyS>~{9lB`P!4ZYWQWVE@4XPZtJn38ZiY-bUx&ckr;-{9j#|o#@{u z{)llueWHOiKHzA(<)=-M9U*@f)!@6Xqj$sQ+_Ch`q(_%lJzD`k9Tx z+=m?oZa2Bz^6~%eTRNx3r*x-~Q$bT{LyFCA&G_bJm-%;eGxiq5XXMJ0m&b+`7L(V_ zS=roEny3Hclj86YZ{CgU`p>`K$!~y=`+xubjiZ>ecVfRPteUg!+8y_S$W5CBZvHp> zSpNH_OJJI_ga6Y$|2J=PB>P`)ax`T9K>Va^?CNy~bQBTy`!4Uy7pnQz^EW&Lje&TM-gd?N+?29R1~BMf`AYO0jZJR z6BPxOrqV)O}dZ-P!+&B4TiCe37@F~iLQ*++Sc$@>h2$U`74G`wJr{}MC2T`1&JW#RmK~+xsgW%32D|!I?KE@1mcXIKrXiyyzXyZi9Wv#yd88;yN-u5H+ z^)jdh;T>VRAox?^3!*;>9NMa`pCtTRAIiHS&|qpeHk!uIeF5d3j<9*pkL^J6gP+E} zSE&+w%5Z)m4JVuJ0lz!N5_xrQp(K^Z8BQV}x8vt17p>-`%Q4J6;PKl*g{PNf>&leY zLYmJqkww`ZDt-Qf8N)+%RIe6ZphOOBV3_4IyUcT_hL`|nEu={fRoe~0s44dk=xP`5 z)yc-Ynk{}KlDgQlRBRGFVK+0YCLnjz@FPXM*9DgK(0jbAGuuII2*1iX$@oYACwH`$ zUztC89DZvEC9C4%D(4FB0>cca1%gf z%UMH#!?G}u0BeOmKzepDkiA$xD0Z0-P0B)btFrV{pc z4791>;RR|+YPYfPzjt_aFH{P7epBh7=F0RM!c;5aJCU$1I@e&)$_bo@K@ulZo? z?H@w3>$ja1dmDdYap4qQ6dQ(QZY*azs+J)t%cYBdy-6!ndLMGa(X^LpKs3@Jn2sWD zI^6oYa~^jlY2+4}L}~7f8;u!vfp7P@ZB-jZ$(ex@jH{?|5PL2YR=l z)Nq`vf+a<<@`DR_SHu81X1jLtj*!gBiBeT|Q2f1_tn>Nt|0qG&A$>ML8^o(~#!yIH ztwX)RThA@&00+tKcn1(tx}4F_?=kQoG78W+x+M;@9x7K>J`336c=wL2Wr>3{Gi?}+ z@xE8k->l7dKfda61JkoQ!ApF7br&8$IP;E205q2w8y-MQO7MU;P$x4b{ehiPGY^e$ zdOzC)fc=5cbkO5@Co5=+VWZnJ4=?p3Z)S=Em>NqX-p5$)sG2_rJ@V9aSByZcDN7N! zWqx)l&~3a@OM{;K{AbHR!^!9=1F0n2@ML#r48QEj-UM}aqOpoqr!i`oeNhkDX1Dll z|5DGFXiG%>K+ZyCrXlpTjL**uLdVuS#a%!W`WcZ6^p@b{DA3OsngV)v#VYm#v<4kt z{_G3|V#Jm0WZ-2_>dC=+4aQ>%9$>5kiJqH*gH9@`12(&`ole&d?up(OE_6lLn-Mi( zY8Jh>;W=~hTL58vv&?#h556FVjt17C!};JNtFs0^sWLFwI%UT=y z5g;SA=%oP!u)H|`Cz#B7|94Pn&etDW1B20-pgC1h5%wGyypmHTlJJ}timopmL7l3I z)^YULYY~R0#Ib4YHx<-0Vg%5g_x@G^+C>nLVGLxl4+TKi_n6GG0~*gKG=qWFf=+zc`w}F3{2-!?5kv&Z)TfS8O$vsxPuC& zhHurmkC}Vyo(|oC68yKqQ{ju}N1a(g305lysZxA9GYNmK7<}AZjrM`dFdltc8Q9$# ziyuG$heZjlgoXQ&)eIc6BQ<-0z0e)y0m?7F(dY+)HtP@m_jh9_qsBj{)_XYilhbo% zvK}ghpA{I}u)H@w%i~MmKLSIrvN`|+E#$%m0gHB;>jvtl>2l;XSh%_umtom|TfC7{$FX#boHyOj-h}s}#nb?*pUR-Edeki=3~6FBcpcZ3pz~+wm%kofF zu(u_aJS#r(ltn$K@a6-@15_0QE9;nMlP z2GA#NbxY)t5`Gju1o}WeK|w&QT<@T+>#m2FziN5_9??h;rJTMIzgFGzs5sX~|CuiwJAAmh@ zojwA6FShv_Cyka4<3~S+eD!d&7#^~(ek)IE7}EeM$%6EEcl9Z8G4~I7CL=`ETeVT; z&_~e1m;kE9+kPBy6*gpGw==VRHTqA%X)vF`L%YB-wLIMpw&9mJ^$%#l*F44sbV+%B zw?OG*E$@{k?OE6TDmNdidfjP&5wcqgN4wrhb8O?%D_${kzZG>W~;`;D9)K$lX`jh9RDBg?rA_P8$9U(f!(Q2C{RaXGp5L% z3$g;2n0tVwHLPxpSoiBP87K?tk( zdzqk6CafqMLqY2I4ElWHWt^B!`pST&{8`L(zUffep^4SF?w}*01K5OxkgcD1x+Ok( z-V@Nj@+~sy9x%wBv2Tia*;xJVo8K=Wt7z-!fbz#tw3S|~tg9yHln~jtjZl2k9#|k7 z@H?MSq02vpx1MZ_(;I+J_ty*jcDp(jNatCYtzDhn&d+>7ZI1qG8pypOQGEE`fXaKe z?=L|Rsx7WwWJJC6e+XC#Z{n`J)?d_hyZH-Uia4Pz)&VNB=U@$cb* zQ$j0mxf~m7j*bc`#F$9*KKinHZ%zl_{*)pj^_#0yj(PR2?c@iH$xF0R-Rc<^+_7r~ zve{vMD&E}FxJvTR)q55EpjZ&4ZU2?C>)>kQx8Z(e$d|sS#{cc9u=y0F>L~VYg)upX zUQb0y9{roJeoFjgzGvA6dgM!$g1B1F>;7*mk0;oP%P0l&&wvik%Ul41XQt5D@Pk7s zwJKzwRb^R*g4k1G!Q&0w;##?KDagS(BAwMB(OFV91=-2sz)!4@dj%(Ck$vDs(>9@ zp_T%i$d@Ib;A{n<7bW2Q&OC?a^?4s81uiYaJjgGD|rTP1TpfJ@2QMtWD#~C^n zLvka*FXKWh4_U)-)yrfSp><~GT{2OX|J{ENKWD)q|4m-ZZ1PapG1r!{&>#IW0Xups@eB?=*X41jCa2)*#d2cHMcpp+HXo*5sjhh&9C;b9i;A4l(eMVOI z&~aC2SPW}5_U2x~(V6gNKR)er0krVZqKhC)A%9ak%1@Nc1l3PtdRBB29R)YG_Quuo zk|vs4DLXS~ql6L1c)h3mlnaRR`Ok95;9CwnA+M%(YfNvyjy0>m^0y3-vi&*nWnOT4 z;5UO67-^4kI=nA32l<} z_|NL*C3ed)=(W08p8{KEPPP_;t=Qo=fQFZAzC_0^TbEdU72r~Ol;{Y=N&LK&fN=9G z6`E$5Z$9=xay%i0h~7pfT&~#W2X`*+uYAdwtd+#9^I%6Ic<(Vt20NrqoI91?ZO*$0 z%`PhjZ0O5&qgU()-{+|f^h`~?Halp-=LI>hg}~9Z&CM5t`qk@x)&K8O3y>etf;24mQV%e+53Cd=qsF`*wK? zvWc!Yx98LObmSFgLSPW@aNicj@k9ucZ%ZY&*9R)}IOlJl9)R937ik((HD+#1x}oDU z%Z$%z@r*{ET)}?W3VxK)&<~$;oBx@84Qz8+Ey=JFm|SzedVcrmcyVJY)?fDQRl{UbMn6Z4Bt4M_{ z$=7j86J#3kGwNV8zr6PUNsp}HC--duqnVH6Ha9VYo$Z%xyiRo{%#JFgLw~=P?*@wT z`;ZQ#V!8@-3F%tDY9`64K=$MHeR9@;G3F<(1%mkyLws^IUh_bugZ3L=alHHh{)z`_ z7d-=3lJ-Ru2@=0a;Uu^`4*$IUhz9%8L*)b8l~~!Xw;L;!c7h_>fPX0yP;4LR13PhNQd^utGaR52&X)4_~4|et=0OLA&B`(O>z+u!6C6 z-)%txGb*d(0N!dlvw@ZsKPp@TO9n2xf;@%0 zBM2QAZUD1v$26X1D8?$7;+aa*^+3%gFYwz2tA*&9NeneMQEj%%t4=0 zMZhi6Yk1Nk=41w5m@1wMO|Hv%We`ZDg0p~$T3yB81Wy|Oaw9ycGRhJdt!%fcSMrb@ z9Iozlhi=r$5)~ot3BpanT1XD4rAUyZVBmeFsRO3M=-fh}_W$Df0&~xLod|LpiBOzu zeTcv}a}HMz;^HfYk;w!6%%RvLxxm(5?3#^%%-BV46J%XMlWP3}Wg*Yf9AF;vn>gCA zwN*8`K0q0Eljha4%yI)hFGJ_+e7(Xg2To4W@-9P2{zikph=PNTvaQ|+@k5qtQKGi$ zGF1951R8o=tBU7kL)Gps`4S3-Wn{D@LSvMo`d9^IFmQ?0^Ay9_vY{Ft_S?x~_U>jLxWutn#91Sql+;1bfH|8;(tH|H@L34T}96)EC9XwhdUGbX=$> z@?aO4{+3h_ZQ#%Lo&YnVqB(alQl;gtyH|52GyRX9UoxvC?bC~ZGh=1%Qnu$9HoJ1+ zncqWu-o+9>y=__0MO(Kc>=U#w_;K?fg;&}Seavs+RLIsxKv8qhnu zOdBZ!5n0OIE;wAwWuB*F9+;_Ydfo$C*5_(%EFOwF?zB#c-JsdLo8b-w_|g%)+vAlC zUu$M45}L;YCPnlFc~f&qi$Li1Q=To9maO{}6rkm6I(9f5)-|#E_Ny7oRm;FMC{T=) z{D9`Z4_2Gqp@5?0VhL)aDF;U&G3iVKwUW`v2(-ZVGyD0S1km5B2-NOMa8cIV4bT3f zZi2g4s;}Da*AXC4qyD-BHGtpKqp5IrHyois4PdgN7)lAlx%pt;?RWW7P$@D9GKS}} zIht>k29aMk-v$i(1VKeyI_#w?;{8lgSBB}R!hTHX6UaT#`Fj!$Od-X1f!zd*J+Je_ zR?C*iD3IRcxba=nVT+dYE-h_?E$RuWji0pVnFJKppX`6MqSEJ-XK+}sr1Q*WxU|gC zQ9cn;Wr^h;I{vNDXfR3%PRas4DNhK`-3q0UJKU3gY~YFaBe|>qs8}lJkw(sehVVrF z04Un|{haPaJC5MH=MQV;;J~Y7I4wh`RP%!@66@`55Hw|_=1#-y!v;Oa6N3t5i0z#% z70_de;+1I_$26J=TWYHwH-i;k@Yj0=OWfnf<3gkRFgHCN52N4e;5mUK@}##TlOAKN z^IAXLlpynRlJ3l$zYAuzHw^0`4ky9@r=e~Qj)w5*(dR6n&W<6mP_Dliv9HuCf=OMs%KRL*P2(iV}vDi>IwQax^` z!Me&1^(@5;W+#3{IwV~3yM_NS_;U=_&Jl~$ru6czrfJN0i>yD z_AT~tFmDpe2125BYsvVn=dd^%xgWny-y2J*xD^IwXXIp)Jd;&1khHNr0_wE^?8SHB z281IMauI?ahzkzJihsgc4tb71LH)`9+u|w+u*Lqoz(B)yANhrtt?42tIw@5*&2;4? zb>6XuB4qC+W7kK+&1vk-Hf4gnben%~+b}?y4bYe;{{ca(TBqEd6JjfA;pP~(3@hRv z$`=R)csOH`#RgEY{DQ1uLl!@It4!xFSdyp2ni(h~S)cu63~iOY_pZK|WD?|k+U?vN zIaOfWNqcj&p=p3mbLlg9ima0=z(FvFF59)W`6%;zKvD4^f`@epwon|-ii(TK*? zAFeSf_xs8+YfSuB0d*3}?39%uM6jRC**o2zuprWBv4xs!{?6j!u7Tu}j_rA*uZ&wU zb9Nam7^pRt-E0K~%U7(;;H>L72B1Y-l6T4k0p4f0{q4pV{9domp`mz~@z=QfU^;Rj zmOjS?8AxY;x zc}z1~Z6gscMJKDyWS5U!I)=SHLm87(hV;$qj?^<03JHT5n^tmKK4?21k2hIFvD&6{^{%`nl zYb4bFU7Fs#h6B>C6mn7@MD*`DFyKuLa}}%h6QGl+9mjvPgK1n65~)Sq4m|;Go0Fhr zws+_OCDNSfS|W*;y|NmkR6G4J;mk4A(ou|^tz@tpc{7v-QfQ@xtd+#lzMWYPJhR4h zmG&r_NrkdeG2Aqa&#psy@y#m-_^CgDAg^Z(d)Ow=8@b5|fz2{(S0X4+i8G{^F%SQM z1?YVF464SuDmWJ)@~_++GZWYWf$a(dH7@HpeC5j9I_rwVFX@;+?j;9FL**`=-Ho!7 zl#aDDp1Wf#){h2SxeHg>8`81*L>;Mgbn~l&240~i5$S=!pu45YCa!%g8E)f3nB)D|JlXuU<{!gab zXl;kWYqh?G3iwDjEir1DnXut1;nOFq<4o!MRM5gF%~A!S*hy?IW<^)VEx7?o4Fh8b zav+@eV5&GAoOz|2_0bL7rM}snaO*=G-3k$m=sph zUVST15HZ6Z*TC^Cd^L$@e+3G@nwW7Ts4TDRbA=3hlty|?j$6DM^&YCcq{~{~QrzOh zUbO<kmfvr1Wn>7Lx2v3E`0R|?51@EEdxj#j(Hrgn+07PxSo2V zhvQZXLMI39c5#>5OjM5HPdawh@20Jo!W$zNnqLr_Um44hS29Jpyt!=v#W}Oj!bU$m z#0S93Ni-CYh!R&XP%Q6QE*<{LGMV=upkG5Om|c;Yd1Jit&MgW`c;`dR?o`1GEpDgM zAV2I?*SrV?Yu}4gsxVxoSQL1ke14`4Jnu1$vSNXg8xR-10f(lwx>peIMwcrdtYlo) zD22=Z$`o04lJojJ#kFbWKp(eCWEVhHVY?AfLoF_&Yl9?;vmY6X5dD-?Cgj`4JdMz> zJ4!=4!)aORVx-56yGA88$2ML=9yUulSqGN*ep*Xf0O7RBJcK<#gkTK12%_(Q9|k?G zVz=-yNCc*`ykVq%rK@$|g=Z#?!{{f=>d!|b8F}(ABf$UUlH<47*Bmwz#_2%+SN9KI(3ZZgnHfj$py z1qlm*P*)1x|NPQnvtl*S86yRj47+kd46SxBgd1(3=g-FxQiP`^RiINa(@36zyT!qY z$Iu+P{IFy*=n4#9fD)Lk8T%lhqe)4#f-<;I268G~wSF%i3Ul1hZ&x5zyY>W%GzeN$ z;?qGGf5-1x(EsUN&4m^mCBKGJxJQ;)mBH(4x~B2c5FIw6^oYSinCt?bIPZYN=N)!A@v1WBW(`XTJnXaa}oH2+p}yI zyQKSy%R^Sk>w@B0IeUOhp2mCA=lT*{%cyi+CCx{6lPwV$8KCzncMt<=Qi0fo(=rHrA`GvL;2D9@igFqp?H`{L~ z*;qH7zx!YV%4MVUBEUfwya5o$jXl(efn?1uNN}5Q9+#De40FKj=QJTvW%*kNN}))) z1wL-JgpX#>#Z)E;A9q3;;kvP3Tn)a#%wT*N3&~%mLJ(~1Rv98_$oRcDjKmshhe@3h z9ElqD!&9IQH==RI9&@-z;q5rbz)Ib1aDS_8&Vp7&uK_sHk)y$&TXm6Bz7O_+)k*|i z5QQ2N)Vi{9tepUE8eTimfDaB%IGY7H zcou1g;P(2fU>QW=Pr1BjVQgKFiyeXbN&+|YAjBi7y*OwsbJ607zz(w_h)G~C7%aoe z%O=H7LoZM6q~pzek^w{`7%_&$!KvPHSJuI1i9U9T>>$b4q4TwXFhOr2!I?d5B>Lw@eobsel!W`XDo34-gPCi<>9ms0&IS>3Fml5*^imE2GriZPTTt)ve{F%Zo}c&Ti%DVrvRWXX$qza>37yk7*-Hq(P7}Ar2^R0| z%RpqhQHdL4%dEZ5VSE5#r@W^^(Uh#)Lx71H`#9Bi=V}t~lfQzyIuKF{N+2oKbY-}} zl4RBYARFhW6m9?nPv$iu6=c(z*&KkfUGAt0C=+wssLc@1gYvm{&>~Cb2%>s5Xiu;- z;hA$*L3HB7d;-*m_s18AfV)TMR>5^?)w&3-cx#DJzVl18{s?{RW|baW!2R`EB?AFO zhspl~)ZueGQ1Bw04$wpL}XF`WA_KEgRuiUDO)%+We{RO5{&D@43nGO|=0_xeqIi^F@Eomu_`puJ_ z?8(5Yoap~Ya;No^WEdoY!>WByr-6t@e}lV5JiM;Exbh#YIB5&q+JCF0Pd%bpTE|sm z&xR7aF_h!+yRn(aJ$iRRMJ9c`uLUY>^WJ?g)M>nflRf1zuv|_&FDG>YUi`!7AB~rd zF+jt(IM)Zx@oS-88ez8ix3NGJGhd{%0|-i}YCiz&SH5&WX`Pne1#kSA?|v&LfE7>7 z-GGd2>djpM{q4~T?S zK~X5L`@ST4l5Q!8Mus|Am)ceR#T5g?fkP83xuQ(2B_I=ine%|3ggM81Lm7*{P8d$F ztkMwN?ENt&51t8xmGHg>kNza*x1J!>dN_U#X#0S9SJ81dFH8Uswb(cSJdU#sXB2g( z#ovRE6~1Ah1{6j)2vB)@yar^oqs(Ri)JuFKbsAwSdgtUC@lHQSKC=`y*Sy@{D9ESC z%b*?o0ui_$;3;4Ag|JiDoRvfekR8#d+^@)ma&T(!A-EyXXVTuoKJd^37X^5o^Fl1m zQim3D2*&$6X$Lu1e)CJb1Q}HS_$k7>k&d;+<-1ifU8Z$KR&z88$20-zOf%aHOGhOL zLgn7W%kTxZD}4ue`6AN;22qeM*PK)|S~_xE`2v8UO4(bh_WYyJL8y_4BZ#temgND1 zP-91f)C%d>9Nda=U6YWjh4t-#B+`eOQ~>34?8E@5;ot_#Z-DmQp+=`DT4#b}2*Ug< zQt5ZGhd`5x+WG(_7=?6|Wnr9rWx0anIemJ4A&?64o^9x2*Mw=&Zd9<(}11p0i#uS!&eNWZ2AGzkVOT-+wwFQ*fHRx z&J&5?LK`?{fMSIyh5#HlG^@e{AqhusOO?D`36eevfE2c3gLYDk1!lt9w(4@)(gt2L z)|1DZ;0jlCS24$-&`FuuCs30a8OjGY!FL>BDr9T+gQm}an{o>$I8r(pnskYG;VELC9fRD27 zB;W24BfNXnV{!oo%fasX7ISfwaRhrSy=90fN(xl?xFRIW?$*3j`4WomgK zj^uCep$?j84%a{8oqBU^)^bnqlS9<80@0GTdbSTq(u84|hCE_8YB#|#bxF@9!^io- zRfsw47hURDbIoZ&{YpkRw^1Vvd1XG(I_mZ@0J7uz^`M%2A%_OMy(#0BH3UII`VQHT zY`)tqGPxT0vgVIuimYq;&@PH>=E=o^Q`pzbTZI-m4>hNIpHHjwazhY7yubQl5$J*p zyv_pa%%7_+7k=Nn4G)XV?hvGW;8I%m+jA0x+J}SGfpgRHvdD|`dg|Em>+pYWS^H(` znF{ma$v62oGkt=uuLVerzr2<$ZZ`j21@{I#p4US|2|($h?~DC|6gQ~D6(P)7O$<_j zqm#P;*_HBR0oHXYFau0&sB|2nSv9tP0&b`pD^U>o7aX^%Iq(chKFJ-333cF0yi7pp z?hzMchqFuu#QzmTywdr9((p8OyXxb$xwll|eF^aA1rY$WtQQDM zfW>@(Vid0vB*s(bGk$)cJPrH+aY~%y)HA16GkQEI{6V2S)c4$uHB2Fa!d_Qm-E~ z;3Wm{uRN`@PD!h;%eIm@lhQ@|$>e-a`x7Z8+ zSdR7>KW8b9beCu;Z-~)gv0rvyCn&+^iu-wp^`NA$NdzFU$arNZ?2q>AFabz@hJ?rj zrG%VTVqo=^cX8K>A%UX0*7f|8-A7;C9!FS02CRy}t)V?coQgMpnHw6(G(M8w7ouek znFU+Ur*eMVfOt+(BZ;#7m=f8`B|dQ017*RSQmk434#3}A7k--qj#|mBgvu?oGw?d` z4V;>&=YXTe{S9GVmF0H;URIGXb!GD%uD(nD3r`6^7bypS^As|Vf1Er5p-x;jmWeX; zAWbU)x~NLy$Xq8}c~|Dky$3HkZR{fN{wH)UP+`OXk?ML@&-mNDNO%>Qj8@c5;4Tc# z;y~S{1QBfuWRUh)zBW|mm^bkH@MFsXt|(x;Y#&&Th7#tI^)o<;=@LO?VB?NC5a1Bc z%9=?|$2E`J#C!3wPl%x6r{j99yOld+bE@skf_N8k9wN}w{jLU7%6Hd&{aVew#1Q+i40-x$+YXAPK#A!SK?*=R z{`38&FOVl#=h9eJ;RT{CzDAI>4b81YL0K?2l&%4ya)a*e+kpDc9H{gpvkvt6j~PCZ z09#k2ZK4=D4pF-8!(2dHr_Bv(1Xmph3G}V~ar*p0`Ug96VQR<;kRthI6%NG-x0xKe z0QYRkw1)I)@NMAVaCfRKz7|DGcEuW&0Mb2~QQT!9(5JPKrSYy9rVJc4uOeN|fIJC> zQmf$^@h=UB+yKoTHPS9nSz{gmsXps<#572}R8CHw0`vTg7hryDir^hXTFr=9$Z_?u zyp2I%4)^`Aj_ezGdUMGxYF4-4vU4t!r#p*W+@wQ&Eoz6_i#Ilnu$2zj#OV-h)vVoMn_B&0>HF=7*+oN018)FF7bFJDHiP(_ z`LK7^<6|6n)TOQfp=;E`JxP`dF_@RBKGopr!07dIB?XwOIQyOe*qIh{cN73S{;a1Q zj(kbg#v%C{l#4harUQQjw=-l0@^?=U2_39{Nt>+iz(~J|ea;1Y!@7 z#*70dZ(tJ=$~tux$u!W5`CC>!9I6kY?h;)6EUhX?sVb-Ra^a5FKZW^+s`R69n>zo> zyReZP`v9P&ZdB(Byob`)U^b2?Tkv!mb>frdrgmb&&8XBL90Ql2?@kc{goTNPpVG|l zTI57kDBzQ)QCB=B)5G6nQlSd3!_ zzyOrcQJ`FpTu_JluKU+_pkb=W7q*ADBc{~mY z@ZCl>mRS)eos%LHe6`M|F7JS>>q1|SBow?-e%~T}+>v3KBE=`)4T2@;&pj3vE-3L* zI8iO%u@S426z!j&C_Db%0M#VWZX8XIspB2*^{z<3gY;r48(*>!Zk*4wT?+wFEDK^N z0p?oY9D3C=`xp}JDY}M_1$VGl1F?(}AjvV;SIz&)OTKvW_DunlJU_~pBLgKQliz;* z5R@y}f883QLh5HQ68lO8LcwU&XiX&)<4zDAtKm$D417X>gu6Xedzf1;fP6O_pWjXY zfy+6zpB+si2!bslFd!5qxGdvxo*h^QWJ^0;$Lts4t*HN)uP?xSd5$H1B)Fq%WUCMW zDxV*EB_gO|RIxJe1C?Z$InxQ?n1oLZB8n|=1o`(NA{p9tmli{Fgofl`Ow3B2;Ig}H z6N9JXFlC4nJLp#>-J3PsI8_y@d8WfEM1YPyPU}|)aI>ft*_-@>a~GA78`vtQmN(hQ z?fC~CkGb8>5P$#&Lw((R{kn|Jr zx8ZBnY&rBly1y>}r~4~h?|*lH{a2DiUH?at$i;WZ)gh7Jx7SPVvD)A@Qm{{Ghu<1W ziF*l~Z$>^ie<&|`-QlW7n;-3Kx%TM(pC%7P-R`*lA?zgjMl|}SdDS1!laJo}(6%r2 zd{eq_#his-WcC9l4=+V*&9aP}Zk^R&_E0(KfX3-ljFHqiBZoJ`^BWYDm6eZqb55?a zIA2rtdc^WT6EpVCZq4D2H)*MtHLQ=4&M7~aQJe`&x?r_XxZ9g$|4^(tLq0)4XYSBb z?g6OrMC;VOLWCvVom`ns7%kjoZtmA>too`lJ9a64%BtyPnKt@MbC}yj%i`i^2g3SI zw;-Rsdb3JZ)R24i%j1K~oJ8)Td|9+q{xRr_R@aEi$QfgPvON#CBq4j9|9 zd4TYy(PnJ~LfN?!r*Su7tnQGv3rSfm&rbWxeN4mcEx5Ph8JWy9Ad|}*b(`0JgQ_S3{d)J?Nw?-T^(%alzWiO;_wJtm@c=WV#c~$*` z*aFZPso)2Ls!L%hwq-!g+%cCsN-y3RwKuzQe06nYk3{mx<2ODRT1cGo#T*F#h_-pC zDIzuXveT+6T+!9*`&nfUZ~x-Q)Z90k&Wnh_4@VbY38^f7di+^|yzQ_h%KFxRXGTrD z;x+n<$JbNn`FFDh+K=AoD%DMh>x=pL)Q`&_YJ0ExW5jsDBs=H@ZEN{> zgN@|kWs7s3IQ}uow)UT1uG)UVKAVkRCVABIa@gxH8(kvbX-y^X^m@FRbn3>JXdeFg zhO07SKgZ(MGe;ZVte4iHhEvvhx^J&42tnibtGuvss@>|b=>BPH;3Q%4ys)LqZ`JcxUi1t*_%U3rk2$aVHdk>~qQ9<#^yM{)Yb89oIL`42 zQ2x;r8`c|9ff>cN-b=^t9wo*hFR{P7>>c5MI@ohq4{@p6plz4e+^U6T&E<;l3Y#X+ z<;xE%7QBf2+zyFgv%HF0Et6yVu% zk={#_e>x&lavc5ko>*;t;2Fmg)|gh<;@DoMR;3wsGJL_J@$SxCV)5${Y)aisPl~9- zdD6~K@wnr!IDPgHo85#r&p7qoxmKO~@ND%$>DzPogBeX}JdOGukJ@&jh_ccN#mVEUk%^ti3VWrJZm<9H~3#7SjGD z_!bSbrEdN{`(O?Q(J4NP)keNphiF(PlcXj4g2i+4k8uO&0kL@jDoy&AMJ2Q@FxM z=aQtyZG5$Lo!3XJ)x`K3i#j%Wj>_x_Hi%O&S0*{t<|-vwC9q>}b!vR*i17YWmTCbBc2GY_d3vL&zfPIT@_b7jGv-KCP@EC1b+-G z`1Mm~JB;0bp$J&LSjs`_%iGVxcz&dhC_&rQ^MDrC)~R;p zf&KR8W#;qt02%dqa z%9rIf-QRghYxhz>fkbEJe)%Rs+JRiG)g{V5rztWW|9ynGP%%{;hcnZdQ+?mzH+fXL zVndYTZk(w>`Agi%r;{ZOYlFF|&yDH^MF&we$-2~U+a*NNE4gBmA_orZ)rjg?9+4u( zI*f|R9DSYk>F%@2GOJEooIg3IrjSVt-ieVJNq21+yz76C`LSd3prrD* z=LbAoMs2VUdRE^CS_kA;UNxWYc$9z0*O%KXA~;ROD)t`yF|U}ZGFQ5J#Hwzc^_>|f zVf?NZE#lE<3UY&MBjU>jP5j>D(Id(a&(9M24T<0Q!~e{~JE_ zcXjG)$yYvMg1rRtfCF|KeW(;m)V@eN<9DZ!FE0j7Ev0JomqiInM2iNS zZ%tO`O{(qTb&!mPj-I3o3r8X@9Uq^WWX5kUa*wE5$vvQU$}w8?=3-L#CI+8>c(CDz zmqe&e`H$Y)&A5-@BpavH4AHnOP6mF1h^D-c0zY%Bh65fsX@uR5??_GX{o{Az6H z^mK<0CSAs*lUI2ncjPQT&MEG%QC-JF-a(v0>+GsN+157K$iDm?$&*C~zwGb8h7NvN z{ic_`Puw46KnXGsNxeo?wHJ?+JHR}8%|fgGK~@bW`ZL`Rr>;1R^ZYU~)PIX-#{Tw3 z8fAYC*-MNRGSHEFYeL=Z%Uv7R$sM4FYrsKJpj*Do9?nm_XkoZzY>*#u_nvXq7zL&ZiRndWGNgo{4<1NJp%t6-Hz3$HK=)205mm}Kqi=S1mZV+BV88~#7`+j?{vuxq*ule?pXVs4# z6t7kNed%>Na%P=$v*RwY8Lrpi$o5a;J{HbwPwTjI?boga^oVadOx2K8KmP4PKcuWZ zduCQ{&gizzlT6YdR!mL=3h73UoqUB(RQ1lg4`N1nY`#1!x{jVxNX-l@xUI;dj6D}RCpXepm z%a)Ft`2R76xJW;}eR{@XPwB{#@NV+Pu=QNC-4Wzady)K%_+c^1a?Uw2(Y}sK%%dMj$cQVh;=avnp z{(N&{-36OJgsKnK|0FW`&INq_ngG}Vun#31q*UGH_w`x-FfYFZAYcAaEyt+g5$-)ug%RLp|eRThQv_%}+A_8sk z2wi#?trmk;dxY)}NBhH{SafL=y7b7M%($ zI$UF=Tr;?(X7E7G;D(yPbv1))Y6g$g42sqaZmO}8ud$M=v07JSB~oK0Rb#cc#%c#i zaTm#5g!F4G>DOA)FCmiq8j|}?lDja;eFG_P2PtnmDNl%$w~nMJMp6_fDLz3bMWL5v zNWWBS2AxBT%2-Z>-)-qXQcK9GeLqsK{zy$6PgNqP8vaO)nMh@jQ%A|ExF4x96R95L z|LS}GHA2d;SZVp_jksnQ;opBx9Tr~}gh4%`r54fh717dwuxUhS)grXMASxRWlm>+KXM}VeBDE2rP>aa@ ziijeoo+PJcPNX`Hr#iw%aw_*Lf*p=t-bnhTT{GwwT9nLk@?bd`vYh%@PLnJr1D2By z%Zbc#(q%aXu$(MePK_+5kpJ#`{xt$vioiO^-Y~+y{|^7Dma~jP_dh}l6Vm^vu#%{; z68%4`qC7T`Cr)zTMsk-RDaw-ac9ZfXNO@aHqITL_eTx)Bi+0xxO4STX)C|hk3?8hp z+ErsETQm4~&7dL>WNWOB)mSOjSRJU5tP1{X#>tB1bS$*!WN496XpvcHkwIvYa%hoG zXwjw6BCF7%(9k0L&?4*5q6?wN0~zN!+dlqovu8Pxez#%BsgvWW)t?atjfjvZ=>8{Y zi*U5XJ+#FGbm=3s+C8*dG`c?u?GJzMqf6t^rH}us@A=mV|2aU415y9;0Hu1Pez#fE z+R|Z%$f;qlqn{C#^$3Fn1WopLBAZX;3F)tx6oOEj>_1MY_|EdE-5P`cIGx0a|Lt@( zpv+uuIsRWAjuObU{o`<2)~qQGT@xrY-&-iQX3ZaKk8=1f8Fn|X?DD^FxIFjQ71^G< zGT-mXu-0w4b9ddI@iijqwL<^D{A=w25h>qx@nl#YpZ~Eu`u|y;WTF4PJnIEM`Tuiu zcmj94Pw3yPGi16Y{Iux0E-0ZBz3b%fPevA##K`;K|J0rykz;e5FwSvjDv(nhJl^C0 z4nImPV;45ojNYSi_`XL4i`F?^>%2@17lP%xrz27@$loF?Sj^QuFBsG_YlPPSdHCxQzMD~jKPVE-##fJ}Mv@7=FU|&yXt;6LPmR%4`?tdPAZ5KarofX{oKVK|hn8H897+U>*7<&_VsN1&x|L%5`%665ataWuo5|VwL zN>RjABm0ts5R%<6Qz?p~vL(wTA$wV~P9@1YWz9Mv>%?G;G5i0R?&tYE_y7Jcujkb( zE?mBy-}5}q?KnQi`^e^O=|=Q7~Y^woHfi7SJ$DOF+D%!lV0h;s2dv&C?$(=#2o?%L`lBah7dq z5BR*jK-Bxj$PQLTjNvQ?;dcuVS~E*kHSBCmEPbAZ^6?2NH2=!6Gy|?0@7=_CFGEb9 zU1|pup6(p$d?cwKSyhcGBxz&AG4FMuSK8|eGIE719fPq7gj5gk<>-lze@RI=SlJ9kF zaa1>!uPUBC&&eN#L2`Tq$i6qg`=bfhqCEjpSAsiCC70d|nU8H|BdHacvhX9r+WNN? zqpE87`%54alRZQG)3Sh&S)0y4lSa)W$r<$>9}My5_3A@jYx;B6C@TFdojkjt+Wg^R zdVaVI+j6i;I|B3%(66O;fMWOy-t`gvC!XsGtUUI7zX()11ACDYiebMsgpQzoTF=+5 z0i>Ti{PPt~z#RO<+F;jb>+-mD?o3o}7IQRGe}Q%0V6h*%Vktn2I^H>^#^Vli&?j#6NbwlD@JFjxr7Sr{yWJe4bMxM^DNp9cX} z_wL_jp!t8#!1VS1oPqy4SlyL>gVl8n%C@fj@(&0Ipfx5*TFju&Q z-d)nOr%D1%-c_=<@AZWP2e+EC?l<1C*-;+z_fw()nPSKZH(WZ<)&+GZF=Se)k;wXC z_KA)KsNriDu;!dO^NM6j$=c-hvQ@Y*dEi}G)OvFLOU1dP!cxAVbM z@xTmXOnij$$TN$3nV>1lH{A_7CUV38@W;}0pj4mdgIivxPgK<6hxw?PvaBquhn=_w zqzjIZi{68DU#Ea|6UYXV-lhxym!#1UsLXe*tr2Sbbz#quRWMGT24amR@lc7xx&Db< zDRMqyk#ZKLinaSl`i_KvnTT;lEvRJ%Hi`hY6Gn_Sbg(U<*iG1tzY>?^c^&##?>b3>t^M;LWxr0f&aa`KC)JqP7`5M1{g zkWm|C$hjQy1U`EZ34cPbGF544P-r~Y@dw7*_?%8Eucb{YD^atM=xwj@Q5=es&sr$2 zM&L`;XX@MU(-pfq797Q~_#O#qCkYa67)fATbsEh#)L{7s5JCBmczw#D5rQDqGGkx^ zofOu{_2y+H_m^dFFvsV$u(tuy707zKfey-5tvVsQhN9e2+h8USD0!Mdy*Gmy1K!hy z3ZYMDAAG-boISk}wYqvS4B+u@f;_##S* z(Nz)Fy+uWiJ(ymPBSDFw+tCl^@(W!3plE8BV(pqPUUKyE4TG)lEa3i=pz}?9k{0j1O^q$p1|ARZAP+zZ)d#PJXaa8rI3O94)# zO6*_@jLXu8a?s(T%nV{7JJVcA2hxYeih7zs*ob$c)`MubD=Qshw)$(Ad0?E;!oOB1 zrruYt7wJxJoLx+JHi;#nbQ5aJGCHnw93C^Ht>tg-{%RAw}oSCpPYj0d}} zmvnGm?;Xr{Zo@oBdo}xmqC>^|9*E5_T|8FTmPfVPpagqY&;S{lEH=Us;1DQWF-S4W zgv}tnyyRoUBTc0H@G?Itto;tmlteU!pOfvx%@`xRpnmz%?(bf}a3snXrSsCiXgmen zyYkbZ>ZH^xR=`SuNB~}g;Fcz2)ffkU)SZuw18_Y$(t84dQexUC>8v(_m z3@0;q^19YCdEc`3L8ZJOp|3hKHQxcJXvNjcm6wcnlU4}L3n~Z#m72DXJ0LYFsm(Ev z>}*o@9r9ao6f%5kmaG5(J~TI_`|TB|fE&D4BLu+6s*y6u8Dv1r;(I#2eB(+D2TTUj z{Z|+V8D&U1OyCyye-z8$Dt0->EkFS_(wp|gH<;Iv#;J)huv!Ex{=5u}%J|svQrUvw z`qo3mveQLLwNN5@RHkg2k=?>?{RK*pvLCv^7bhOIwo#29HFv|uE*v416l2FPodQVP ze0}(+Ykjw!YBV;|9eEE*(b>1C`NoDFc4m9G(i4u=*h*(`55-~edg2sl-FVkDT|}s` z>SPx8{FIgoe4$aJG_nf}#c!A$OGhyirZ~;exNlqF&BoI4qrBWXZ&HT#TCa77RnpGX z@)cONakfded z&%wTQwv}p{*WopB64wg~mCnuXP`0$ff&_buP^mUpV5R^Q1ZDWLcaWN=Q$>N4c3RKl zBG^^5v=&d5ttOYOUS8|X_$db|oN*%t($E)6=*8<`Jm-%W0NUjC&9N2g8#T2*LReI@&Yt76h;LPKICd0=)z?3%deP zfXgR(>n0h=p9|waYWBRy!xwZS)ykQm$srHs0RT0C^{fr_PCEUKux0pO#T`#LHhrxG z_B)+cBqJLqmb%vtN;{5eeO@+%huPsXp=sqzsK)(V5s8FGEz}pnYof=bAk|lDF<=k7 z&w%~i7MdnWQaSZN#;yIM(L3&?nd_8Rc3HW0XlesDd7+8Fa0vjf5j(#@F7n)&`>?KH zFB2h)!lzFiq@&|hCQ!RGjZ#m&z}4kPG(pYA#m^o!ko=SOt4!^}A7^Opg!Od;-A zZ%r&DZHAy*Ilzys!9tN*4T+neo_%h{RRv{a-2(0_`q!6p@Rp<^rDsU{;Uf#5g{wbW{`1{pYx%X^;pRKNd%NU`z)vQ zndNzAJ>RW`mF!MRgM`X~!}Da&FxfX~K?e-g_XGNrww3%R?|EHuZ=I4NjUjum{wGv}l0#^v z@|v<-;0_kB+88)0lQgt~pQ4JpUFcf(T>(y}4@J}odtr-3!`(sWr2Qj??@21{Z|p^{ zzyg9nB4B={Y9>IQ*MN5@SPI*A-5qSCC}H@D!J$N2JW@2W{a5o@GdQtY-W->K9fv6A zy~PDyHq;AFDMkY|8PQNX)~x7LLtt)hXhZ`P%yz`*DwGGOT+!dI%hG1 z_Md5fz)f`bEB(8>Ro(3gaT-MNLBwGbHF#fs8%P2(N)bE;+3%UUycD*lvhM(?>RSRS z!F{&51b$dUUo7ZAVCF)9pA{a0|0g zI<}9O@zma_01Iv+TkKw3NBb|%JS4F<8B{TND|uN}g9t2flobIm;?EADz_h)NN`v(- zMcl*`W@}?&6JTIc)E6Q9&RQ>qqFCri53T-{ui~o%w5lbW8a~K9n?pyzAvBWDULA7J zSXW!zfW}O|2n%U+NgoQti)R<(!A7=Y-_u|8coM(DvBlB|tVm4pelSaXy(F3_dH`~RH_b1uu+opc8r`DL z%@bt)B|yL{C~>VeY*`IG!6XU_(5z>;-}W(*mwuQ#-^UcT3|{+-IZyc#qX-p$tCK<@ z&suYNmkh`sJ+P6`^T&HesgpDXqhBJ059o@`cKtek&6HJ2Jt%=R-1^nA zU=3XoT4}b!F$e0X67cj=*z*Qn8iH90sIjI#F|z9j)mgC8@cAyTL1jnP&@Sjo@9&LJ zDsuXGjW@h*96kx=g#M5wWT;cu7lMEDS>5k}M3oY5dnN1nG4CEZRatY}(3+@t*j6hz z`Hs9~yGh9$oJ1@_TZNJAB8&V5tK1Mf5Hj$Ux+CCx_T>8)fQlt+y%B;b(Xt&c_Y!BQ z^>8c-^IT*30+i~WNIRnjRzi5%52nRuk!uCnNmr}j7$;%nk_$5LAw!NHa1q*G!@m_j zG7E=LM-V`QF>oaD#^UUD4;t|g$cnL=6#<#B0L?*{cfwX<;&wqsQS%J$D^f^h%NDSc zWNpaQ>RUB=0jk>I;sKC|#(OuyuYmt1l6PR*?~7n06V};xrXC$Dnz-yA@h$0|_mRoa zmq5r}HIPCiZL0U03e8p@#VKTw`;%Sr^mYSHL(*y#WXaO{w!qv3{Q+##)X`c=m=Gu1 zDCIcA^hI&`@MPQF!La3uafW@AcyIdbW&I>gkxw&78j8d=_bY{gu)XP?8a%B?kpP?G z;^Ha-@G0~*U*H$yC^_@En6kktC*iPJVHj`&sGVs}ZBz0}QnmkVMHVszl@$|k>X)ar z!&tAP-vwx64x9U#PHhxa9x*rqnN-!3w~$HII)5I1T#Cm1*f?7i&|2XN$vUX*k?SD~c0l$qEpx~^x<&igPJ-H~fdICWMlO%=Lw z`uwl3wV~9l?^9sr{P1RBcQQ)(941N&L<|T~Pam-R$kp;o) z$4Q5P16Jpadikv880GS9sPlbqsVf;um@oBi5FR~42<@>t55>WwgEHgc#RB~U_&afS zdAlar{H7zZu}oF$!uPSgWRvrC-44b28!9I ztLRH63(h$g!U@S`9xT}@l(bGO~8Q9yc)iG0WpC?`Yq6%-U<}7T2 zU-cx+!Sy)p34Rm~)}fbd^<`jbN3EQOlf-d?9Lx@(3NdS#9nukXusIwnGSqGdfx;A5A$4cvqH-YpVE}g_yr$}OlkOG{sgUsBz zgxte3`GVKPZigud<%q_^u~ie(2XkOG5|x2Hzr z=}iA=m-GC}czfr13C)#LdD)~eRR8sbG5HtGp|I!laitSzNzo^ULL&;*ORmMta+6aw ztr&o(B7MyrnCGtZ{7CQ?4Aa9jpxaP*=VczBw5|HPKGfO`$Cp6I**IB`%4ig##UH+3 zL_(h3E?+-WBiWjF_<`iSFD`NLsCn@w*z`3qOF}RXEWS{K^YaYKhvV?TL`XluPA4kh zCV)PBgo4xO^xnC@qRl~#>G^Dm=eFM}KMV9(A!qf+tyr(;x=0yrL9X>MAYVr2XfOb} zGnI@@l>Abni4453-q3>i-DmjKv#A|mcfFVQKBV{F*>B>`JHj&CoKsuK)?2js7!&Je zLM3=p@V|JnmT*U*dAeP2MAQuQKtuD^NO7>>c{lpP;hJ54OxqX+!*Zee5+tCO*Tuut zZu8jo13dSPpYvHL2C%i@E_7M6abnL`q`8sG6djv89RLhN%i%2=pGgU(tx4ox!1kDq zTV@>Szw%V^ZXCw#;)l#`NE7kLhQWq$JMSReanP+E=5UH#_VR{HZ}v&yD3%a63ndj0C}fBCf6q@DzHD+-}=^Y%uhsZm=D;9SfXNpOIuQrB@jYzNMw zx_sg9@>$&M_#FqUWp@&|=Lb8*=384RA{Q5JIv?$UJTr!WsQFs&!ysoKX;@|Z#}(Yd zcs+Xh1&)EZp9OcOqfE$#F%M5T1g(r(Qv3wM&`fM?0v*-*V^J2oQoElV6$Iy-34fF9 zen{Mt4*1E)-dmyBK{cY_LU_9^ZRYGv_Id8z&|1vv5BNI{h(1fdm+_<0;1Wk%g*438`#)&mfM;bilOjv5ph5&^pqHlb~YO|n(T&psAX zM{%aDkg=BFBu1clS<-Iu7dIgqNHGf6QEe ze$RgJnR@qi?yv!@@>g+hAhNEm+;irFAMct$CqG*q8)wuYQ*vPp&ERX`6t5AT`OCBv zqY~YxsQ$Ta7#f@ga#`(*aK?z1?}hc=(MbbNdqP3LtbwGu^&OB@Cu_3VPUJc*AM9`-LMql6eHgF1Zu1YK=B-0bET6p%8a7ca$N1VrVV*UbxpxJB- zyQ)-BNf~uPv)T#gXGuigPjvV@-=KfbRa(F`7!o@i+@CK5?zQn zMdvR>hp=`N5Qo_E#LpCw_8*QK%dDtlYn(uR?u*Jlgd<@$P^@TB2A^`oPN3rCms+&R z!}eI6-!8iYa-ilqad0W^MebGxP;S|Bs|Bx(TEx|o4Yny)b@N^ugnB4yc5AV$L^xHX z0aH>LD((bVtmI-|aqm9POJLU&jlD95xBf;-NrqW%;$0X!i_&mol;(+mJ(?5rL;lQ~ zO0cAH{#HI_w}#?=$TgGMISY@So-27fxo&1O)!mmMUgPYgoH2-fH#?iG$^78s+Cmoz zvP3`AydZ^rU6j0%s4&SgDfGdv{uBCDqIUKe!;{fo0M{&HL%~kSQ3671OC$kMiNu=u zqcDXC_8AHE-mk6%&~X@b)sm+u)~5D0>B``AwUme=xGFdf51)cp^(j%^0#Ed!&szhM zx7Pv(Hwa4TCsDXTkXMb%t^vlZ{w|>vk`ycXa*tvq>QqAYW{_R;^=3j4AE^Fe&j(x9 zA#%MmbZm5gFLdmB>jve)74{+7+Jv~-DCmdf7n^}mqRgp+yVTgorO1E4=zE}GrbNj* za3Ogs(7PYXY6QdvuO!dqYvT8>pW|74U(a|LI4P~irX=G&F(6A1`JFd0CyK;+Pn8{O z^r%O}LxtU&z}rjH#2CV%0ly*#F8$>2-{`5^#JJg4!aHD%wJoY z#lhVni*bb`aTC1+5}TTDUWQ$pl*5mNU$OGr^ANJ#rlqlv;#?+y?d{E1AfB@5TwS|n zNo%*=^*5|;_{qd+xa~xtHH(iLNddC3n2r{|KP93;Je#m^Xa-qgOEw@KhOOuGfJXQO zs*&SvWA;~Mv1~zg@yrWA{7pCS2W=cKPtV8tliPIqiixu;Y`3IoLo9FLoe$qQ%LkpR zx27;l2d@Q#k~NkIP8DZdwIP@tiIj<4e}Gxo`tHKwW7sB-jk_iQ=d1d%T_fxm5wEGj zMhJ7-!rQh0_VZQq(3Nexd2mop5DUhI&%Jpf3o_ukz1fL&X(Zh{zcDFHDb=vYKEzsA)DSD?*;053L6VOerik^4)CtsyWkL!{a{qksC|h ztbf4;4|{xs-3WL3QhXD=2AovF?eFx#Q$x9DUe60iL`JCQL%ELiI}LI^`rt+%>L6@5 zz>4*ja_l4IYOm1mUo6vaY_Gig=`iIKA`<0iL4v9wz-c{np{NW(2b-Ibg6j|&ywRU1 z-3kG{;nuKOaqy9PEG!~`xlZK_ZWae;>1?MD#&!*r>dDO@y~L#)(t3H}?kuAqC3LOj z*?CwVERve6?ACg<+`3;4?glef%scU37NUf?roEGo1jCS;px`0}qHpwPq+& z8o_0kUJzvrJ%m)*VF2zr>l<;!I5@>!Xz!?XhIjaMT6Dw&NUhaAm(^Ct*%7Wssgz<5 z2y60(%Tid4)L1aam(G6Z3NT% zc$2gctV^Q}?}(;ZJhniGAfGtS34w(52VJGRNJkqm31^JFOP6B7$jNC(y}*bD-VsHV z!6BCwntd%7oL&tXR;1Gir5&r*e*nke$}_UWT5sitOHMCvGc5-(8=IS*}}slM9wDVw^kxHX%X&z;L;?(IC%+HX#OPxO;E40DZ`yE%XukmwoDwA*?-zEAE@-Gif{F8=z63s|WhVM}p z4mdx+B65TLddO+uR9AVH6^BLUQdaV1#bLI0cQ5D~fvG{|RSZl<&lCn#pYkm!EJrrt zHr>pC*h1q)BOq!jlUmW0yGrZcbe#8oc2mG^yEhi{Vs2P2Z^Y<%8(?*J>4uSdz7bANv6T ztI(x39={7wR#{rK79tJ%5&ONkUkk)|#Ie3ZmJlYhV0|*{jPasviF`z;KZI&EH-FFa zbZYzg58k^IGQfqqpf$-p25}=&>nU&{sbu>69gi@js8F811UE>jwq+0?bl1lcK1;zA z-s_)x3|FgTL=y$~irBIz?+UCOA8OAd(sC7I`c!XdsOcXk@Qyjnp?_Po$< zxxWTbtjqik12L@2a9Ili$#1e@sSg`nBJ-^DNzM9Y_IajkQ!Si3yInP&!(JT15@;|y zT~$v!M~uQSbenx4Bwt&zehJut72I==%3+A4^B2MW_B_I`OgjSH?XI257*&+TCqR2sBw|7I#(Hgrky&oJIqazC2NilUuNf{pR zbf~5@b?#D=6H0R%TRmhjpYppG)#~(kA>e#jcyA$P9eDn`o2OKvfX0Yl_Y0gIHeL`$ zM}=Jv)WZOeN$@Pw9%wj2uwZPyqE?78PkNHh1iLKF0DnN`hWWh{lO%Ze&R#4mO$^P2 zyBM#GnjgTEs&zI72ny-$MPP3Xi&q*#0lm>H) z!OUG^w~oi{CP4$ocT*gIBUn$1CGdN;k4_kZJ2XyZ=^3v|*KA>rG$>Ch6cS(>ik1QZ zQX`~dHyqe?i#@&JM(H7#6$9(saLYD0ACZ?rd0y{e0`~^mphV{a_Tss*BJNJ?gt(hkbsUDmz zhZHg(Q6x``n)D0KEChFRJXL*a8n? zT3G8RGHT1Eh(4!I6VG3^T!?OTDOr#qnp_p)WjKReoHEsfFMz9Z9ejO*;v&026l3q0 z^@C+j_xj?=GH7@3*b43iu>>L)LI+uFkKhTaiQ9Pvq9;r~;l^b~PS0qii9Gnz(5HS- zO>!eYt)rp;x*MVgWs{dK39w-<`-;7qWSyX!ddE@t-AV^%S6R2kVrB<`^8;q%mVr1F zb!7KXI-iCn^FkKld_Yt_u;5CZZMzF!0(bTtRD}-bhD1%o?MCu@eo9n-ORRv ze?+IvtUbKR86{TZH@b&?k-$;gtH;v=z4s6TS5PtDc**%hSCE_)m~=H!8~hK3KM=Lp z%|RCJ$xQ3>G!~xoyGCd22@`~Q*tjUI6{5j+A+kOhp6Jg#7eo}O-UGg!yynWVKXqdz-%^bjo=cH)%zEZUTo}Zs{$Sf9meb1?}|HhE|fzY z%s&ma!P0|)M&aSB%fq8;ynwJsT{Z-S%S>VEUU(}6MLrsxxZs z;CQa``iCLDxU%N;Jz9lgW+S?TpaPL$4{g|)sVQULu`<>q5mWt92Zk(r;tzDhW~` zL4i|HJsha`68a>7`uvpT-SiCKBcI^HhPTm0`Z|^w%m7qhFAldn1bcWeyW@?fP-P{k28L!|z>|3}NM?fkp_P0(_ zP^KP5)D2cr<%Jp(+bOVy;^fgu{z#4nZKnUHsvWgnWHC)y6RztfATh7!P}euHg2A zg$IwX`p;8a4H3D5W^4u!cQk%!!WWg+>&>$|NfwQtRbiE>|C=9fCkKz%-5SYR&CUM1 z8=EwQ_Zh(0shQOV*L-F);RMpAGuNd?vlK3|jNM0IT}b6DgWRyfX?7KsYR&zj5hoy2taUJ!`r_QUb#^&SVZ)xS z1mfX1Q@M#1A(+Ae?uZ#ApGkwf40*2oG4+57y!Nk)#i6XJA*`{N0#u!6BnJ-?L-k(; zVpw0n(KHs(6%2Pt$48@b15;+3b)3oyaQ7`6(XINhR$GO&yKUi5)Fy~F+CG3!7*qZPabB>@`K z39tzbk;`nwL~r8`Dv*}N;3IK-IF^cpWx+Cq1To``BZEMFjW}J3m8dRy>A>xK zI{XI-C`BxbQtZN!3LE%XI(7l*`BjP)%3%+}4kxk^KDX$-zc!WJ;1ool7c{yNyb)Pn zWhHLWOn5qrQ@?snvm24@l0NJU&gkjW`tU_CSqpxyYlhiJKoryu^M!E~`b+yFUgY4K z-ciZsaKs+-FMWsTPx1@tFWA>)0nK~(7#_8pmm>b5u3qSv9mHri3U_2hAQ6!=w)L=e4B+JbZRwgfu4(;V5%+u=B<_9OM;2sw z-jBp>{9el6SlvzlFRw}P#B6f4q81h=NyFL)s=`=PzY#33%I4#eKo24`Crq)M+lx=1 z2<5&hKgupU1W0QbXL1Zi;)b^uKo-v|Qz5?EEMX-Ci;dJ*<;$GDVE_AY2U@v0pUU&a z*0koFLi8(t_B)AR4Qn)Z2dB2VSEDUN8^_N+I`R8R9J7NLLVmd&qFbkj0>EAIYbqGx zo*hdYK+3GH@Uw#LX(u8S!UOHh1|HkI&KKDhwObGk#6-j}39b0SN^DcNz>xrB^ zz^ewuioo79su<=N=Y^%wqF;+Ty{?ItsldE_B35d6*a_M98ce$pBJzB}n>AtS zA0n1^zo_Eb}L!Y&c`X=VbxH`uru%H7%DExq`&4b~|mT))(_7|ipukU=G7MFBjk zO8NJZ&>vWr>j0lXyl4RL0yX$35`Tq# zrYaz>47_=2_^ZVsZZlJ~7Sh!7@;5C*nse~hIM4Io)4yzYRS-g~Jz@z26-6P^VZerY)oEYAVAAaJ^pkPUdDXk! z>2x;;DxZPx)pZLe;ha;vJlF#%rxB65izaXlq0r<_Al?-@Lp%kugxvW&0?gX4$K92E zzIoCL{A9gtm(t;}bpMmvAOtemtl;Q$~EC9x|*~P z@RPxBX`!6EUimdy)Su{eTsE@EqIJb2O$YND6lHfLgTep4L>Xt7z*LrA_(4fAZ6;J) zf#wZ|)dkTx@KhUGy|@)t~Iy{ZpV;21zw>!6`L@j%gtF|_YUeatM9H4mkuxI#es0>0P1jIq}Eb{C@Il#7`OKj_q z2T@qc-Wa@z?VlIIrGCG#+HqDSS?~~g8HCFd0y(@S08g*bEf72#T-*Z^b8fQFfP1NPS8IOA7HwY@xXV^@Y^2Hp zb3IvWj?lu==5e@E2ss);AY9eJU48~)%um%|?dLcS96ZU3F|#OnvkY}NWA};c{Uxbbvsdp61?G z*<5UO^i)F6^2E+CR(9SJ0ThsSb`1%wTvL0pCKk3R)nLIak@IyJdux8MKzWC7SPkWT ze7{5FelMD!E)FsE>L>rYAMbS)?Zh$UW1Rn_T$C`C+1N?R&s+aM07ZCi+fwwm$qgf) zF+cOMe+8PG{9`^*MEW!;jKBM@u%ayW)(LO6!Zq)C=wHCYbai|q&hX@nH0DBK9=PQ> z>Kmf-xlx{%K%nF@*fOQz=-E>=$;F?ylepG43Hx%lk(UcJHgx_JxYA;^G5>_dn&7ii zc$8S_bimSeJ?r;{SR|+7+zRIJM=+)7Qe?zMhWzzU%tuLE@D2?KQ_sRdju1@1DwUf1 zaE%&J#wtVTgzqp*1VT|~Ge^O%#B8Nq3xuDXL>ki9rNxxqV%$Z2;Iw;53k2iSx)r67)>@VH(f5&^k zTKH;jBX<_mUf8vK+Hdz##Wk1@+?D)G;15Dc%7ASq+b-{gRwnl(ep6v1#M`z*o}|#n zf6LoC_uqM2-%9^8Z|i@Bne+KSn7J^(%r)^Zf4*OSzr2ml{b7r!ZFE@q;b!+isU5P> zn}+^6)UkQ*`#)^|*mU-!a@=3BpP)A^Y*MTNr}xbL%ceOQ$N;M2-2G9>#bukPyYV;oaL22%we}tU63}t(kXCW_ub)*lj~fMu z$5z*hwrlV&W|e1i+tbC?KIfy9$G=4dddsETq$-ls=Em4nx0cGKiI!f#tq4#Fjed0ze!EU3CKH3#KhVyz~cIFL%=FnW%_)U*XPUBL4!X6o>_uV14CT^!m$MNkgZdXu!(Qx6~$+FKb%k2k@d=8<5XTBPg58rVjyxkJ08?Wj@ zZ;jjK)yVwErm;Jz=MIr11&v9XZxu)k^R*K+XM)JgzHjSg_CsyQ$KI;px7svu_um_) zQRD*VQXf^g6tn-)?$j~%&mqSf_f8B=pf^piqbRNQh}M&(+m$M_^+z4wZzv|mo`1Le z%c`x%KaSb8}H) z%XF5%*cwfC_RaDqe!=jvHPNH%eL<28pP46bsos`?_d1#~OxyWMd%wJmax_0AGOlnr z(Eo<=0waj4DiV&_8Nk(zOHgybe}AR*#}Vhi`b};fc49-}l|n_IeUD~WC~B*WDtri= z7}aU{7#?J*wYfX_M?>ry(ltpOxTg`r+uKifR9vzoAXxkPj0J?xulLFeT=i(%Dcr%o zg`n6w^Zd)(Z<#)GRpA|XcF@%Le*d%lzyDcdQ7hFzS=FvHzV(t+pwOK`_Ec#lbMuz)!~|n zPG&K$)V%dM+o@<(Dg0o{bS?0lW>{r+>Y zf9*2VayuB+o#lP?bibBn`5E7$^R$t(22l|djy!jfrhsEkZWc|LP4GEE@9aMp?XX;a zqV~{Y>~YQ#BE{e4sT1L@M>xW@*-X(~AVpkllbQUH$>pnM7c`Ifu`{+Iee6BnAMKt{ngl(TFkzvX}`Ye7ZH>CF-|#U zdmd(XmtX#*<8snA#W*~2Q1$22{xKn&{`>?XHv(>NZGO^2M?K#Q7>*9#XNq!SIc@QF zMTo5p4S{`s_g}2PK8kCO$hI0R`OW5qbqW62IMgod3yY+2wD#J_`mV3il+AAR(>D;P zAl0<;!9p8@VnaM(^Cq{kX(_9&lKoSX9ec_Lv#V|$Y%zdxEX5VsHMPR>lEoKam$@d{ zo^Kj|c#}G=cb43LNpoOK3u`unHGGGRBQc^la~zcH8td-?4wbmKrT?A)dQABnHLi>P z=(ZFdac_;ldVWBU5`AoL$^4j0rTGonDVoX)>HPyXsA(B^4s!VCS`3?Ma`-lf__A5L5(YC2B?xXS=cKUltn%DrF;c{Yuu@{!ovRVFs z$JdyH_6-E%F^++3z+8N2-^+$qayLkgSAPvBN|AhvQ#NH@D9~IZZAN&s%o->@cFTEk z^~iMb?O$3$?nbui=d+z^3UHps@p+%`j!y@?!bxPvJJDvmY^f_sP;JO%neq%DvOg!H zq3L7^aqvz#FxhZ3CkP@YvO9ga3|#4sK=u-;BRf4J`UEyob9y5%E|8yDsVr%(YP8^= zhS~pxKjbNf-Fk|Py*?5tT=W819IgdP`{C{QkhLk7qd;WR~NrJqrRnaCS>o=(iE}4Sv}39 zE-}=)lc8BkL(~0xeRY(Rj_u`V(UP`K5h*9~JGKiL7u^$Lw;Av$etxpj8c|hj*z|X( zbJ_p&a>gGc_@x*v=NdXnK!9qJ($x7P0-Lpo9Taz#HpYH+r1N6OLWGXSx4UmeFy${s zFBsX1X}Ev+*5J1}Y43qEmOwCq}mvz zb~CK{i-1?cQLERtxMAn6i|VW{IS7ySP+tws`|R!~Y9$9&y*O9+=U2B6%xH%Yf$2i} zhrzN#*!T&51(lJnnRZ@}wG6FZ6U%nTSHX_??-t!A;q%gW_JP9*sz;aBi%x^CY+C<* z0bRAcLw!2SX9{0Lgy)&lSBL>~gE}VRqV-3A&KU(B2P|@;1?N^?=at* z9DQs)WWD@V#W-M;GDx#Ms(U0c5s@JNRdxMvAN?pLLF{4K;mcoTzuvxil^&;Aj-EmB zeU?90{v){-wRbIR*jUHT%57gqOURR@jDvDFPy0j}g`5!I;e4yIq7X#|ow#6Hd^?4Bk38 z?!7$-^Rt2Aa)EJOQmh7To6W&gGIqvTKj*gHdGbvtD&p@e2XN{r1#yEts0*1|Pxv%P zBeh%ZwyyhKdQDS|cFNAcE=x@-uKyiPZ4l5Rw+2FT?}jy%o95pZXmGJ?F;{m+j_8t| zRsKZ&+%td8-dnv`?mHn`r=aRwZPz*Nz~H3SqzfO2Oap`ct)Cec^G2SLou#dtZ&o9^ zZb@D-H-CnunMw+ep^bKI=T0;giLrcH7la3c>puNR%q$Xm7lF<&(md?-QOTP&v}{FE zk;*)aEBpW7Gz0i%?6qS~t)5toDKy!8^H=uUt3y6~=07`(QWg6mBU;skxdU7Q1GK9hjF3 zoDI{YFXu}cW2?-vv&trnB^l(#t0!uN10HL$iMs z!bV>#eYgLOQ+e2_$69h}U&aG^&!i<4y=1VQL^rST|A9|^p!eupJHJ-IT&Jn%(Q%dL ze<6B5bkXU~1>PfJfEz0Lw;P=Ke}lq_H~#Ym$M1}Ca}D&n`Tt5BIs!ZM=@mNj7& z1D|y;@wlnk|NEzr{cX68|M;UP+fRSnJs4zoL+|f@J@ml;<5N3!`O9G2|Hq#+q!!MX zBP{!#e|b~HkFt&TA`RP%fDOfW``-r3>>qsp8l(y7{~WCU4X8-zzd%KcBj&!n$EBkE z^WRdwZ4K)3{l|j@`-gY$Uc93BK=SmJSv~bP>l)wF(mS`!?QWRfet+{+1GlYCz;f-3 zBU|%Ka{GI=Nt`#7Tum?a8zU{!J}%j1tOfrRnwCo<|G}FtRNg z83kghSbeTdCKW{;fF${`g6TE*agZ_Kndc~$?cxl!nIjMEwGX*V7e~! zF$!iH*IO5gWe>9%2wqdj!M-mzQk1FLkU|mJ=2}@&o;9N1orei3!g+~a#};-ovQv1} zCEC-&5#09R{5r|<70$%%1-Y37fcO9+iT9M8MP!u>Fm#OI7ptfM<4NypOlb9J;GlAe zTypp#ayOdzs}eo*c5EF0P;Kk^bv{1W*G%Y!szr;SL1<+kGrG@lh+`=U#GWdNK0x>o zgXiNZIGpo|l19ec;Ux_o{b*o+)2$6UZHQaZ+)W}~G}uB#DcJ)iC=@=sf}B0u4){fl z6>MBTcM3)RD#)m_^n;)0j)yqap%JD!As!4sC=Jkr+~GK^c;Ka)TVDY(d8IvA7+1K>5Af47bX z-3O5BCzHo_@yC97 ztn`tbMGKQ<&eGqB{9LV*?Pjkw5(VVP@>1zPj^8V)>-kns{rODsd1>Gy$&gjTUi`de z-29(1-beS0Kabe&a<*ifk-D3eck2Ovd)p1tS)(F5U(oJWh(w1Qa;%6^n@H)QO zCPEmZ5b@0?L60L*UaSWaSm6?z5=ewvz1unsIk=|W21$11@`#l`k0z57Q1KNRsa1^w zVRWd%VNk=q(ndEzK-R(DI+kEPyx>p=@>i4eJ2ZG+Y^dKKyyt1^+@dQcjtJ|4OVzDG zYa6@r#+Oky-s7Siw7wxDQxhcaz~gk+cS8`hdJ4UUimS@TRzkpY!5I?`kBi%^2=N@o zu9-%EmFeo!1ONHPqRB6odgD zk2FC)bIt<_whtf9B|=7DgaZSlcGd}22OwgA;TrCf_XNqqv^_d1FVO^uDZo zsZFbaIx+N74)PcCu`NDsF1Z$C5Kd^cJ0~iOEh1Z6cLT7+x8Mk;u~e{Db9z6cpoOHs zd!P>;l$jUE2jFqk`L8@w!<-xP6JIE)IY?~~YL6NtB=`F&3K*q!fwY?D)i43}K;*hb z!f?FH3zC5T8zm4yG8-o+nPZUP>{;RGn?N;^*5KNTL57-R$xTsSHc+YF1Xv9HMlo3w z5(PChAi^WC>eu%tkOB(BRt;9D$xZC*__(rsK?n77dhm-z7E%fLBTxw|L;TN7IS7Xp zJFP4Fv-0B$*@o>9O3v*{zjP#?d(o#AEq?%VE?hcVAdyYY<53Yv03SOPibA5V^*w$e z80>mYeW;0}?d>8CW5a#`f}*Z8ZywBQa~1|vT(6hQp@_2LDEk1o&a0nz1VN_3oG?^_ z>5{7QgCa&JShH#{YK;y~(gx6#e(5qHJXXhhzhEI6uN+i)qqYbs=DBkN_IKjj!!Z!* zzRu}<*nLID)H+JK=q;EbsPV;*cL0kP0dnV)&8i79cs1 z&_2x3f<_AMMnG^Hp`!^UBJEhAAV1J`a7lxN2;B*DXo}|UIW^wXoZX&72ussXN*M+S zb9Mp97)#Ur3!u~@^Lvj#7+LsCJ z*ZKZ9f1K-@p{Wo1*?aA^*Iw(s@0C{zRd+_{YAgVgHedkV?|bPb7Yaml%p_nbNLyY2o-PToB<=m;GsI+i zfBs?6_;RDHa@_6%`s&&A&ZL82oz~OWpFx|@3m#5WLhoSJubk)!jVr=Gt%*rng=;LSXZ8@&?HNF5S0CT0M;X5aCxh7F|4KwoIcP*tY#s`YK$Y4sw`&cWHi;J&}w@HdJcX1aqAjG(d!h<#SdCK(#VLk#E4rF7X#Wp8~3e&*AbE z;2%W~Q1c%GdeFX%+6hga(_KRrputtaN8L`@NW9&2nv1Cbglbe=za^PuK+&sP=5l2Q zSjasQw8BAn_|W+|Arw3&M87f+aCSlp+G_sN;G}&iczAI)!z=<0W^JZqOMMKW9?c!5 zB;iHBPmE?yz|hCIeuJA}RiB3WRLX*2Ro#*&X?Srz1GC-w*~nCO#Z?<>)FMDhu-HPS zbZo=N=Tu`9IG!boiP9dpY2g1n>r{X$|+kj`;*kh$Q`4Tol% z4AQ-C!;8xKUXgEroi=wSygo8;f7+VFwJ(dtwg*@f0T}@9J@dlgA$T3WKTiRAc%rnc zy_Df?#FP`rC?M`EHn!Isen}J_)!=<$1o%3g9@|S*g~N(bkcV>x#+P~Gw;Et@(2HFY zVAzaK7V66)#MACFLXUBI0tG}3}*c>H+(v5gNPSDLu04d7tpEt z5r~FAF*2biPM|xgJWBNiFS;b5hgx_qwjchyZLLji0^M*SOcF%4+?e&L{m_81b=e!l zd&aQ~1&G=}%_F%Keeh~t*cCgoFI?A;JehiZr1SdU4(`-5jl|@PTRFp=?BY6&T>roF z2yWyfw;rxRqE~JWsw{0Ip_Lbc0bXPbuvi{UpQ|9ci&FJ%nR3>j6GV zy^-m~GfqO|4GRS42M+Z|&7e(2dRss6Gd3S3Y@!n4vW_bj2=-Hy<%ZcYZL++*@Xefy zH1bU#{SWwNK<2tH?CdW?-+X}#<8AM_r7V68rz#5+K+j2(C&2W*7Kaf50+xC?Kx56O zqGEu9M?t4aQr&$reS_;x1MvL1DZL&V8(+-*6~K{}VrCNvHEe6XZ4ZzUrB&yR(G;vg zGH3{TPIhVkVF#0xT8*`SbV;D`<2g1{{Tk1*J)@Z!2_^BWw>E1K0@-O31mukfc)FFg zdR7Xg$O;F)ChY>piFUk$pxOuDz0?6hI4Or=1-0M`2SZ~p*W$FDfKN^3Vu1Aq5z#dp>J>>xGGmP0lXxk3F(LFN2m%w&7@f!yByP&|NVU}`!ZrOT(yKn|s1<={B ziOlGNAv5QA`L!Xh{nR>2g&EmX9vqm;WNZ}(%Vk!)aJ&UhYUB?N7GNmf!wCSY)x`~i zHWj1e<23T#iJd6IU+@cPoof4lEw{VB^|$HvkDXV8ETf(VBZ!jd2BpE**n% z1OQzVvqqf-SjVd8D0F#0L>Mvw;(8+wy5&(Mse=GdIF+shEuLxYJHXOo{H+I63EWyQ z2H8H^FNLFt4T(vD%DwFPz>U0Lk@t4OOGzi4$GW6hloR>fWs*9PFdJh?(i$F2$WZ}|SMZ_79 z&20S!{WGV91ziK+sH3O`Kq6vc*hc|zlblcs$IB-LJA?}1(Y6~b(&mH%Sfn?z)*oVC z!?hZUIskSDrrOuRZcn_vv_j0I#cN-xN0!K2DKU9gJy@+xxAn3x-*@ ziMfDJIr7}y0MI5H?w$bfUSqVj!XdJlTLhSU(Q`Q97IDXF4+1yk(_9}+y{EARQ7tG= zZ2*4~Bv0f@?5j{OluU<%xzKIf(`=%FoRGd^# zRWKL!6c0ez!E%ZS)n#616T>E}`We}AS&0#p74;WdMW@OQF~e4?c?@`*EJ-rNP*D#} z5fQdh)_P#~Ol|?53hvY$2=^zZA3Fh9 z?MB?K;!5}qcx`{rG5~b=zQzFn zP!?HYlBqN-@k3}n4jPK~_?n=LSv_wY;bAyFP~-QT8saYOguzYJ(E@lcH!mpf!H~~e zW_T^Fh-y+%9{{P^Yj^}c8cyDZ`_V+11fcROqzi$%mE)INV^IX?-+&4m>9Y88s>@C= zkux<+FZ>B#qG)p#yoJD5-HY@}*-SGb|1&qIyek)$w5!Vr*miTgz64{m?>Y7~@FM0n zl!PD_IG+0G_v!}edh}@+ACD0y!z+H(|227d#EKaq_6FXD*h)ad%W~Jj++Frq1&y3s zQnnW8>@o8TL0fF3Iwpfy;X*tLcH!qeax%|lEOKu+AQ!#;*%htkroS>Z5anAPtLq|w zuNg^-g1r_!;{v{l-s2DM5ABu!I99q=6;QdnN0($^WHLk#1hLw)@7QX)v{5pMidI(T z2awzwhHa8WPJ#fppRYVLm?v-&fq7?nejdb9y?Z=Ffqo;Vh5-_j|3M!R0t>$gyr=2( z5ELDIVUGN${vB|bhHHvE;g~-s@Dc%T%e7E-*tUi#bvHm>17oN%i0zEu7upAY%1?V5 z{B*wDyI(<{&~MjZjJ56_acj6DnD21;9ik^eSJntCBVuAes&=;KtYRX6 z1!Y^5<0;~ivRvEcn+?M}J8Xj|t2{FyioKJCFj*=kh=%hErep z9e75;Ty3}#8QhxM0rn=R#sw{=tex{OBG(Rhr})Lzo7+{9enTXg8b8>9rxjFNPXO|t z#n(_|=k%a6A@D4z@`b>x`b_(uz#Er!IiOF6;Ecc|dV)>7A@H11f#siD8CC<3G@1g7T)~+mAnoTf zY;7CulVrEtgOO1-f^^sW0B&ABvIaE@&l1}RbH9ZU;y+CYK>kupxmaa6gj7(hEBg#A zw}kC)g!aWBApl6L(*HXmtVtzy%^nPj%MrV<`-_KD)69E?6Xf?FnsrhOFAQW8Ml9jR zgOTsC?I#~$HNS#u#oOgD0BPo5bs2<^AUCTFkYUrAcvw^aYD3VxoMS&d1$h=rA>%TL z=L5N!M=@=2wfREx4`VC`vhC@+LI0trRTR)+59AC>t?A-7$0guN?+Xv54(=&`=CmYjJ=uNDr5{5nyl+_<$kxbFZF; zp-toJVb7!ee35P1b>;SY_7ua=dx2{;esHH!dJL!#R5<7hG~RHm%=97hqE+H;K+$B4 z@f48n*XE;Pi{2 z#(`I(vR1)I}J3Wc=ztF48FkXCBT9a^buo2OZm@Yzjw+DB*nrwgbz z#36UlSx)dSdfwq^jeUqgCSfIacyYSnhoLp(%fvW~_KPgv%rQq3h$!s~ zwlmJ_8l~{VU}KfPb^4pdLpe2kgNBJOvl^ov6df_{4cgo7;DYZ<@9sZ5%sn}kxTXZb z-;Yfx;2^?$ztw?0*;?)e?Zq_{`_C?{wM?HI=jxi(GWBkY;_()9cjopX`(byi5712J zG9jr#T10o+H-aFMh}_PT=#}7N5NabI=}zB2SlAkWmDqtgh)4h$I3N;$>7 zj4wQ;0Yeqlh&9W(w#GpVNRS@6a%nx=b+rwz05sS4+^`7zn_&8^FYtxbuKELI@W&rU z5b9nEh_L`ju+abww(Bt29f$`3RSaX$o=b5Djn>ZL!e}#SsvZ}n2C@&%1i8*%c*T>R zdh&vt`D!l{0A-U+K_W{z)a1Z0t8jC!`o?-frW1Xn2C|tS-hvLO@dcJ5T0)KiLi`$oSP7MC38j>u`EVjXiPa zGbMidUzX0{67?QVt<7EY;5!G~>3}U~&*e~MK@-7i9z@*Vw&;PLh)T*upknok6G3%L zAraFEUOn^Z2zV3K1jEQRWnvT47E~r2ToXSSK8G~hq$hGt^WW?!B*)|JD~47|k4*OZ zT}GV`Tid1yTQ)BjNxYSkXCUgVf8d$~lNa8X0#T>K4qr=HY{NM{^e;ROJ&k;Qwrgv* zwHf@T>hO3;G6rT(Qxcc}vfHGk!$I2S{(FOy-GFrFjN=Fy z{#BE}b`r_lPKh`pa-zBSCH6)3HN0%b79t~@r*fr$2>#OA2z>E5{brEy!{t!meC00Z zJWDJn_8@kHnz+}Ukpo~Wln=qMyb~%f;5K27vvGb-B$=e&G)AkqS(hSVu|M?~K%IHc z3WmUn_W9TW+#L;_Vc=CbeVPLqkWxw=gc$X$x>CcqPIr!H^?(TQpm`%Q zIuy4WHW~Ix67)nr_PuTngf7N*si8Go2dKufmd)mo2bOr@BX@s2CIKkX-=pWQjVq z>tqCeOw#D=R(RYx(i0%)3wn!wsuo=sfvi4;ku(AlNE-YgpsP=gGxxyel__`to`r-O z1OcSzlJ5j5X0{IxKfDXvd6Q4Yv%m3dR-K|R+(oT9t8mT12oi7`U{U($MPL%-Q}*MK zN*1G(LCUaT{&$e7lJRi@hVfkA=M!Kt4;$iv8BnPg1vG6v-gg~jiDUfJ>(~|~w-4tF zQ0yRUp>q7I3hK;Zpd689vk_%>oWmVnOUqXa&}TCh{091L9&N|rytIcW|Ax+rUP-C>r>W;(V3VvMW9HDO>gA`HQ)tJpdkiC zu0h*jdXZ12M@W)5#GeOmRztsq0!-aN9V|$Wx#OQNh=%jBXmQ@M_4#h_A=EwBj==q( zdZ$1YPv+#~&tWbXS_zl%f2G>QzldF(h3bnBXD3;ZUmV4q+XzIYRRRllJJY@T>TWnK zG43G-Yhh)E1-%}icXiQ^YCl}MG>1WYHs}=-WwMoFvk#Nn_ZL(sJA>jrkj8=JZ1-VcS3$NbLS5t4rN@vv znOAUCn3tPFG*EQd)@lNG#A7HMa@YzE?S|lCqkK++3G$wJ+X01g^z|Pg z{!lbM|7k7s{cTsZRP=eE>c0TTPH&nI5ZK8)dn-xDC>sgUe(>BgGiN!(f1n^M>lc}) zmQLHNOxxVLsB!s>AA~dA-6EQNPs|bm?>BR?IfHOpH=0U2;u<=05nzFiN z^fDaDn^8xhZw$g18hXiMo6x4p(2(5tk=|<#p~KUo9FRM);~EE^ge|RH_6D?%6r!#Z z;K8}=3<2ndloqm)`f)mE=|)NcAInGcx^?aAz2 z)Y3J0?W%`Ou&YgMG~uo~?K=fgCVROr3Sx#i>jV-!jX&pa0T;jgriFKFVR4T{GkC9#klWA-VkP1m)E`S{BBVi2 zt$v<9Kh+wS%S`fs2}P+?R197uVz0!(Qg z%wC=l6=v_wAHTpcKi+5%TMO>>UfH=W>3YKS>&X#CxRPut?0lDWly6$%5i3R62D*Cl z*N@U{oTFF!4(yD1{|6om1+8?PiyPeARy@=t>BIv<?VzU3WQ=- zJSxV@S$Jh3<1ur?J$QWUV=)DuY9tZU!5wXQ&y0X(q$J7Bm*oxUx&gRM<@{0@fi+ z74qexyEoOpK_QAY(*mY67+O=px-qD#-<#um!At~@vRc|F5Kr1ddeGjUfrxSGxYtr`*le7g zb%=q}m5iuxVMMoK+4}oCs70!Ip3#B$OLOf)T00zem z{^5Q8Px|uN*cGV1$f`?O#~_t!Zs;?0r2gyL!3I67@$RBMr@+%x$MZSsA)A$yxl|iu zRq?C6t2$I@SI(WWeutLme3}qlIXe~TUe~m)s2zU(+op#{pso!<49${8kZ3m?RBwO+ z?(_D_w@<<4RGP84bbZH&b{O#=+*3XXEIVXfYRhQ|%{W>=wt#K5joFoHi{ z@u}Xf1@Sn!of!?;1zij!msRi#s^C<848%6(njN~E?P(LO&0MuB~WD@V#|rqn_?P%Cu$z^?v4cr$>S zaC-=4UmtTfm3Mqse%K&C{|h^DI*h*A)F6hQUsr9=Pz!jLyBs~h?@&Q%M&r*sR>pVm zM)E8CD~qi7u4kU)Y7l_KI|U^?3vWw$KT-p2JO&Cy@|TuDM&n*D??Pt+CB`jZogEy2Q*G;rn zq=U?#Rk!{b2oxN9NQu|xM>FE&FsP{1 zcclSHY$9Ln9Mt5}rn_B1R7$0Fa2}c{v1_rZli6$eB3R}!NE^@_`$a&)p^2mp5yv`_ znJOLF6;rLLC@=%ZqX&+FCh5$$HT5k&hc}7IWPn~A!)^K((0s;o-Q8iR1A47uGZ-iZ zf4z%O#`p)z{4|K!{ZJGd8GVT)ExUU%BcOJxbhS?h%JmafIZ$t$341dFzX08_7iOr5 zg*Am}V+CxNDU6+@45X8+aY1La)AkbEIw;8`1z`wvL*cf^Z)ViB2<@|U` z5H{j6m>OOJXtbuTWVC#s{kv)}C|V>MYT1J#;CYG$s3&#@-v#x#EBswmf?N%Sjh{JW z6ULY7EyIlXuCMFiXT?~?C-~V!L~nq=W{Skkqsl<4WnTOlT$7ib5)3Xtwso)k#}(yi z&|E47jjP$CqSV5;b?w*&p3!SpbFp&5Z<;ZkXb8A`2YZ9iXpY8fhd?`pfw!P2k}2-4vwHfc|Y-UFDhKvq1Y z)@PW7_DJo&qCpgX=1s^Zz$eZv=#>I5?R~`nRPGbei7}tKu7l|k#>lZoa1K!hG0Bl4 zIDdu0;-jGhLB0$FHl%*QM;A*B)b&?Xsb2(zK|b7MGJDfVm5>7^ z$yeg`K?B8PSAQr}Z8|U!8Dj|sZ!Qh!lx6p6D7L8BEkRsgPUzBwA!mox!jq(qOz5dvu~r(D^iM9Xmso3WqmdS*$$hy1wq#m&zERoPNPJW6Yi z&$1;K!bT?;_T67G${)!HMz93;Q&O&hBlIq!N&>0gFhJk7AKmFm*V(cQDGhTLm?{lb zt&XNG=BC5`Lv;Vwo<7wA(2{&kc?5z6X0*%dP=2lK;{$HP*Q)3|RKh1V&)kEZ$aaD| z#PndF7t;1;&e7$aW1Oq2*jqzr?`T(W3`)b?UkPMHJSQX>8KDnS{%L=G3pt^R@&R;~ zZ=|LIiNEHrWH_BJ^9C!y38gW2rXlfrnb=}1fE-qB&X$6+aOc+?SZ;qxDS3xRfsBCq zk`ll%MBZUQh(TC41f24m?3b(1x9+Z54br!+;ePsISnY{6AvyRqc;?x0SZ34iB#4BL zcvySO6XF6jo5)bSj!3;bA-XcFSJZug9ly?c=P5vT1Zg4&1%)FcSEQ4D))I57I<0JbyWp7?_UMchIN?9aCAHsF(8CjaEPo;g99 z{drT7E=-JDm(XynddkF-krNMZYL<=%=)~N$2*^lE2!5NfnBwAZdLZTCO)GFq@pDh{ zcX>A$?^@~(s`VPowf6+*i?eqQ{dqA0u0G$AAFQ?iLe_GIk!29IA;y_8_k+{C4?7R} zL)3EfMK~eJ6f^MNYJ46<3BCEv_rHU{)aj}1ik`~eg|tI(E^DM(oC-;uHk9^Y;gm83 zGgmunc~B6Jt_MSL7r6y%T3Wz_wljldnh2D0&M@{tdQ-aice)7Z_9fXg`~h|stq8h5 z`0UU3ouGT}mI&C-LT~P$MlUy;ub`#C-M?q$-2yiIAadTAYWd zX1<5|1^-pI)AN+|qvL4YJD(O1i|J3pK%OaK{o1ylTR6+*&n}4-0@vPk*)lfc2ILsl zs;93JoE=l7J%5j zA;qvF{f3f@Tx;*2I&%^L-%62^(iOG!h~8Jp3_MYdoCogkNHGiKkevNF6gcXD94iB5 zKMyOw*|~gqfCWR5#DAR8d&6UT+e1ENw?-L+ee-WkbfL_AIRqr5VVB86m(6K{*4e7T zj`&YHp}~>(%$^|WLUeqWEZ!JGOcnIU8H>y!b7CpX-r=TRz&5O6atrS8H8j`k9YD#m zQrsXKlsx~KmHH`QG=C1FdNljkFCd-HKwX5bVRXtKb^~;phAJ$lo^TSBI(qi3D8cJ? z7utZg_k6WdyNF4Wz5dT%Xo^Qg5rk8VVFfiUKSgR!&7+R#ax~ z{L7tMD8bTn4{zmZu-I#DaNq~4A-Es+sXcVqr;che9Ka6F8Tmm_HK2BG9<{gA^CkxR z*=33U_K9Jce|H<*}W@qGBS`3>AgK=2zW$BkUr!lA~~e%QmAbB zr^3VRh&I9^>I44eWOQe^;etEq5exsaTWt!7tOf{-C>1Md4V8o8)m>JslzSk<_S>H zsUB{C2CGdAvF#8pDrBDn7+d8|5-7~F^}U3eP;okm43O=LoZ(+XqG&;*7Dz7&M(<;w z2H=nHf(pyQs|+OoVJxmdQ8&1!VG14=mL><4=RRSZQ}D0^?)S4$LB&76MgrHYBTEwI z6@TzqI`-2DQ{@0TfzI+#1*55Z=M4o})ik)M*_rIt1A81;sdod5PJ?NOdQ& zKM``_A%g`9&?VB|1)AiltmZ$Q@rJRTHSve4_%SokQx{gl=z^Zi?D7cI)=aPVK#x6e zbthqL(<6o8UC;%AQ2Uy*tGNzdc>*`{b;ZbAsvdfc(q6@UgtjE+B_A~>v-#B=8z_pU zlLY`V@7^Mig1qbO|NS&+e_3;qy3=$k+K(I21@j7Ic|uWe^Qbk18mGYt~i$vX;F>Nf-89^g_ay zNBV+S{3!G940Boi#s>^@r|x8nd`Mcy><$BG^-yYF66(8iA`I{?)~6a6BFL@M!1rX# zQcoe>{}h^%L-=({>N)4QJfuKVL4y+oYpgei)*@GDKuoMc2%6T{cB#|55sw%mBVc58?%{a^oa*FpB*Yb%b#^dYZ8y^wRk9?w4<>fsl ztL<@LZ&zXR8~H1jEkS#qe?1t6n^=o{5Ckb{G=CSuJHt6K2Al z34K?At*tEpuu=+ZJ(lps(&&_w(bddKW0}}k#L$yrMVY_y~Da(#{v;1%}^Z?tnX84vVnu( zbj^XNbfh1h<{yC0@SCnb2YO+B;o!k5-p|t@X5_dWcSFSR%w{h+E*~h;a~Oo8U@`WN z{7=81a08xLtDg>#@8yH~@Z7wPVaUEGXZ-db_+i9p~q{h?J>0GD=Uk5sNe4GPFE zkx<2}5YYaFV*c%1p#Iz(IP9hWQ|pQc@MGR8YbYRpv&n2I5js+~R0{x8p+$KEgVd`E z-VLeNM1dY$?ra_=0^EUz7B#qS_scKhlK({xJNs{P*gDzD|49z}KN3SC{YMO`&)sKx zXOGCj-@#8h?rW9&b!GkNR;5d#YQJ6!+x_dVI-B|RyCjFUAKU-;9c60NcB}Kp_U^j! z@rC1W8V3)Y+<4sAd&|RPCrlpOUpalez{PpBQU29G3G)KzP<&y zMx?zbQELy@4Tx^s9Hbz3dicU_Q(D=6WAFVOl~YMyhoy0vH_J572-u0Q%Es+QXKb{h zHhSZ63O&T5q07_sI13VAV9%3Kr7qxtE6tzIX8`N_5Qn<8hp5s#)1t(B{QhW=gsV0> z@9F@C{P}KcaQ)2rTliCY1Ys#Yq_ec ze{GitQT|5@sw94Mg+s@aP)V9wi_MDMWauf5D$VEff3R3&xbv ztX902kF5y0#uZPqP_g4T^H1U)m8=P{xfuO{nwK-5Buqz1sE(*(YB~`{gx)_R8Y$>k zv(=Axjz49d&5JA~1v@S^AG|@H&^fnr(!Bgg;lphw_f2W5I(aPxeu{1Pozx6`^nQm0 z$YY<6y03)=!u0PdCZ^bAvlD7gYP6Xh9?udyUBx-l2QeUWg4Ny1pL5>)xOc` zLth*A)Y26X-#{yV``feWNW;9ErSA=F^VxGdlUP}^gX}oo;yrLO8pEfk|sfV2W)u|}kwneVxnNdAwUOp&SG2fUSe8-kVI#PT0 z<@I%;O>Sx1WPJC%A4su3-&x3x(Yf8pJ+!>5Yqiipt^Kcorm9c-I*H>ZqoiiF>n-1Z zLuYT9!T2-QU8mp$iLNy%769eVtomU8PjVVR*@ zEInpA$~Z81C5}w84=t&|yB*j5TJ$`Y|9oAw(U6YPp!m`EZ!jw;@8{!+T1@O{y|h_x zeJ@Tp&sjue(!)IAtM|>NjD5wG(M4BY-8wi`RpwwUB`JPqhey2Y=O1ZSqFvj<=zD_F zTApNlw|VxKJ9miV6}rDKs_XGJ4(jYV+Vvfaz4l2hK{fs>=ZG~q%#d5j zMwcFpCGoq{9b~4TxrlXKJxMK>SLJ_NFWJ<;lD^KL#NDs7DtNFfhClgqLw3_F_Tv-! ziTyF9H3V9n+V{inNXw@C0~y?YZ+o%u z;Y)kOdhKV<-kGwC;07_JZU431&NC!aI8*{RwJKzZ!6_fYohcr2i@I|R7kRet=J7H= z>8UY!2}<9Us{@sB+miK+jr|XDy8YLXcI=4Bf$H@0m&xh{2FVC<97Qgc152awI zi}_!69+~X0HHt1hGj!pPfp1?Yu+2dGocsb;j2b)T+v5fq^^2>Ix6Wn zu=w=EJTs|%Kj*u%*9{lzJ;K!;8f`S27kfBNdg+w~_73rr+=;DgTueIk1*Y@M-OuJN zS2}MG+&@+pFTA|^#r;N|^a~M*9dQ$y3124$s%{)7`01SzN9}nsV-z-pys0_t@A?y{ zYo3COm(|bvFBe41cA^47YU+z->XUj^6&G_8*qYPQ^sZvGr(jb|D1g|an+1`WRLTTUrByq|fn z^by7 z+>yr6ePr0)c$feDS5aXh<0m#4SEY<9^D_qyKc_9oMK0|*6Bp_{qVt{*<$iwK#Fw(ZblK)u5Kdn~ z=b1F#aPKCOq_00u=zDNN_mhvO6pXMVZW7v5o?Y8r=|X?|+@`{Ew>P6H?qs!}ypHa) zrtr-2R>_A^L%iH)?Iy;4L7HVZakW=Nt7Oupx1$wqSddBw?lyg@-Q3#~es(geY!l-- z`rCdgI;i!2)6*Bi%SX0qUMhRHHwWgrUjOx41cf)_r~LjluOGcbK8RQ0dcH9yYgW;d z`XtTP{p_6_<5QC3UN5bma}QzYAK^5A zlGY1@s}I)gS#?$Dn(cQvuIDQk`oyf+^oD~(7}MoRI6iaFzXAg{{58->95~hRU9tI| z+CKIDUw(-^Tc$BdNp?SvAGH*p3p95>6p*IS121=R zzCVGwZa=I4n-CC3u&0_&H8Vs@019 z{}pZ0Dw=&Hef46+z4veGJv>PLAXUh7RHpf0G&2rbURk|mw0`m9U6EY|DsA7}u6V4P3KwV7HNQQ*p%7G^ zEfY6!MEGAmLlYgYvjSlOHss6mifliZ7K7Us;rzFX`>9zgZI4eT<<@*f~vEZZL8G6T(FA z)zFRKRr_5(KHR1Kr~ecqW7D@z}?$V+J(7`KbE-D9A0rxjZ>GmdXf>r(HXkNxhYWXYdSxm~3dS<|R$ zaInFk^3aFTTViW<2~>^I*c4G6`O3_UKUJMre^2-ZINP{Lj<3ocGvqIwjOJeB+KL&r zUPFb-U1&NFhooBBw8s$63USt<1V4T!_cc#>Vw}$HPP+QbFYE9A*Ok!x-|9;1_BZ{{ zE8#}Wsgox$MmMi|{%`e_1c<)U{`LRXSL(1ejkEYA+$&|HrF+|34P#~LXP0HAHyay! zKlqmE_38E<4V!0;cWS=Mn~{(GzU`zmt}C6f;cwM+Jxsv7BVKx90ljzc-lV4j_hbR( z4$E1Y<-9SZ$S#0HlC2WSb_2;)g=A|$vRy~JB~6=MPn+FLI~a=9iozz;Xxo3% zHvN%OGLn+HKoMS~m@HBbEKuAQDbtITO)Te1ma`(u*@fjS6H??FQY266*+jDam6oSK zJNN*r^$+&qL+r(S*o%?ai!s<$QQE8o$yT1$Sk-r>ezehJgPuy_XKmBrl)Vd-C6=>J zNYO!(tuQU`AFSVfY-u?5;zw=MpTGC%&mrrRY{h8@Be4mew3UZb(tf1O4W(>fp#1zp zb??egT4i#xd6$K0js2c)DRaVo@JaN}0LvN1wV!0WnU=SSb}$-y@r!olAiWd&as31~ zp;kMkUit2=OC%aG^FToNRc_qnZt6XFHp1=DeOgx zF8sGZNnW4~{z#z=r%-;RL=C0jK56&WYjf^mOCzvd_pn`mW1T&N?rDQmzWGF@KN6N}j zN<92GlF~Vp(h2kaBc-}tTd!7|^9ZXIfz^6|Eq#P7{Tti$5Ze`o)w+xAg0&07UWCbp zFG8`Uq1e?ewApR6S!GhspQIk;kRqp$qB53qKFhfotZISc_yhR`1D~{WYqW#^#;$@D z>XCY`hZF^~oXr;~KRU5H2J%E`x7O40w$N^g(QbjID$s7h6Mv=6{zjYKO1mXQyS0P% z|NeJ=KH=XM671l)?Z2%>do*Z~61G6u&2o-sId`(0#r{1n-9NaLx<$(P0!3<(a&eK8 z47RdB`M>{VdzP~Z%ekKAJi&qvw$9!x=SY@wF3Xw1a&}-jSF@arSk7BQicCU^+(L?k zLyA;FiiARn;5EHNio8OKU;~^CDY6bJatMrpM$z)1&I~Kc{Cs;-3Gvv%^O`^R9LO zo}FHcO`i{K+t6w?!!Ns45q7uvyTOByl*Sa{s})^ADxxquKl<;v)AmXUBXh)-@1~MP z)~)~jujh|Hx)5~&2Z9A%@}W2UXAL+5+GvJ1vw48meVsP{F<2ldK7`C_%fww_+~D)W zUmgp|pZ57no$fyF>^Uy~Fdy9(+o&{IWJG^dE4bSf%^es(ahiF4 zpJyAJc<5lkNDQG!NVg)o2^RNx`#Ldp)v@dU>=HTpc=E32U=M{d&<~Hqs>HW&O{&UZ*znKj-}aM8od4|7h6tntApj8g|jGZ#Kk4 z9d_&7<1>`;sCWIXLqkRu(hgA_@;6jlt7DEB=TJCAod4vL_iUBGWw&d$Vppk&PId>S zRH%q5S*{XckocyEmvgao75WiqU(Dv2zRrD(f77Q#Ao0&T#DKQiCr}}K@>4$Taiz8& z{xv=dWXP!bplXN6nl-D9z2@b3&T-HCf=r#tedxRkKejo>v&x~S^*fj|nw!<=hR)#! zCcSgUy-&om`=3?j&??JQf;{i|53MjwOMIrYO>o$!l~c6Jl;o{EaQOWLN9V#i?a>_v;1?VoYbIkX zeJyxai6D!o3-WPJx%fBMR_IPpMJoXj&<j;8B=jv_l zjDdgC)?@(LRLt>A0>SzW$CBsHJ1+=fGI=?qf#GV@Oke|X9yR!yzc8I0^a$SY2FFt2 z)LcxbExN-Jev=4j_l3gC;x3>&2XjHet$$+PA(xjU4ij1V3jfAaD;ypvhw_NZ8$mf4FfvyVn*`BQ&4Sa@6+LUa5AOAM9Dn z*8S6g@Y>NBwD3Suk6;Wkah;&K2f~2k%oeNQKH_vFrk{w)xzKDjZ`i%|q5|cMf1Mu6 z&hdjO<-q?U+4wggfJkY+ddWDAxTj+#4oxOx_1dF5W7Fh7t8cvDj7QGxHwfTCl@P3G zXDU0#aPNwxK_A~LhnZH+>44X)h9|RcaRiBiU%b%vr$L@h^}qI(*?;zyy21b4TmNVB zblv}vr|WkL*k*$YTQqxbv3sWS{Qi5_PTCb8RX^?ZP%1p@XszgjZSIeEtJFqrSN2@@ zaGTQBKLVaeC;qzbzT)q@c0ToQ@=lM%uQ>$oO{!)#_k8p5_b!gynf;ArZb^F9v-f@5 zBtLlxmvhb^Sj+Rv67&?SC1^Cx=d%xv%xqxit4+M|wQi3;Mpg7YM8epFt#J$8`g*=q zv{ihTQp7vD(k#ihO14scG8vyg4h;vGFk?4x# zQSapt!Z@bibL9b&A)y3F{$jdix|@LJrmktVtehW7#ei-B{lhGPitC(L;Uju~IfxU? zai3_p1Mv6c7~dV3k?M3sD2n!bqD7!29L&7a2T#Mxy_bU4q&FK~fN+CVFb2R7;|&&C za%1NK=QgcxSSicS;j9iWLUDD%D0l|i1vVCf;98a;ulsL&av$rK1u``8l81nMHcKlK zgZ8-1BX;mGbN5uhs5BWm04Ih&Q3*WIrkV#5KoTj`Y=UyRp7f#-(jAMe_v_5bq#&i; z(CeL9^amnt=3nIL4b`l=xr0DTFRl%i1G-n5Y6%Rjos0+JC5((UJhL3z2edUNSz8=v z9ccrM+$Y!r3xUg=vmmr$@D?w_b}h(WF+>IzG*ZjR{EPg;rVa|p`3IbU=2pF}90-fL zYvl;pP_3jNxSI2CIG|p@xg|gpg*39Tky>9Z;^NiY{}s zAjjd_@>#8xIn&S*`yJ^jNstdG+Vo0u*FgQtd*-CP`IO<4o%exXljVIj?iq9`lcq!8 zu^jIPZBTvC*+}IeoY_R3EIEu?OJU?3P^?-S?*U8DNP^1%dXnzG=jqUu4R@~76{b$i zKn>s)xEoo}{(NpZq0bArMOB~k8sLG~!>vK6r+m&W9B5R$)(kStot+I9&|n%~U7A3B zQjpjUb61n-1jsj+R5w`G%V{itGH~v4kUr?$vx%ojIUgsouH;EOxqVRu3}NadkQ#ik zxl;f%#ncq0z`RBE1_|*rmYb^#L5boM5mdH%vwifT6nxpR2io)Ss0q+N%k5o$>>nw*DN< zTf_kp2nP%(=U_n2hrAHF5oncjMs?8s@Z6LnAU)@T$e^Kzi=!V0IN5A7$U;;IWl)Cq^6TyM2y3CyfX=x$&uWvZ0?V`??f=-Y39gY{ED)veusEXREXEz?vtgeKd+wNu95~m~~ zHwd~Qt_y4f*j?0k(RILF&WZs=A7SgA4u~5Wp4|xud`9^YV8j0j1=?}i69lnVA-z5u zd0Yp7Bg3W+({mkGK}XyAGSRgm)m-_XnZqEs`L585m$_`_es@O2>HO45Ggt;P-U}LE z^|D3|z~gpOK(i+;gNz1K;rqrzC*NK#rm@8}egjKPvlL!-R_6iZ$&q@)gF9duW^V5a z2gomd25yfWOX2N3HlVUuZ2j>t43C$V0wNL^+8OX~;>;X)Ub=?MauIr#AqfhMy(>Mx0*}VH{UJ1*elP%?m&H1jy8tEF)y6p)IV0kRWe%)X zLvN(l-Yvs%p~x3{(*bkW;fq(jPq1D2+u_B_Ty=qh<>WjArr)F1whu8skDGm9rOY}u z2kd3M@e?eHrkx8|U#_D85HheylE7x1wXXnSiQwaXNZWb=YZe*h-llJB?Qs@l9AJNO zbCEL03V%07I$SYBW`WXluP6OPYvE=U^et%3UeZ^Gv0(BUDI;NkWJz$DBK%oO8^%$ZoP{)3|_*3q{zbAn_!xqvy-wIWNuhpntk2SD%GeraH#D?jPc4yRz0r&Le}Y z{+iq9JNgR6BUv+>0vw>So$WH@SN04hU)sVasao@?BYWAup&lxd1>tA1`)Vf?Q?L~} zP@u7>5M>SJsG%;w1ts3nhb{K~O=wDKeW}WS;pcP~xU4y+Y*CC~QIUb;;;8M^8i=^c zR6A~=IDN52!SFTeu$>ad1tDtodnaYjm&4iRCiCrHW|IIam`odmzOqt#IL_}uK&xbx zp(L>?;wJuLrC|-qoOA}!**VtYlrKcQmCLFS_d2Kb;J<#1O1_|1i&s+zT~PaDPb8K0 zF>RLCqDF0CaakRR)ga$o4jN^JICJjv*_xq-lK7Ud=1m8ngbOvaL(Ood**$1`n^}j; zQ0vF>jVa>y&T`ZHvIW&1_m#U}2Ma#aRxu@fp5G$XcotTjF>88CWc_!|DlakOAGQVEB47}ug*6|piR4->0 z%fk3nZaw}Db$M(~rzI93RXNEg~x}%j$Qn-iwV84MQ+eGK(y|!)P~;J zn*L@#Kz8J3|3HD7D8|VaWVu|Pc+<>Z(8`u*u(q)MK^w%p7p>Zppz9dtPC)MRVSBtZ zEADcgI_i0>=7vOJvLq+t@d(8OloBZa$hW`Kju4L9TD$;V%3`dk_c3|Oc2jh`2!leO zb|mbYF%(_udzA5Fn4z#vE%0mYCNFO4{o7Zn!Jlvy%1KnSe#pxzxS$|sf*R~Dr{)K{ zoAKriQu^rk7*kt4bAWI>MO_orD{7V$gbf2Zhx%u0ahy*ZjR>RA??f_31bo&-%??!c zAG6i|-5QJWbJls3>+1hi1uj{6RHi(nx2ZOcpI^F5!6d4Tmq2U%S1{{@CJOZWCnH=@FKKmY{;$14>E*2Z zpH}01bRVe7{(>3W|AjFFMqa<#0vHTkSL0gvGjxrx_b_lKLxCe>;Q`Vs!?>sRS%6NG zFB7~Ck^@abh4%w!aVwU9b=#FZ^L+j;tT%z8^($33JNHBO4X{7SOS=HCEVXa?6Cz(y zZ3tgo6c9rVBNjU#IV*DHTm;!Jy}eA*5b`=M z{Y^Z7^VBF@b%QyJCfPBRST5c-<|-pc-0GjHk#DPxWf>2|YCr1SGs2Claugie1YYUo zU$*VHffBCqTat<)1Wuz|(mDmqSX}2gf&i;!)cvxP&+4scjywzR+ADNA@}ptQJS}Q#NTQx3cEH~Hg?-qrkKf%I741=;cYLN;!DVRR(B#|NFh-%XX$%Zt)_Bz(%D~a_KJI69eeVR?OEIU zSKmWCGjOJ~X@A$n6z+72Z`p|t#BZkf9W7q{UdZNth?TaVoD@u{F8r?Rxx4{7r-&rd z=)I4oXWA@sO1y%PCv5Uxau}I&HB+6Y#Q)_~boD6e!9iGvpatt?t@ z|GofM!o54pqErEuYo7NH)k43pcuS3Y8uY5mk)HBVhD9&Aax+j8Cl*fR9GLTuO~?{W zj|{-z?rtI;npOYR#8COR5sPoNW2cfhC2wt3-`E?JqRX*)md4nI(t^z}>1^7XRg%6Jx9bp^`hAwg`GYQ2!J!>{ zd-W;?r3A@gK}+Xn?gJWSq|gJqB<&+EhTBy=q0{iKT;Q$+qhRuB+AS=;pnaN7f3aLl zDm{v1ZY}62SqAtiR@tSMxy(0(!es87m5FA|#;%B#9Qv(}&s42r`{^}Um-|;9uaHVPuPuD_2NYN@#^z6*Z3_&y{6Me8OBahZIqHId18{Pw9kc;lcM zTbCOuw3U&$_T`JqhXJ(wW315I63ffl;=)UU0os(N$nMkyd+FsJ<&(=nGB$>U9xZT` z413>Z!6_1Q@bH5Y^{4V1Gr35C}WHO`uP<6fjkraBNJ!CX@<;a59j1*#V!YY{~3d`gt=|WwP0+{^~X{ zW_1C8pDRu^1j~)3t*z4FO2bGRki7OlnA~e&MKgsk&w*5#k$}hZb$R6(fUm-qXA>U? zb&As&(FX`2s;n`6Jm;SgayZ&ESUK^yh-&UGf>>vzg=*i9D9YNZ3KJZTqnYoo^1F+s zQ!iVO&*H9pjt>4e|MbczI0<>@j*%CkkdOtuGW@L?=w%1$tVrIdEm z!ahI$JrM9H)4FUpn6(014Nszsdb35}b*!eoz@6gQQoi06zBt`WdnWh|K}iDPO&cof z{SJ?K4_(uH`b>i5ULw12Ed9JAX3iVCHXA+8$ouw9J%G zgn8&=Q`dV-ueGbC~d-ck%04jrcWiNRAtfCoQVUzY> zRs-8*t{3BXM@2ZI*LoevRt^S~tz~@@grVv0bO1JQJEluMCXYGWT1!@)@b#%7mBGEF z{~Cm8Sw2+_zyJOq@AxKg@VAZoi39CBX8z(Iylhg?B{3z?MutLWAB_KCAkzb7m#N`o$ zfoKU_bmuBs;OrcTn2Df8&*#<&j7vDywoV@gZdAdS#Yb>`tM3bkn$>B$8*UNNeZiQ; zw!O0`K6l+_?Ey`aufgoapQvGF7AG3{vtd&t6Fy=(Z98s!?6GdbgYU9jtyt0Ip&1xU z!t;$hZ8KGYuxQxFr;N}gMqAu#ofZ_Q7X>S~Tw|K{UD2_D(DcFbC1s2&w=Mu>)Gb}K zgD((z8ffB8MuC5x@;q)sNu21qobVPUxB6wmY{@&2$9i&%5rVlQqkjVXn#9h48<2i@ zt^`M1NMHVHoNR=s1UOsW*E%!t1A1EBVYPb)&BQ+8p zTg+fd)r95hShb6gyT8=Gs0yLR$Uqv7O0Ajgh+^HITfkMZiCKXecV2L-Am|sBPm7EM zrx`5g?P^x2Ups#FAVj>Nih z>*CwX2xiF@<#Dbo7`jh;M+0)XI(}h&ooQJ{p(hS=tJD9Qr5H~)v$h*gWZqizz6A$dCh>`Q_VY{?NY;iO$w79fdi`j{uw*LY! ztA2V%2v%T5jW_sel}V~l#=3oDUtx12I6J-}iuB>29%x$6%}r)0}JOvMvWL z)D&U$?ctq4Oo(M+7tB4BAn~$*e^j?{f7L)hmVCGqL8Hrq`ymx%zIy>)t3}B{u*}j% zKKH^Fth3q(yh*~cIY00*?IZ*mqcBVLU7$&Zg6q{GyZVZb*qmW@)=WX}ambW-mA>tm z*-*s`*u7`BQQ!-@p7zCF>pjQ7Vp+GV2rip2^XVQ8miuJ?GYQAPr(^b$WZI=T*JzoF zv-Zjl2^h=CUjxD!St-6mD5+luvyie?0`D2O14c+ak;m89%AOrk#(PfO<%?!KWmDbia)!Bnlwb<5%`j8Xt-H(U$o$|eWT6QfwN1lxL^~88jYz&RAL`@;x|@S zj;<*}sLn5sr4aB~M@o&)YV8`*EDgsKRfd|U5Fj6ZyPsq-;Jj!zzkG}%#Qw6JwVPh1 z(M;CUKPnQyeNx0k-&L(1QaK@Woq>?wQZ!STg#D3N_7%Is%5h1vX z?PBM_G16CnIHjZg%MmqL_iePCZ+xZYFJfmwn|Emm^h9>UbWC|6dc9p{nPFYtQjl>v zuW)d>tOwO#si=^4J43R?6K(^OE7&phFvs!{`DU{EY49Esr-u;#w9m=M|C?9ULE&x~;>UN= zsh#XpOJ-Re{a^I5wYbiK)Ht8GIq>=+&J=S+Cse>oGWM492UX>?y7Cq}D`gfA6>2C+}_6}3c7}8FG z@REnd+~xw~^LFoZIfZWSCoc^uV!U!g5rCDKH3qR>Hjz(bLQIPwjn^-7QzAmeOlk6Y zp&jcIa&K(Q5Jj5s(7KB6qt#hFhT};}lYqTh6GF0wegDK7M%1&*GE5%BRSZK|nD=L@ z7CyO6EfM2sCyLz2En?Dvv6LD07`Rf_NmGLKcA<|#GW>IANmU+5Sv#MsmxEn#H&#m` znz!y$h8_Ip+LC_6v|F}^QoYg}USw#qvN9X5oZ^R1HHLhu0L|__7mg@&PVuI0LcLIg z#%EU8)L>7{MNS%BfppxK*ZQ|s{d=m!)iUYtzXTp`;)c+c(bO*NXad98so7^l2* zs<(e5^Ng!Bx#z09v>rtxA|? ze6z@~X(P?j+Awwl8UDdyxgFijz+e>C&zpDW~iS*8?Q@@gr0j`b=+rqQ*P~c_xdGmhWO0Rm+Pq=zB&iW=tIJV2(fsI4RFmC_~ z)(XErK-WsXXR!vO4ZUcHoJ;yOcy5o932q1_vIFo;{1~Ia9ZwAwaMx3F4^->iZw3Zx z!o1oa!C3nnLLq3!l)H@s=<;Hkc_Nmf=i&n_`xDDdKEI>JN8k-y<(k1=UYf_5Rn4Ct zPh^&oKDi>J5o8$n9EQ@8RIXc7IRuxy%qeRr_@BH&iTzec9|i3EB8Bvk zemCGGMG=S30w!SBI1m4VS=FJUDG^&r@Y^^p9J!U<{Potj?o}dHV>r-Q^iqgYo@boB zb}1RDEz8)qG+mdWc6&qxXm1W_l4ED2l5+Uc*DZmvCosMAhY5d;!Z7S zeRmFGhyt7H#>eA`4Yi+XwE9Or|$e`7KOriezS zM51kWGU2{3dO|3mXEhRBR_4V&^1Tdn7g7c^ZWm%X#A>-~7bw}9M~>?X zkgEy4lpaFca+)BUTxU7LvYM<45$tX;)9_pu0S@Aq@+V>}m#Ox>aP57PHoCzNeZeyr z0z{f<8hJyO$ZLC4`T8Z%;-+@wtA&C#b+-6owNY<(0s#!V@h>e&P+l{NJgUzkQ0@~F zp^KydE$HxWgg65yXH76C(Fot!qk9qhmpWmTL-DT_Jc2DgT)>mT;% zd}m{$91cxPBjeT=vIcqh;Xz!kQa^H~G2j=Cn(C6g!j_jx!bmkJ55_~cE+C`E2e7g2 z0}y4@R^5JEF)CBqw0dDvcYLDa_`Bw#jr>_LUC|w_SAEm?rLEcO$g(*x&b~_nnb-)q zp~^_DvSVL2VM-cAnsA)(eCePXSYPOKRA)^VBo)2WRCaXDQJ4!h8oNM>;PD>Ua+Pv_ zyt6`AF`pZHg)z*0EUOb=yoH}>4H9jUNDukjLI;`FVZ-miCS`twrThf?REsR~=RI9Y zXdTzF)d$AD(aI!k^B8}QMU8FgvK*O*>i-b8cC@!cNqec;sFbv-XfbL@f4QPfdodny zqw#(YT0{&ai8p~htdYRlqX)pl1@8zAejZpsfUgyQ>XqKg-zEtX$SjJ8R|CZJG-Nsu zpP(tR{0fK%-Cx78W{f2w;kY$(=l39Y+j7?yN0U^w0pADg`r?hlyW@9#VS4++S;51P z_@5rlawXlA5IkV%UdVxbPaz+Q!eoF6Dy~Z zFdH!f{CuH;)pJCwmxfI7b2QX0LGW)SdlBULvcZ4yZA3I%XS#m zk;5f75b0dLDI$ytmBr1K@Ut8U$;cAEm^C;)$GEYIRh2S=w5`krDej;VxU1R5u-w)J z6?yB2q^BIJpCco@oAlJj|H~JF8Y-bfD{YSJFuWj;b$Q>|o-xX8p4WG<&tuIi#SwiO zXF4JY1rk6Jt{Jmw+mR>@-EE72h|U6qfq02qhz-A4#7rjc$jt{&`62(9mX`^SW&31& z5yBCoLy}g{bdM(}(pud3x!_Y(phbKlIaMfNxX6ZxR>RO>f;6fdtR4D6*mmn22Xngj zlobn;%h20aGsuaH8vDS}d%Al5CO6#alOW z^B+%G-n?%|MB5{4m($Wn@3G@ag0ESb&9)*8#9syoPaN%$Zq@lXRKriV(t|Zganf21 zH9*5jlsW;U_=z;O%a&)%5-<6(AmRAAe1$(pSJZl0qJo=Nc%MeXM0e-h=ck0H)j*ck z@~#DBq9}Aa{zpbLf)EWod~Ak}M=IIL^D<7Oj!%ALcdPkH`YP9I(A4)3yQGlS@Lgsg zcb2;|KKDn;Rb7gV_?S&K<<7t|5{1IA6Z9)Yy~5Z^3e+wD+NtYz%`uVo^nM6)3hDY z2Drpbhp~T#bQ2ZR-)m@+<9dYeH~mAIzSlNTdyDDe~z0kKl5`8_bf6(Vxfn_lf~A=p_c}Y zepSSM3-}9~3uAzyy$`Bfhs0}__ep-5blzbRmb&M>uON)gKntP?>AfjZO_4tgcHt+9 zBCrpb1D`^1RV=re+r~dtTIdnD`z8Cn2Z8jv(fhLiBU*;&0p<}p>$eFH8NX-)BAPR& zg$y7Y$Csh^BRO1q2)WWHu?H~ROsWBJ0O}#ze~i}n9XG@iWhK8L@j5=HQ-a!$$9;74GLz4t&WUv6@x0aTd zEb$bw7K27V?uB=^RG##5&`h#iY?x(Y>J+IZlP9I@3Zhua%ekdr>2gyNa@@+etGPj4 z%Hot4z&xHCo}pPHdfT5^rUfo)U*C4=ESx+XkM3qfGi>^0Wej2C0!;NqnQ%$yFS@o@ zSI2(HXhtB?YCRK;4&hjoer#U~yjs=eO>sj6{L@8~CvzNpbK4!`?(f|4ws}I3K8$f+ z4r>iqDwFiB{<^66ldpKbABHZeN*c-7dU%YrT}uZ4w+7jhM|G*pnwCIr;L3^V{LeMIS$9sisraAC?#vt8dm>_V62~y4X>dj1lG9Io6ngYuVH36DGrM z__~9cHZ^-2=hIcY6Gw%qYkBCn-KR%1W*v&|fZO<(thBfnss4az`|%fm(3)}6)SJm2`9b|7_E_Z2xw5L(SmeXp z?dxGdWtBLyANb9s>D`hA{E_X)l#mh*m03nvZNN;e#1C^WR*r0ywz~vcQQT44qeGX~ z(UV}}(wwh#<}$9c#ir(z;bp_^jG$5_SdjGQZ*qt$ydg%0^HbQW zIYQ28?5BqB3*5)|N+;gzfvM0wU6}*;?B|7N<&Bgs;AMgTYN%@QIx%`w_==PXwguGs=i?W&0HVP#M9w;`I%AAdU zQ9GBl`1E3e&jZ47nV3KGqLm%T8VLxN9r0~{a1W(5iK@5XF61eGuB`!W>W``~Aoj`0 z3Npe`6jCfjd~1u0wusJ<7@BzIWftX#BNrL7NSwcfGBWX$XOn2@@)uPk8rec!E!LGE zr+SPUfA&TjA^@3O{m`&~gY1}LXu-CSKY*2<56aPg3sZ8K_uLojBdXo)-kn>% zI`9$_YGe_lq7||~7U2r@s;b^Ma<)6}^;~;P#6nu(vf`z3|7E?tvYpa66TFrVxue2} z+MBcsj!r;vR=O4Jo`9|fR~8|M5=n+bBiYGf@H9}~uuF1eWOl_8*zn_478iG)#geEh zpWA@$N9_bNBu3oLd-fs)@y(Mbgrt7FWFR~eVM|jkr^qa5&m#$KAxf~SQ`u5*c}C;z z`PH)o{?o4U=NY?*bN3FC%vL`Wk3`Fa*YPd&)zumI$zxq2JfdD-Tj=~OCCi~(n91nw z@RdKr)Di;hl8gOR_@ z>LO7dw`N9mEOVb<(?5PNX&iL0DY^ zmituceD)1w6u9imTY)lk4}ZIZ6({P)xUciW;V$6Uwy2o;A%kjAHUQq6zw-?e@+Ldz zdOy;|Ly=jM&4i8@PIH7|f4%OjBZKIA8x|;kTVbOtwif9i%{JV2v``avU7Y5KW7}9avcf9l;Rg4_dS%~_&Yz( z8`S-6b7g%ADYg(<<8RMGyN8~>;59x)nqVx^`A3%A=MEQh(QsBJ+LfP2{St1+rw}p*LXqfo zkNFj@zfy*H5V}3{E}c=~r;g9PLL2H8+XKJMmdCv|<@KU>-lR${TJO1=(QzM$>M1FC zL@w(Js6=+}n+9tyKEcXl^eGrU)sk`&D|{_21;wW%7d8Nxz6IsMLfDN?F}Tf9WJBw0 z;@Jwu`ch%2pL9PT3Rqp#Wat=RcNX#$xcBySI-wz8Z>7BR%s=9eXU|5igYTZE?@+-)LAq<$QsRAhiH@gN_qZ4WzcK@Cr^&^1X2oTYUt0{ zf9p&deOKNM-=yUkqk(Vi^PG&Fn!0?iqC)9o%-i_0MpsjFB z0rGR*jET=*NJ7s|F6-gwaM!w*XdygKn%ZLeRTbqLZYN^4VJVUWyB@q_d#QKMTt2!L z#(imERlkMP%fB^J$z#!4S16{~+5;%iS{a_`iPcy#(}mUyZI66V$dOCiSjv;~T|1NLBtNVu0>$xZ5qT%hW`pSwWVUzY`ydR3Ra1nJirh75fly%7>xI>rm5jBYBC%$MH~5Fdx%#QFrco_gIP?%I8E&94+7yhH zWPAR&^GYhiZ+=DT(Zif5Sm1tJWESy`TCH~~$CnC=8^WuhzSir$ej68r%7_Jh@rhrJ&!_-M%%NW5k}w@62Db2by<@?F@|jMOS<{_=y2w#_A?W*URs;|2wYc z02U=D#win197cEu{eyH#F#0bZM_Pu{@o_;;Tj=qn$a(q^!h%7$NARn5T>Q!_RVt8r zd2>yBdJieFswfDdrsdzs|N0R&P*;UafK)tfM{hslOa#=iL5hr44Mm;PW(eba^qMyV ze0ys?AA#rWJ+ua!xa5@COL$_fJV!p>`?2{j%`8!IHl%%Qn97f8h-oXN)2kU2pyW^Q zTE-PB{nM9ZI2~K(T(CA6)S>2I>NdB#05PZj%zu%h_Hr=@;x5!s9cH#Vpi^Pb;GnAJzZK+F7kQnMZPo5)1B!p z1vsufI3Eob+po7?5@MzE1oHC7PW|-Lx{v>%7Bl#_TFk}mf2zg)SG>C5fAi}4-Tciu zO9j4v$vArFzrr)`>slGfufK8Sdhup2mB;^V{(e#Jy}R(5Ek7Iow)Wcd-wx)8Z8~rK zb$IoSpAW6rv~lH2!b$nO&cM+8@5K@^+OR;R&>65TS?zV1ETY>U7EpfXsdT~ z_q1QjVMqNQ#_e9UjajlzZ;M!WphTGG^$2My%a^xTD3I9Z!?WFQ^Z7F?IXd$0^*4^@ z6yqqHzJ>$x3Kv}7hL7l~-FCEde_c%`#FZ|rE!`(;y5Uz1^6c|3lhiR&d9uCw`}8bl zgZUbw*!|<`2TPZ#O16K!m&xdRzSyF+Ibh(}YT2Nj?k7Vo+*{F*G2s5@eeLB~UrrhC zfq)iavXm5)S#t6v@z&#=h2()WRj+ei>DTfn0v>qpvvzhEnC>tejSF*Jdn1iwXT*GO z66!rFEnHhRZr#cW4qur@b=zf0EU~CHT6zZd+kDw2O}>x(&TW#aYkvHVpwfI~vu-DI zN@#2S-O7O3Q|H*JPyCsi1guVL#K+9;s!Z0sP`|Q+t-HZ_i}!M|)Uj%5)jKizfk(fx zFWVkcJMU>Mcx3s*eZqClp}Q+;{^{P;t!&kB=f~Tw)FQZ)ky-|I**$i9Ti^LUWB=ZF zjr-YGkbYt_D0YU^=VD8K4c#sK7iU>gC4b1jXysu;-xGgPT=TjLrVOk-nKxGEP{ZzU zr?kX+G)^50KcTSa9Em+^Fn_gt`<8Fo_QtluJzw)3#a0jb?a;ERjwDWSsm#}6Px`nE z@y{+A`RyslJ!mZ-Iv79YbBou%X^mCCaeZp_?1N+4O8S3xuj!;}QjM)eX!F~x$)8%T z4IXTk<~@0TvxrQ3eP+*-(iNP+sfY6_B`@xn%5^ZM2DiMwTdCB3e8Th8nYU&GZnpMHvydg@cJq4?=lSxL#@&0Bstg3qknjy|`O?E9LQCe3!JGWBpd7M@e9 zHXruf^0L6F8AUVS~z7s4p)+08L(quUG{bb?}(wI$lw2KOl=dmDQN`6fJ zEa&?9{TksDolj>It|QlC83Mb((b>u`_;1uhZwQ9azH&$?L`nJ~t6<9_b zAT{1dA=5uq+uACH=2>>%tv_OV%((EOz1GRVwwr&88L0&~9uT~LO7eC|@PoHsLtC~Q zJ?m|Juiky#)^34g`S@w`-%7w8{FHWLp9Mv~`S!<=v&%-?T10jzZTCJD zxq>rgZE{;oGA)>7L(rAD#9LTyB_1u{$Pzivu9nr@{vdcs-*4}OXQZAh+~}Ci2D|(0 z-+UbvU2U*#c}LjC7`DMgp5@TWi2Rw=-e<=K)`o|L>7V0HD@#7ptlPiwZMV{vmZ=?g zqg4mbzB%{&%3TV1hfST=oq;Gqza8so=`l5j)OG(}%lw_Y#&1t=otpB7fbC(No@>Wa zoDa;d@ooOAg`i8FTW%2S;`ntiEImpp3ujU+$KzC4tK-V29sO3K?R&-OqRNMgtYCDb24>o)y%Zaa!x>fBJ%pf!f~TeY#x>RN(XI%TLC+ zk#?-M)R5)L9g>#_K582!a@b9_Y>r}m#iZKmfjY+iJrgA3KPl|QnziA%>(uD8rE%Wh zmKE!7QOVC=$Pebly&tO1a39`t-hRuTVtL&^TkblAZ4tF{JfIpRJKB5lfSUG{#Tx41 zB2i^y-I~AVt0`3H4xs_kl#WS@P-ei<7!Ec6tnh-QMq|FcreEl)N`JY~56ibU1mr!b zDn7H@`iznM)*AbYw)vvVFyGBgk2pVvu8~!3^|2|-=`hHhSm`=g2h;(TI zHASz=bt8=6op+faD0kpR`_A#N;R)pJwZ-akl3zk7HiAOh*M!R z)hQC+!Y=hy&l!$+b!_(>?7MQ}P>7(+u3f%&TD1D3-@a|P)cf0B!$I6i+5OfHF@n+T zt3yMt*IJB4o0b}CtSMc-`>(J#vfsrs=i1H+Z>HF-x+TUE2 zeC=1k7CVk?eVnp{k+yb7##LV%9?zZEMC}MEpVQbd@BN-c_|ohuZ0kQ~D>%+D8`9A% zx^Oo#_#$JKfaD3@n`=(-VuBL6t`4uhFx6DV7@aw>Bqh%E(29#+q>t^Yn7Jhx+oDNG zntv~p*mF{1fTJ$hBBG-FdCGR1G~sz}Y2>ogiPDu#Dgj@cU4%aDqE(+H^+X6}c2imI z^n(l@Ifho91ho@cypnR;7~#lb6?|s0Rs+POcdsqbmbBd3>-Ij*73l;xhIcM!w8qXMhXy*{&2jkUB-Fozc? zELuLVzs;(f!j4vJrNv~hOEPYOS}754Ew(y9LNwO1|7m~fjC1(Pso;e_MIVYs$LoJ( z{Jt|%%-ik$3Sq5N)_W$@2X3BqT_apev)Ho7ME&%iP+)%TPxTdfSQ+_q(H zZzF4yEiUm|wT+W^qZX-^qd5DCUTo z_X4*`knX;~iHcY5Jg_<0@Xo=JS+#s#_hreo@k?SUPmsrqz?O>SI6Y_i0E}~1= z^E|35{_cls(sqF-$hNoh)Xo`uc`8-RIY987goRqrmC$d~L$zm~Pj|^UntZoqOu+A3-I#PJ3#4b1E(=>0Z`Y_vp0G6O-Jb zpzB?ns+gmmF8%-dFwWFxfBNcaow(W{cik>)g+Cp3Y^~qLBeup_#8&Q&mzEl|di7!^W9Hl* zCVR48XOm(*Lv+v0w@VJHCyg$Bb9{S}xH|NQr*IXXLVxwGd%}g$m19%EN7rus)>?I9 z)N5i>He2qo!|L2Ry}tL3r86ojXLbjCy!uhN&S1ivBNaO1*Q2sg;a?}1>7$aj_q{*6 z=KImu?Ao$bV%Aah#r$+;w4{ z+EtoEsnnO$9V>s$YyM+yM&exT_`yHFyn4WtapXB?+!FIN@;I>9<+o5S*Zhfws>>fz ztDoI{Kc4H}d}iTm-?}Yd8D5VxW^=8K#KFU{X(MCX-hU*k?n~8Z8Q(+v9Og6q z+F9=F^}L}2KYWxkg8lpYs%M1d&h>Z`lk61jANQ#W8i;GU=`bpzHZYkEpX&@*sz1;D zBm|t%qyMHzIVq5yAPQkW^JaPGmb3(On7bhJ?7!wK8fk* zMO}6p_iv>`|NV!;_;O3P&G6&@{pAw5#zDE4} z*F%X(si_~oiZ$*L#-o>ZaQ`6;|Bo*f)ivx>-&X|xB=Jh%|L==Ovj9;sCdUxyqrm@| zAN`+J{rCL%_y5oN`QMx}uk(P(>L7cvr$umCL-C!9hxRbJH+m@LDSEi2RyWJ?nr%56+9fk`G zLqK=3-@1^V1#mC%G>vUWzjqiGMNDO?`!ATfKO?(3bIjZ_X*#~5AQycB!HCjf*r~Q) znm(A69`u}(W&30#hD>^DLh{gOv@K@#9!{3XUI6PyAE+D=5QSd5k+P5112kklHGaQs zppTiVSIN+4)Hf44Z!C~IwH7IUTdvv0PX&S*Eq|K~w3YGY-U0sCZ9?I%BAlg`O11{bQi67K+74^@wC>YhuU z`do;ChAQOkXhd?J|rDoQ<8avmGZ- zW-^mv2|g#O$2AumDgi<&(`QaDcbEwQqf{M$>3Yt2k-?-fNml}AK}gD3Fdg_AD5Hsv zXy1G^qQVEi4Im~BYGzq9KCW>*@HprueJuxEMM=Q?YG|Av)1lY@Pw zsexi(B$*IO;%C@=gq9@ON=3x%=!0z2bzO$O1Xogav^0UhGaBgOBaoaX2UlZ(Y||i^ zl>pXNhQ$=eA_=9l_uz+&`fTYef6C#7lYVlQ?`Q!SN#H+r-tm9$ykLv}x%2*aV5ArS z1|tpl1)FwC)Xp^*9_!nuvEty(-J;jl9_*?#Sl_d4{cc4^X`N>)4;{Gqd%ZY8<)16N zMNKYW&CfLY?Ki#D^w=JovR&0dDKxR=aZY`XJ8LpNCMl_p{&Z9@*C^d_9XVsSc1Y@I zowT!Zwt)P8qny`{(?x$s{VBAKOp$%-y}FpXUrEQZSFA+0Ym3HFOZDu8%iYp`hb_yj zJ7hL8GU@cm_KL}ONMw4(mK&jeT3*SwJG%m74ewR;>_YdI^0j(sJv+Eb6y;&!`)S1} zay&=MMH0h4n#6B&5wXP!kxpYTubp&L%a}A&rDzS1zafCSZs6j-5TEQV&?Y|CWuBYO zf!wXXb{pEVL|9((LNTtuiQv+oFbp*g;{e@R8 zNpVQTS(RM`*Wyz`UF1i@9cvO(l&fql)%ztpAY<&@l7u1`mm(DCWl=0C&Is(zWeM|% z2Z27L%PuFroNu(VT0VA6jg%$+i9&*){{6%1%vAEt?Z5b>l83peWV~h zwep;yBZNo;uGbb;)?3AA|AP2|XpfF9hHrNujlt?AX`q|BT-BH1OK5EL@Ol1y)I^lV zT8f~tQCH##lzCruCzAMmnAOq1e%}RC7@N$ys@>2es$ct+0iJ=LllRU0>j7C3bZ{~i9i8h0`mox}b;rT|Ni^fF#AS|U?V1in@Yu;T5f3ONe0G7yVV$geZrJnLhL_Ywd63W69w+)UB)~-;XJX$JO~e) zwi@mzsnkNjS4svGNt3^|J+YFdm3WqPQ@d%wCalpsgX-|Qw0W1)AQbBx~AZ6*&x zN0Jot$HGvxJKd+yiBx4uy#(6pod~9)K30{YgC2~%H@v$cJTYy`O`&dP%jNBbXA%MT9EfL zU);)pD8v5mzFlZVJ>&lZvaXL&lp5ykBMVnVtCe*L$~AwD1Rr(@pldf%V(;!G2Jne* zyjVl-uv|7F412Glj+|jUE$sXqkr_1m839Y`;o01k z+#%oFnQExhNIqg+LdH6wB%VeAaj9R!7AQN?sq9w6$}BDs8*Dr{J#vm+x%h=X__3Db zQvdDO0Z$Z$KhCP@;oG_`!U|C(6y@BUd{{Pb-@jL3<-H2RiDbR@ioI z6Ocs;CrgkvEggLW!|8Y0)|75Kn><9SiLB%Tsar(H`mTpCXI4So_FB>r!PEEn z&$g8`4qfb4FBgc%9S`4tdZcU3N0huz3!C1LpjfJl^g*CD(6`MTMaPVeM;|e*nb)`m zz<4BRrfx>jV`5l2xJSmXJmdMp4cerj9(;$3-(>caj5cd?1jdETgq~hHnnEx#H7wU8J-R;` zI?7yGG&2xQ6G#s^{T^rk_%}ZvRLN2aE?6a6``u;mqPHS5TPX%vD(1~(r$`A~%Vo{_ zHzb>6kXyvRA9*u0%$7YqJypmDxv(cKfg~F6*7y}TD`WjCJlqM5%cu#joVS7y!H-h1 z9o6}#Ary|2CfcLhq^xWCLxP-UuYNO*hff?8SfxZ?3SL&UauVmW?{O~(o7m%?B-ErY z1J!_il`d?HaspoOC)63q<%Nh6Myk8D|FH`nS8%lGJFQ8QUc)^{QO43XKKWmeAULbaMl(%=s*6=&NJgq< zu-Z}zT>0<%HX#?&TBm58yBYi8!E+CYd>f-O1jq}2J1la*4w=ejk@(iIog6Z_hh(**vAB+!&I!>`6 z_&}qs>1M%g5BREk-kHFsOI*DeHX(p}L@w9u15MR+J7Lqfr(RI^`m?rWZEC?EVPVQL z#Xd{Kk{#{S$b87e{ek&fH2?f_;jp@yowKE`?|0#xM)u>P*WG ziow_X*6su~XwbI@e`2g>o8;goM)~U>2DvDvyE}qUp9!eg!YOQ3%l`|sEDj^A@{g)& z#ihB-q<0KcYrUB~%q&$m6%{(Jp84+W7N|KaU`NtzhFLE*pY|qLg7|np$Mvw z$#m=0xm&0i5ewPaVp-p~$!Tu+iS!!VnT;*FTRS-=-A4f{tI`MnEpO-i5DGDJY~A6* zR$iUKadvs@BAA{*6W5es_>P5{V$TZ_w<;Z@%f|GPJ{_UUC}oyJqoKV2gCO{(1EdgL zuaJqN*K<@74vL>gBdCYV+N>#@)o}BsNqXThFnyaB>sYBXD>kWyvrPl5sSj>K1TOe< z&+XvqZpruv%u}LTpf=Wa-o6>2IcBOa8LUMSRDx+PAT+By-=RNe(NsKyfxT|Qo3TkQ zD6>(=R6c8~DIrs7H{b@DLGf&~CUl=M-WpWAcF#B&a)JEMpG#E#4|DGs)@0W8eUCco zs3>Ct>0<>!h=PFBs3<6iQ9zIy3lZrey(Ky*h%_0%j37irq=ObWTXWM zAwqzV{;YW2*Lz&Y^}f$>+#laBA{sXP+~?kF@4eQ4{T2)}pW3E+61mmzxjNXY=lv~k zU{qz&LZE+>Z9ArOF4kGWfw9Jhh6I=df00Cmw|tB)eFm&)_h6bTXddlr#G$aE$B8h= zxg_ISi%)|*hMcJZorAl{bdL1^x*jrCNT|bauZU73-fM2A5vpr=T$5N3*XfN2b^1X_ zr&q^!1AA}Rw~@M~wav~zZaQbZFMkxa6;?vLP!4oyJ;VM`Mp;`?7Bow#C4Qiv#0SJf zPEx;nDF}tg*mK)qA$QeEK>tD|+D_K1yL#*>t~{(^rluE(wfo^110pGZVPe%z$f&Ww z?t-Lr;(Iqx_n+|zz`!mUI)IDC&K3syz`=qWQERni>D_Cu32!$*`&%3qW096gJzJu# zG2Hcae|Y_4)QRB#wtRAkwCuO2^P7K%BXM zsgPH}u8({RJOc)9`|~3qDN<(n_Fqvm0qwpOWEp)$b+rnqD;sFb3!cCYmf8Zs=ml~3a$Sf3mieIBoinsKBX8; zge(*mBG5**#7Sl(d%hW3{Gwq2x8{IRDG*bWu1fy_T|KTKd=n31R($A68eBgrGg%bi z?pV-S-)E|)ZAMvxGLSzNyXuYvfX%~%&)lu>!bAB?5bz?Wj{%f}w@mPYK}9+hflke! zXm%I`(i*wLIie<0-$PF5XtfOCIzavC^Qoc(?`Y4%a+s1?CjGzy;?-PV~w1g?JBLsO`M#HWPXeZ+>n$mUfko}hMrk5wvGiz!)Pia;cq3d ztJae!;MKK;noxEPd^(OXez(CO&d~f>{nY5yER(G2dR&3HsJtj|zS}(*YLIi03VQ(P z)mS_AEOBhX%#&sKI1YHCiAcjnu$RNc>IlfFVGO%S5)Z?ET}t3v11Y2Kq5J2BOQ0v@ zTFX+7V+3=RA#hLTPHw~EARQv5A!UWIgK3c(Y8*gNhPId1oUe!DI+qa;u?3FArRGQn zczJS8w27@>QFXgHXAV4qb@gUK8SEQlYrzrVg4|I^rbSI9C>$6_uwsR(hu1DJ>$Fzm zhEE-XJ`eY$y6|eN)yKGmR;V>Uyu4lbn1G%MBCeW)b<&cPJ1~{GL}WW}5ha(E+pFxS zFv?k}#h;jXb^et#9h7ADW!fEqv44Fdpua3P3~!!f%V=uTlsYN58>g2Sd2vH(lHYme zGeK6HU@x!4DZ=(%caWGw^|tVw)h=p%jGZ)a;RgT=55pOM+8oOUk!wZgj@acFm&uHw zs!jCIJl8jQ9#;_{rpJ1Zbl-<8?HfOywW1#_8+lTvMsy)9U+z4&RZbGb$eWWQGqmPW zGyZ2i>Xo3wGWOIykr@qpUr(IA^12ySfI9_qBSf?25Llo2z!g_M9)K&mXBCa&7&*sn z?7y``mf#tJ35x_Z+x2W;-?s;s(#I%dEjWHu0_VO!!hcAS%6{c&tldio#;u4rZjRkp z!!7qzkkVpT+j@XdFolotYftO&OiRr_ge!St~56S zt>%;fi`G=MoeUQU%&&CL)g{XkcKV-6Ur}bY3%7CFU~PBc^p5!z0JbOXqgo73977Cd z0e&fOzB1?5rBGNZ@)w>dLMqZ6@v;Oh%DAkUxRn+)v~5}?E_lYYx$nBT9hjn!(l;S8 zFgfm1deX`82SqUatlx9!Hb z1Npu1u;CxW9E4U=2ah)`qw={$(h)R5>kG4-JA6ym6_tnZ%_BSX7$>K@Vq610r+cvz zK9{ZHgDA!+8w9i9W48O|aDii@-j=QW4MIx814IHiwe$?W+mBQGa_1|r2~3)r(K5SO zKW?o9SX^pP(4)T-)L)Ky>&U?c#nX4{YZ1V{d}{rs)gZNs!-$AK2Hz)XhJ3w#3}^Sz zDx7Tv!#tny=!*oS+46PZ0*EKuho!i?K^0ADBj>=Wc>`UW^*eYkIPbmh!u4$X!NB+` z(D%|=hm(xKc$_F(-jz|GOB>qi4zD|dx`zCji7$OX$rNR?1e(b0WGIGvhK!HGHJEAr zs{_<6W~BwGf*0;~sE9kB8Hl?BKEg9jj&OCbr!N9y;YKPj*k`Nt{lG`4=syZ6`{?UY zn*n|iSSM`3raHNP)}GD@?y*O}xUginV;g{L&IyQsOvG^;7uX|zoxA{tD^;!mq}RM< zT9^QnY>;;r`u3`F9&?id1(*1^W6jc}ao@!XUR8-+0nrvS$lhA;XGu)eeR-{?Xa zb;^3iVWpk^iI?P?4u1>*F1Kz4RvJ!Jy2qGsqM~+q0YeDEkJ)w#%)07#rZdkVQC+nX zW4XXoVsf6lgK~R*pyWEhxnAh_Lb83N{6!8pa`lS@fH4{_QKW>6QW1HH^63ZV>w9`li??8eE-4R1lF&8-wa$Xor*eo z;NA0wE=)u6&n|u^q>yx(rx-(G5rtO)hFfd-x-3xL9_|P9TX~L;B((Oh!3^@RqbIQv zEL6E(#Az?UYsb~a*CQ;ZQXKBlDy>-Vr8@?^Q%>!FcZY8+RlT^*q5euF+994+X*w+a z^*y%0?}$?jd^51Zgm0Ffhunv6C`IYzvB9%eH8=fx0lnhhvyqWwGqv6^;S*4V(DeN? znvDyD4O{P+d;AeEJnko;eur$D@6F<>G$k0hl_Fan(bPtFs&B^91V(OXB(MlJT&KJXx zGR}Sqa06}eT$n@U0ydn_JNHsxCQ`BsZe-~8d6`^E;x7d^J@JE=jUJg(34z8^wl%_P zDQ848a>UZ#tOuZrHxmwnlg{l}eJAB|+MV6>U)dTm!5P6SMa{6Ik~ zIg<7*V3o36sN6*cA{U|N67(E=NnCH20xQVzB+eDg{*4TOt9kx;iJKK`i>tw}w5Sbz z=%*1toQ`^Bz8yM=aCL=zg7#J4p`sgn%VyTNBpohw)e?ooo%{Qd%N{y5-`~K*44lY0 z<0G`v#0z@P~B! zZ}I#VuV{9U-DZ+kKb2S`e)8To1kal;+<8Ctl4} zD)cJLG7);U9Gu+&=37Be72;W{zj48RL~p9zdP1N=&`}A1SVj2AZ&dGA8_%SjV9?f; zq(c;Et7hFXK-Tl>5N2@Nm<{U(m+ZpVIiV<{fENx)A53yxC3MdBX$L5p@7M%LX8xm@Ln(IB7C_E^?6wy8(_BXud^0PIR)FXIOr($>Rw z>J@@lo6Cww!-8SZ%{`panOwyjJ_GU7!!hsFfAEZ#KeW?BVY?c!O9H-{*B3c>w<>&Y z0?g(R{6+B04oRMYGtUN_X=po!I4nZSg@jln19l-?7^K`U-kyGx1b6J`mn5kt5rqQd`V3fP)*99jbqgt9h2WEKc=uWn}ANU(JF zQbi1#JPLUAojVG-(6^|aQ1v11LV-QlxJR+Tf|$*JE&+4ntC=4}%KW1tG?*tLw3jQy zP3~m=RwZ!lh(M|AA$ZRr_p5rzDtHdF_jP!4bLwrDNw#NE?7SEb@fC*blgrM?qAuF!w@3c`&F_8 z?5Agl`yU+FiS`n3LCKvu4E~scvaO8f%OSIxwQxJ&{^0_S?V&!df^oF`yj!2|E%Y@HW8zY|WX zOxH=ULB$=jBb)e33uSBd<&$-2D$&gA=C-nan-at!H`@1y1~53*Q~)*R4Lbs&&&Ki; zKmxfTeshJ#yIWfW&}hr@PM{JJ4>{@AThiUgozBSc5tq#ZgJd1w$aE8A__L|Tdhxz> zDvEH_-8yrnIT9Q#*Kl3NrsRNEz-MoUWFimcD zKv|SH2i6pnTH$7e!_MF+I1fjnjKBI>V3_(kc_6w7$ewCDKb@1{74ie#gDX046K950 z6!?R87W!r<20Dej`V&xPz@w!n4}$k*sXD+o`r?TI{7npTQRFdoDBu7zRe9^oPl#CC z2Z$SmmF>M94cDeTCiN18jki>r?^Y1ev39-{MyS77PQD4DbGVb6A;L^)Y zx0(~a@SD>8fpyAm9{QDwyhOJ+c@{E(ed%L(114{KyyKycl2}+l2vYg))KEYN zbO9WIrQsuZc^p$_F3GfrOtIIzyri;U&m}5`twJ|ZDU(E(_>IoJISKBTjz z$;PRT;D#Ta$%^fOH|``~qHr+TIR zMZ)jPG2KMB1t|ysjou96zw|?gJRU%pdPC_xbZ$WL#3YCzqBJf5e|2uN{RAfmHU>OR zM8#m{!x_TW(WVw_WmoLgNHf7WU)%14RHl>iWkG^7Kj#Md@!YuwE8ry$6(+2QW0RiV z*aoN(vie0#7MDEO@3OdR6hpjvAOUG%aP78KFfa4-IE0?}WdEWb61VGOls-YvRINHM=cnR9Q>8$mYA>vmH( zBrlOZ#=%A4?({+^eBso(KEEn7<(4RTLC=^8Z)aeuQ?RvF00$xtg#tA7kW}a^HAr2* z{$n4+_TK%~1TrI4H(R?}`Cd_O_&tD>y#5lp5Q1_Y+#NrVW9n|v>kmt>&0Y_r2ksGz z5X|Jd!-qyy>O_RBboonrMM4Izx?@&L%J0;8;Zppv>2#Ej;6hxu%j?H16=MI=viWnQ zimHtJKRjF4x?@t*PE&60_c4B4HH3lpb`VnL$tHIMg-aQ@Sf)#U`p|wM*5p~Kr$4wB z`$u^cP-}&`gHJ`YAyGb4xV8PqUtSXfoPFW+G+bkfB>UST*dKl)ah3ZAr1R$a`ee_; zQ+qSYfZjf8NjU`mSh`h9^HpSP^5H9RR=QQ>slEvo-X9npj%XZnys`+XhANtHqgH2- z^Z}Ooc4rS*FbWR{tNtD2VIXhR&5Z57!7SI?#rN(r~x1r6f-vLCi7 z7B2~ab$X=+Qif#@3)qO%!@a~H9ytf1fvOb7$_s*BWn?kr_9hHfz=F}C z8$*OT^vX31^lVf*OC;NJQZohT@UHs08Hl0tBOD>PXHwbsGd2445L}oo-<|gdu|U>1 zzz6LHh-6@23W67<@-F_7_tII%-VRobG(a11#sC)I%N3$1(jTo^LXe zAL4Eu_{nYTand(*au4w?5=uZUBnNy3TfS_52pezRwFuzzqu94%zCj-I}S;Gs6X#mgODtZ{dP4 zig3$b4axT9bpm^Z?7LzGk+{*Vfz4n~iQTZgIhEOB5ZSfCf-a8#;)mY%ZS^#h3|5YTTg~tec!5 zVJ>H7+r>dtdPG_a1iVk2S+QiitSW^XY=&wIDpMsF)M`_d`(xBKu5X7u;9+VcRn$z9 z!SA%FRNjy?_{hzQb|<~T=4vYUKnXv(XTSdkUY^G6$I}p<&O-mg-(|`eS@ecMQLXU# zqyzvg(&eC9WepT%7gam8^auS*!COIgwQy75S|GT0yxIN|?V1<#9*#UipQ8ERDJv5G zqUjsX@rMPGkp33#;~_5e3*aZvvv5;|{y7o;3|7$yOxeNgOMcj~^G1d=P*Cy`*oPw& zIzQGXKm98@NEqGCx$Iaggi!a6C>B8}o!s+7uroWlRS zI6{!tX372@*6xyQDfoOvhtY`7yyS+!N@w7Y++ad1$g*Jc69DSzTdMKZZs}y&+@&x=01&aqOJ6gQ-D%#@-x>I_o#L=XlFU4V6p5{Q}`Ta|^#uh!~%=w#b{ z0$8Ujr$H%ju`U1v9f2h%s0kKQ|NN;)FVGX5kqF0lqofXV(4)3{7}QE~TpJYBd<;yp zpuJ6FJcxDI(3VajH5E~kRI}>t*=hq&;W=S9br6y}BAYK>=UWEiT}}`zLZU)zZiR`)DX>d{3d*Gl7gsx5@cT)#><=IF#@zZ6n=cA>*IX$e$1fGRSaLBm4wF8zd-OJ9c941cqv>_lN zq#U$=;g??ME@?lvK{84wU}TnxP;PrdG>Ia9Ij)T0nu({pez%DjGae%PQvW=YWjzI zS>pJdLc-6Z74|V4?lbO?9zYy;rDH7w86O;;g!q!U6c&1Cd+RcsUIO{w8bpEMgi5e| z^xSG?z?lXMCn7gP9JD!R6yWUZcVoT5tpgjm0z~2?ns>>cMQWDNdZB8>*epkHIwwH* z(!d^q5bvC`_dzVJm|S%>7VZue{CO7$;Z*p4UW77)wZi&YV6Mh`+DR?-taVow2;#v$ zKNnbvqQPC=j2MVZA*8~UFUlfa8)uTph@a75zB=dG!m??OyZ42sL4xf0S(eizTsu8? zk5*sR7n+v0ANCi;7Ws&kSQyf)>XXt?q5-=s1`i1*twy-Ojo83~cN1Vv1;gVT<>`Sp z3^D4UX#r7n=d@&iYgMZx6p2b|+1MZRdI=k`4269Ph-+L`na8wesp>ZuzYIa4hVy7Y zc!w;6f>Y<}s(VDu898q#L)4zc^3yUz+ZfNOQ^3(#5ld%y!p`ODaTRO`d2-!&qki&e zBm-Qc=gKL~!Z@}HgS)K=4*h$i7RC6-g&)!X!gRWw5IK}_KgQkK2&wf%0Wcr;YgrpW zHIHFSIx7(Z5)pFTZNZBvtoS$evx;3yhw*_ zFW23E)eu`!7r2ysLLMgiIgQkIiDqp$1i1=^LO{L6#871Wg-nhY=@Z!l?6u8ahAs_$?B~Dg28CY>J?dBF1^=CBLtj^~O z%-tYbr`Mxp2nQ2KlK+6q{l`=UpnB@A3;$WhtA85*uxx}8tgd^HJqPE;0Bd#Z=)eZN zI=zXPSLH~U0%gD|mWu(DP%*0bFa+|0h#2s$kzdoIL?T!WFXAYyFPby+04O(DWeHp< zR?cA!UdSW<_Tw0AugY76KaJu3GL{Cf{P;JgNeh_tn%Zey1FOJv-<~B5zIz_p7Wimk z0cA6OIq9%19Iffd2@mkTjP790eTHa~=Pc*3>2K+LnhbuaORcaCF1c)0Y&&aAc)ZT|oJD7O$q+*;dV7u8ciPp!t&Ru`J!SN z5eb>fn%Cg$lIh$+gO*#BzShF6*U2~L8SJhHM}w|}zJOI3?Q2pG?&KwNejq?tDK~UP z7B1W+#09Xi(+w40VCX~FdcrHcP4)#@v**T;AXq5xb@QO)nJ;WmIVm6fj) z1vPhe+}i`LQ{PCQgv&@hgoqoo5g-B|CS)2IgAHk37*c71uLC&30TZYLiRxc++X?rz z>u&P94#1otTPE&r{-H;<-E=B?>w}nvoD8$R?u|K&_Kh?IRE6Pam$s z9uEO;%!`1^GZ>JF)ma?sFi8pS!N;)1T_I3xgUt{rKW_5}FfyWO&3LEhPF6|mZ)!0@ z-2Ltf58)rMr8IXqvxS}6#lHPVd~l|yZtkj3QYl<#u>3Uu(w^Qa3~+?AMCHIvhB%aU z$=Z4Gr+=_#UpQzKPMP5^z>JxG=JMSKe65nl?GH_rl&SJsM7v6Je+dV6aQ_>9Kxhn^ ze;y3oM{|0QKt#=K&!`_Gfm*W32{3Hg=cM6o6`cI3fD&dGKC{<+(`oJ!9| zC5}HmGf$;ts9#%JI^Eiz$CWBg*J-$C9djglgb`Kn>*N?wwts~4e$CDFPs#3a8_!V( z6LP%*S!d1}%HuG~eV-J5GiH;h=F`X5Q&qXk<+`P!U)=sMRUy*wz_6e^Uh8XhQF6sv zT1la-aaGWFx6-jjopsAM5h*i2Q08cmE_W%d8Q<-Be9!3hq(1NTqfgRL1=4<;9#mgb zFeH}gP*Z9!>5DG@o@+BtKF1y_lZ~tm9}NBLQd6{Jm^2 zs?~@E|LJ4?q3}8DFiQ36$3!NRbRaYK<=L6F8Sa9;5vV?t=J&>0y%W29P5rNa3pdd5 zn!0qiojWPJTxiZcesu&>aBrYSP@?Q|M;~2;URLn^;YmfeCk)lk^0GPzvwRw-SfQ8A zRPYt-8n@f>JnGE+`E3Py;ph8B(27>~06nkcVlK$%a z#GH08Gq%K(d;86pZ^yOwyujp6|9a&tUf3PyS8F;ECr&rf!lfp|<7x+W3+u8|?j@2D zfB(49N7F3~4=p}ZY+ppk63-X90iNhf1&-cpGg&%GJ@xKUl3WBg;j1rWB-|LDEu8AWO`_e8w)Y6u@3!W+|C65qO7+0bnG&H9afygN$`=S%st z_`jX6kp+`qbT8;LeYd6Opfl$(Ru9gIIbC}(FTVP~h!u1P`6d0z_KEejV*a5+s20vh zylyFTbtgbVYK~8w3pxLUWcYiF7vXMeN2%9_(($>hIYQNk#JcXwhx}rE*ZXDIdY-Ju z#GWe0_Tk#@rxFg3>-#>5$s&a`8ULV}md)G9P0Zxo|3$El+sWhbM)FI$RD#}QjHLj}R<7x<~CN(P2yIe~QTFI`7k z=R+$kE0`I#azhQ!Pgq!F!-fhRPhqGP8LZn=E{c_Tu zoWl!KOVJg*XI6AK8{ZNn-l>bt@q;*?oL<8xSke0Y3fEzWSPQWo{ z+owT#;1sf3F=r!^H5*-_-r5}Huw^#wMl!!&cz#ek`&sFe?-RHeM!3%1+sLaiYmJrh zw~un{?g(2bl~%@VT@v;TCkH8+{3%#W*JR^Hc8wz@87)ckJX!fB=iWuH(4G0q1%e(~ z2P!W}I1oRjbj-)*+F$L$`e6=D&)V%oh7*3_6=lks6>goa(M$8*bDATb{g=~lp6;yI zpu$?lx7+)){e~1@G~<)rK5byV+ecVW-5)rh6(QfLm;I^nlelXa|JA!qb<_}zyG?iG zINW}zuA(lfV8H=4i~n<4g~2e#^Jx!W`wn$#WW40hWt1Lwc8M%95^hA^>>}5lI_b?U z*fG!!tzpZ8bP}J9t+J^_cybnG}|6ZUosC+_PN2Xfcxn}0Y z8N>QP>#e$Z4cr<{%u$nglLD#O40n|1X>ZE+@(xf1<(13bcX+ifo5ghF6VpyexfK{8 zmiM<7^X`W^=eWph;GaFKTNXK=*up$*eR!t$@U51Mt;(n5aSvkK6LofR#MD;xQvkAso1684EkI_^y1-Be0V|FLN?^fR|Jf>8mMtpKQZJl{9 znIC96!5kgDpo8^@y)Qd|M`3b0cE^3$0{#{Zjr^ODwa8A%!i4JJyDtZs=Zsh0ITm$s zNio4EiYjS`n+ftwiDVlax2_PwRl%xueJ8`2k<*+mZrSpqxxMTOuX>g5 zBDUuu!TsYotYOwjSi&}PaLs|mWsQnsw=1unj-(6~SUUAa8@V_>TT>+0pxev20x&{1 z>|cJu;wp6WLX14U?OI=xPM+k zY>;eqrfTuE-~F%!y(+Ot-|E>PbL+&-CKx1)Afq849jEcVqG{iGrSTZUO>)+^0$+tq zjV?RSb>S}am)f>okWfETj$IeN>atA9l{-^HSf1Gz@81^w@Df(dpH^?wz;|t-@WS^ww|q2%Q*YY#3hX5q5QlIQ+lHC7 zf|xQ+$Mv!md|!;#6UoaFx;Vj2h=vTBOs;;RF$;~?We|{0K2`UNTM*xe>Pa2;cFt{n zoqhX9njmJIaBo)ayzU#v4?{OU>lWrpXI&Qb(GL~MN{4kk$`*eS_H=pRatWQkHXoa;xyx-o(H}{ z-GDp%#J}qvj-TjPi2ZGPN$*9X%C-$`d_!ktu(+W_ukYyhpphE>0fYIBjMM(K`%Z^u zmzlbErXvR~$4g8}wR{alc3%sdWGU64GPD!P6tx3Ie<@gy1FL6p^)_zUTW!Fc z8SNR?%!Lzwg3cvo(kt#jb;|cuwq(<}35II_uhi{|-4AE2eF<6f;dM^?>AGvka_v$} zHua=0NP|O(3?uQl9bE>?Iv8)SV^ZYm^CkxBdBzcfKT&)90_#=I4J5UMQ3^I(II@S7 ziPwGRXNf(MrBAutzGtb)X$L&34(Fc&0Z9v1TLqtXD?s};w#aL3Kcn{KpkukUQN^}+ z$*uyiVjR!Bfxj=X@ekXl%L13<(^RjCF0VabUa&4?{9$AG;?wls6^CNOknii0{$7yD z=Nk3s%sLGnZFTa;8MD8dzj_z6ZDv&KXwxNxpYMNV^W(wE0OYh{;(%WHL9q~%Et;jd1#8Hb$X9du z%UhO=mW7+gEBS|)$mIj@mO*66fYkv8^m7IJ0w_;H=xyWCqR zx?FEJzn~m3KgrmTnPe$_P+dso<^Eh`x$I2-LJ1K^S8LXZ$Lmd;k8rN>pT4THXEL+? zNeeB57X?@;U6U1E{BO54>#~z(=sJFdrfcdN6wOcYtsVQm ztYIYubQXx|_}t9cP-HKDXPRuQ{36{qYZKWd{HOf6aE+e z(t`hgf7r7FPbMIS|3ZYGKvx_>SE!*Y4AB+G&=p6}75mT?>gWn(bj4A0g%Y{~K5zhC zp@R0yKS!vm4}7sNju6Qp7) zX(C`_sO0?DutDgh712WNeOs*ibPfI4k%Uig#mkZK?Nrj#BBqC3 znin=0MD#dqzSV6H{5qMD(TiD<{i5<8YW8rHInDn3iu+t&(%T)7@`kV z>V4Dm8D7M2nV2MYX=2#mZQ=z(Zo_Cq5358Fc0d?-{S9LL;shyv>i=nG(3$9Q0IijZ zND3Uk#%Ofxz|Syk2?PxTg+ULZ$3C>yGla|+eB2ai3A@aGS5MtPoP^LzMChd=dKk#g zB@Twl#7Hh;@J!62x62!sJ9q6P3}WCjX)SnqC*FLDR53|1Uc~4zG4OVCm>AR)X|x?* zmyUpI(TW>!jutj3$u31LViYDx#S5MS zh5&7l@N!@9;RFQtAUZ$|{kop;2RwX@&)u2`Rrm{h3I8<^<{m6Gn0skqgWtmjGs6bs z!v-y(p+!t5Oe4``nV0hjW^Jn=;u2UI&I(l0MJkEdil@Vy{rURzl7$5B#@}A&Ndt#X z;isJ{yR$-e`o-+ucB--QzwOj|w56*v=Ks@1fwL;?r;Q^0@=ICRFF|YQy>GYv^2={) zkMe}BSx(n2Bm@35Uzy!!q0nF6&o3KKd|31U%fEiuzfsz+LmUso zbL~Hd$MoOB^LhNghv!$38UMeIjzDC=x32l0(HYX)eD9>#uU*T5LKPX3pZ#x#r#8*} z>a+OmRzT76k^Sp7?3vy$uPYfVw&&Wlj~}j36B5^~6Fd6E<)1<(rRCn54SQNN?)0*~ zoj?4tPHaLdcbu|+&8BlF*WTYWeKS-+MLhWEhY!W~qdWSw$-A$?$EUVVw=s2n^(uWg z>{%6?Zo`Ov&RM$a8P$I(z>6w&^oP_B`0*W2PTpEuWAK(Wa#-|J)obKd!lFDk2EeCx zZdjTQ@!PQH+8;glM)lumR|bZ<+*@N%EuSvx%<(6K(p+~@4|a4#u?!vL7q8vB@3?Mf zdXaavis*N>$#kW;tW2$VF~p9(FdE3z`0#jM8{n>71n!_RSD(`@wL zVuOF8I9Kk(8J z#>b z{w+)tHA;DT^qpUQ+z>&TPhrfy0yrI`$TZM}Yni?guxaJM!xQo8&MsThMGQK4zC4y! zb`2AHK?iCdfbC4fDTVs1D~+W^3D<-Y&(tFGWZaJfrDVNVDh<^M?ZSuZ8B z`R?Eq&Na5slBXN11p4l~(Ow{s72huu+#n8Fp&A*fe7&#ie@(3Gb-w=G< z7#iLLuk#H6_$X=0WJxDc?|lpW#Lsgr`JVhsxH@JIKhJQ)4OiH#51>=*3yuMh`}zwA zv+0(|z6j`p3=F%`C1hU>@B(W@Fg?a_cQ^xxdpu^sfWRbIkJcpZl0)s3>kS1ioe6;L zv_+5H*`6IL0?X-%C~_$)IU(@=tIcL}LT+*`$s2)$7X|HyTOh56apEbQ5r=BV;=;3e zLZ1BG$fdevK;l(c2yx#PX!Yt~n>8Q($Fej3_p)oP{_kb?zhlg)|C=#45*XG#pwPUK zmOgSoJCNdjMJa#f^$ipO#fURrOuvGG*n<0FY@ z7Hg>Cqs{2f=I|$JHikN^(0W#=cf9=jlEt#7-Q;TZ1Fn%(%g-yTyY&O_&>m-TrcG&_ zgJ${o_xURHs2hyFs+TjS)IP~<=?fe)n`#2jc6h*7XjKCek5+|@4B>Q|W|amYU;n^Fg#*f&E8D@8ype~-&2Z;^3> zL@uW1lXz?@-Dcr8QL{raApU@&hq6mOAI`==PG#it5TIRX3K>ZSW3-h1hZKpAoXi!^ ztbGs?Pgk_@Yyx5hEuGp3W!3_;Z_U|$EeNypaJszI6X+d@-^sVqPTo2Q*$Tr|CJ>7J zFvv}SCS{LTK$8ihI=@1F<6L_#usSFcNf3IZel^_+f_fsaHb>M!`hu^_QqO?v${8Pf z_I&@S5+oNJy)~tS)Y<-GC}=rOEKET~? zv>n80ox+kk&mm?U7{}ZRRkjJXZ@2T8$a#gCkQKJUoz??Syj2?udi4|P+`W*o68RK_ zXzlBYC!h&kO_n=E?QN3dL0ROBqPatam!Ks$0#UZW6}9wzAt@z7rKfRNj+cp?HjLoj zYfv@Nk}{M-g8b?g#F93&SDG0I{i_QV1HGL8M??)gFS=GJH-$90P(cQygT>AtfdtA`3Uk0Pz!f)Ca2jvWM!-iWN9sj|QLy z{hu+zDrMZ8tmGW3DnU73mPgqt5ec%sQ_Ub5b#KlCyaC-vmW6l5_k_60$LfN#2s3y9`Ci>?D}Yt6DQ2#9i493g|v z$ze=J)R?&;r2C|($|tyBtXp5+`C4-1wv%{*HxwsA4MU>Tw9p)KgrC^qo`clOCgBK7 z5>Fx)a>45c9!9`(E-=Jkssz{gguS*qU2s%m3WYv|Q&90zc{f%9Qd^1M=dsj{`COhm zLR4*V7_E<?Wxe5PWVu$JKnGe2)z$~m=FMAjP}Hi^RjDJ&Kc5_Cvxjz; zz1Xs@P#n|m69_rqrxub{gY)Kh+WSI*u#>YRfa==&oyCHQLQ+FRGI<}$0P+X}v5xS1 zJGRe*kdfR|q6%`YnyQLIHKhT^Yr?{R{|l?YF!4;AIO@G zuG5fuDJUC30R;>(tZ)ihj?*55MW=Jy9W)NCSEDaYAWPD_;O1y6KHTXBv9<85yQm~N z*4UC)YsDIrs9Fcb30FRcK-U@$c7XOfMy?oiXGLshQ1I4W`L-AIW|V5kbDD37?E%}Q z-A#PHZz?a$HgHdeLbB~ng)yGxGaSxq>w++E{@pFM1k@EHmB4^S?vZYSVI#L!LLuJ* zUNZF4ySf63J86u;ys%{D5~v{eB(G+aOtVp$H8}@z; z$MwU^n=K&QdRB+~op1VXdHyy`w_xEXm?6ej>OhF^SREFFot2-J{h7n*(+n_FggmMd z02l?1^^ncLtDDjXi%igAoraaQ?TRDhAU;=rcZ8Ft<97~n#@%PKp&S-{8Kp0(03Bot zX^CWEXEQwP0NVePehT7-*q4{6XIH!nR>NIec~|Ha&~fes&J(cgZ{Cs50X}GB8sra6 z-4hprD*Y2F6%3vKkUz|gif3;i*OXkaav3Hs&1{3znS{l&y@gaLAXtHXmXxUgX0>Zl^DibVW*AO+ZjI)LncP~Q(U^fkkS!J@8}pOf`YMuhwg zIa)`|cKhgmO=j=+`o3!FPgsNQgJpG9z_o>*`5p#E+o!wI2ZHC(Hg<9pc>v(p$U?5Z zKemn|15z|9Llv4^_+r^r5O&#jFDLm~)qWqI%~YW3pW|?bs%9lOo7Z33<_FWu&LpG0?qy^>$&=;z&0%2f~n+M6a%u8fd$ZJIK_LNZa<}HO{ z9hJ#zjJAyPE=kpf>~X4B`K0!FH@tvdXTC4jbkB3_iP)Tu*677$J%4S7nHYGa;w)~udXQ&O+^6ph72Rg+q`=5c)n4@><{w7ZNR%oa;ZO1Nzrh@Sx-t(L{KerDiZJU6Si+2bA&~6xaz7mT zZaJS?%bAI?w^xVX6#h6|4K3`x_jKn1$3{wjLD@;D{3#$A2$ycbmN<}>8oUq@1zZ*$ zrhsYcvnv-78gx~NTREe zvMMCWlNGQ1RxGKq&W+Hx?1{O9bAb{5R(dK4@;}aR7l4Mawo3JEeYY#65`Kf@tv4s+ zXQ9C5NU}>Kwax1wk)Zx!gj@r3h6cy{Z6HtNPP+Jn z^`|@yEs+KwS*e3B7?jr~0@0K5u+}dduC3l)TnN9SPu-uYzCR#jE1d8$&#Zqde>^|5 z`87|q1D!1JE^h*IQH0r%YGqE!bzXX?A}jwQW?b7+OVc>;h`$LUH)5Nic?0E?TAI90*sOT-;bVi5dWGxU)T8!WRb``E>K;sah(>p-6_}68(%@v z#x{Bv2&-&%!f`{_DF_XR6|R+^Xb4l^?{xsh{Qhk+P>xq(wFG30p*0!+bRdViKfFJk zBdC1s3{!X06~fa_o}< zY(#~tZ_2R}+~U4SM79#%xTx zh&}7Mu|gagav=IZK0}H}3vdy*1C9q^HV+mue0Wy3l4sw*TJ<&-?1tTkkvLG=h2m=` zrvtBcygb?()&`qb2{5atyR{@iH;CfTgP4@b*MhtwdDS4%Jq3I1U>llUNHT!r=IeIK zR1`BZ{2&$H1Q*lFwiIG0@aOno-(5j(a(X0NMKwnIA5KDd1%F?$P)W{b@Vy|*kE{|+ zLjof9)ubKJu-_?%Lq^}sVBi};N-#xuWB~Tq`KiBX1ddSmTrti~Us`1VsaaQXldqy$ z-}eMk8MOlOG=gq?XCesrz2;MBkmRNjp1@Wiun(cO)6PB3g|-oC1Cj(p|2b#u zd+xnsoZVw@x1pEc_pP<&nrqJaJ`+f&$$n-0VubEZBHGC3=iGPa_m3}H_Yg{`YL&B) zeJzA*O@Lx%e$WpMYw6q(mM)gCy}vR%I`_GnYeW}=u{P9fA55(c!kjkn_0skOrC`Y9 z3(du0opQTqLXf|wD&a^T7gWu~cJMB{%?I=4(T&T4N-U7n@ouwpGx z;mKr`d@{Z-Bvp??+i0H$SOgMk@O9ft&)K-~%PL9om{FsP$#@%$)&r^#+mij}W%dQe zjGGL<9X+n>Fx}{Sh?h~}A8)_RzTHBJ5*_6k4CN9J@hlV8Zhpt0v>a4Fi4#)KJP~Ea zU%o6t=QjC%uLeq9#})ixZ04OAhe3&Mtq!h%Lw-J-iEbMMgOp65vgX3DxFQ1*VOIeSdnn#X!3ZY=K2gbBw9{Vq}*X(><&9|F# zk=`hSK7E-9*lYfjuOlS*Q*Dy^De(S3Saj}NXkAE9IS4W~iQ>UuB@J%He+84$NDPNG z%!Q5Zv<^W%CU($$2ngYwWlLMuvZ{5f-p&mL>*Pc02++({SZ$1z3^L zSg=5RPefMZ;=~-%JBGnFKm`v`@3Hu?B2>pp2mm_c-Q%Hf7w$&2JANcic(7kU47lu2 zsSbsz4k;OafAPP+)Il$T06XH?)C8a|u_qqig9eIq*#|nq9m5uz3Nn-(x*%JE zLNgnvVihfInwNH<4fmq|AVb%A(lZC{iG8L>vT<~Nyr?XWL1`^bP3*0xt@d6uPfu8j zZu=;r?C>#6YcTka)QZlJck4eJb7W4`E^4P8_#u#QyxTC4u>$9yx|MtJA+D));x%FV z-AT)~&!o90;$ED)73rHRubenbc<7=}?EU^hEm%3rA?jy1j*0CTR6!9aYPydrtgV!_ zKEMTa9s%gco9eOjGh{F>rOLSRWZRU3vFPj?>srgsO0^u9g&@&2c+!`zivCd~MYG%y zb4Ua95VyAlaL~Q;JJ4b{Yq}&@yq{vuObV}Ml{7rvtk!R5k7ctb zJ%>+;ij|Pv7}k-3fO25$or2On(bh*23>)t#ZmvXlKA;(``wLnlDnXRMk;=%;$?5D9yu$7)FwHTrpXh9Fnhu?&TS zS9iG?dqZVX5plrcAN~*uw>zEZgR!}FQCdT4!3%Sl`T^BxC-zjOfW+}}`N)0#aJMcZ zFtupi_d^`RrKu<&jX$2x3a`8GpG7##ZSsT}WL z04a7?KUW9}A)`MCAiGwlSbm($Qqf|iTffud9{ zD+n>jXU~uBh~N>wB;E&>Q_G+H7e2MDSct+$d6nTFwQqy$lcpoZ+GS8V_vO&U&;oEfrEg6cq1R12E*|qedkU#XLzL%=NHg=<%LHHWH;HQlL4a%`Z zd*de+TUz-}nHAR)S3{4%kM5}N*9f-7g`j^%6KxOHfAYe~n715F!`AC2ok7!$yaIn1 z%N}#9WWpZVq>rx|FXyMS2z89Y^rl_yR!>A+&FC(NR*X^%C=V??YjW0fpA7to={#2A zHG>(krAp%2ezhI}RVX{;DsF)7xdkBTDg=JxdnuRdz8^%RdR6tS0J=svzozhaM~UVA z^#gX}or=xJ5rq2matEdE&JaOZi=|)K2>xdCRr>_VG_ucq{t5{?EPLM5AkI-g=(}FeJ zUIh?aqGx2q*7J$V)drexX^|}jHinu5J44f(r*1P^KWWjUaE=ly*4s7Y=K|sj{XNxbSu2!Hl3FM6G)c zaMm!#Su6L*BB&X3GkWhV$i$q9`y6w2O^i;c;>I~P$ws1LckrGL5fy^gf4BQQ~uI@9~R|cF1-8Oh&j_q=&{J`wzu$7HB5uEhhTsx!7AfBM4!>p=R zJyswRWEb~bQG-{lqmX@fATEDR(k#seM%iOc7L;<%A=N&A@>c^_-sld?v_ku;^JV^O z@JKq9ew#R4D^Mx>j9jA<5Kf_DHOO(-lhs-?-H-NK9K=p1cysf`5w=)p_ZJ?-)JYdI z-ZO}Rr3dfp*@kv94bpf$m!RCpjH}fqTy5NwUAp# z7e(|Pn9jtPxpCu*DMlY){`>@^i<%X-Z~ts8Bzm=GBg}^v@hrmVZF#Q^kvkHcf|M@H z{fpf=V$(BG<8Y8dH>=ISsHtY{hl?J38ofDOs#RwZ(&g06=%5t~c?iC*(Bb;N`x|f+ z-U&%Kk-2lk*i@|KH?rdA=&td2d&!^MQ zfCaDO8C)(#V#c;f_@6m)H#yc_R1Sf5MjlD5p5(CQ`0ONqy0#O&OwWq2E=|0x8|17r zj1QsIELT+=@vTiT2?dFiY0H(@hpBt;Z0yG&WI%H6dDLEhT@k;xCZHtkSi>VAD^YbUUEvaL%BtRS8R5p=z{p06X0y zL7Sa|2~7Pgn2-6S5S0izNVvGp6wHJZt=@YUmm&S7B_0^4%yf3CmVIXqaeG%zFwtW# z*v!IF?mkQGVA;jKGt#v9rNC`ny8*!jNmtQ3;rcH<=7Cf)H9 zwq|RxhrsG>& z=IcEH z?%L9qH)3E&thVbxU`=ri;VvtqJH*uy0b8|E#j{W^y05=ADQ~70+*#tQhcsfwOob)L zp^~qt9uG!G7r`|WKE~vRxWfD-_hdbU(yn9CbaYxY($0mj&`IJaQQM`a?QzET8IMpB zx4_0#*D|Egim5rF6d|snoMKUyNx%~MT5^cf4kM%tJ-)a9hTxsMLeZa1`Vv=MgJE_P zoHQ##(WYRxD_;;y@09u*sn5C^vr)>$itC|`Rn$ATuZ0{w0=s=w`fXi{lp|3!>iQ>~9E zN~P1w_Sfw3#B`h4fRm1_{*C0(&zVlV_|rmQQ!26~`6=I(yCGnFq8`XUJSk6+Sn0Ug zE{FhLnQspty>xg|3;D&sTE2R*GU)4u;Qq6W^fBGwnzM{)!)KLn9&S-(?$XjCnSS{W zSnyA@{3V#qN1H+se;@hW=z%^eR;hyqW@3DrQ_Zv@JO|B*{;od&xU31DT7}Qqcl+)# zn=-%Hvm!uq&p_V<8nK|6d?#rIeW{GM7vr02Al?vf7nCD`K8$<9x`PupG`^;mucd zrYV2vszyIxDVos!uC4iuudKd!rB{)u< zdycq^mBq}Y$bRE!OmvY(T&qYK3whNkD`8D2odG-}iI=(S`YEOfL2C6Ze}l;z2k>jo zc2%2Z26iR&P=`1gX{_a@^@DVN?zbDfqk^yz^mwYVwr~U#Q|P7QP{4657IpI-y!8)9 zqQbPD#JnqcH4sd_AgFdAT`PR)8rUQhbDM4WlD)mdsz8~_UXiH>f=PN{A5x*6_je32 zjx*f5e*&lfdVPoSTdKbAzftjg z2wIL-#63I&TvSbS&RY~B_$~YtI%ZPi$ErWaUFiEd^$__`F^#?aK!NWjAAS;eq%s2u zFZ;5uv>XGPKf@IJNc!y3UL@p|YJ_lM^B#W7C*#lLnra&1Lf#{-e~#N=sW=KMoj0!E5PzsO}eY;QQC@lO_o9Egm&8Z&T`e0{59hbudJR# z4p^aPB|ir|;D|ZbcK6Y0BCCt#CZp*T{oRZhST<7~v0WTs@;EgYfqku8JCV3i-Ke21aBhnEgu7wWSZ*pd?F<*UFE$T9sspol!M z+vw18YOu-+PbZ}LBPfXSoY_C3UuF9=nd9U*#!myU-v@hHocRUEPwyXM1&TgtB}2b6 z=#6dK3;z5c4%1$-Sq>AnTnYj6qOis3Ov;#fjmwKbApnnbRJBPtdvBi>yUE~x$IC9b zT3sUYe&Hy8&#|aQcHWnp2=4MR#Md=wnMsBS#I3L6WsR-yD|MKE607Wr* z_mIljlV*E{%A@ms%<_&-Fw$|e!=pyWaYjl3UH$pEZSMh`(A5r+x z{vlaa9G6t<@(u7tp4Dy9w2e_DPrV&7jTa@LwO{emkx_q~&LJNOWPa|dSKx>j4@qI6 zIDS$%U6G#@-sOigr@z{HHJ0MzhnR*w@7>SgE%Y^MTIen8w3Er|KGJL9D6O#$#GRAD zzjsJsYj23g3qR=ALL0Sh!5-)N0Q&Jcv>yr4Ux#NKy^)N3^}2p*4AvU?fhL&c=ehqy#dzG#3eLnA+IwaCAL`k`4`Y z#B6z&D*#G?SkDcbM_S3q@FlDl>zaDTtCp^^wm7V9eeK))ng*$?U6n|04vX=c0Hr#! zA@vbr=`)=NpW4CZIDSF@ufH3;aG2??nRXk?aP-fM0VvLD`yh%#s>cy!25-t z8UE&nJtx&@8U`0%S*6y^!Gdyp3UOCzL>iitmORR%u^!Ex}sfuq0f zni0Ag9n7&6L>&Rma>Vi<=EJ}xa(O8X@d}Mbi(0nxZ0PDjd^^Ey9;iR+@SNnA=uEa1 zfNJ2BNZf!EZ`%CjI#}w(0k@arn&sh$9~oyHVjGAFgyV6D6gZjP`jN3hiW0+7K17W9 zk>NPwg|<0XLLTDCrWg2mq5Pt#s}g}p|1zyX#?g%KMFG8R*gUBVcxuoqDSNf_8R z`(OWVTJ@oTyfu$y?vIK&%xZg_C79gW?z^#o@!D3h1x0(Bk!nhhxANGShihZu+F@AxesF*E2{Snax82lsxk`{k>V7hyWu_G;>H$W1qV`)SAx5_U%Ph^LZ?uR7v$j&* z(jWVSn!Jd3%;}~+Nj%>@2Q5@4Y>@{)u)Fo^jU?lN#&eXC1P7d4CWtA9F;2+Okq53w{zW-hUqjN zV_5p$<6Q93VjYsuE=jqaC5V-B#fYURo!{*IMz=jb!Rd znt|(Q?P!X5*)N>h>CzywLf(^u5y@F+5NRMdf82*l+Y1g6jWry;bhhuijWpY4 zby2)=C381OS#xhVX`rz8WPDSGMLlj>!*7=JU54ZTjO@5~Ocmj0#b#0s%rL%Sh7>V4Nbe02t zQhZq|w9^iW;u8GCrArd3xIMNGb=qlY#wJ?A&A<|vtsdVjxbCnB zYiEFcCR}m{C1;4%4^t^=F?P}BGD6|v$E+Q@pvcI9{Tou6^mx;&YYx@c2RvmlmSQ!RA z*P;S=X5+8e>u1QjZ9W)Pkqk;mLS%Gk=(;@61!7qm_bzUIta8rJP5k3>2k-jm0AYgi zO@m!cZV7PnK8OL0`^E8y7STyN5XtIko!*SbI-~LlFj|4dK z2d}%ox&g>LsZz7E9w;p6Bj9>GLAks@#(W1XofTd%ZDn1M$5r>`^3&4=704UUp>m(H15^RMHpyau6rp6>^g>I{7rL*C7> zphOE+W*`Bfxo*`+ehtc@nn1vRCr7&YWs2Uhe*hV!M5zNYZ=pUF2BPYnUS$gZebX}z z)ezfA-PatExvzdb7?88aFj9^Qn=sP*ZqCx#dL{__&MWg^M7=?0`;0Y$jY(7Hn{i)S z@Y|9r=D@6@)G1+JbB$@Y(xuu=E`jYfCV}&-;Cr|>{EG9Eh z50)^Q9;ME=J!D1(Vi+Xq)&rP}SDpbIFc%+Q1z>jH=}qxF!z}Y#eMRJnsNnI81b}%; z>yDqnt+^p1iMyUQ3n$kwGT{eiH^dxmg)rc;epsY|ETRG?BX^Y-vVtp(hq;H_4pw~O zw|Zz(16f~MO8+~yZ$vIz5_W6BZbJu3v&a^icZaGEhBU4A3g$b{&DDobZlh%?V+vsX3xH92!eEs7N& zD4pO((Hp_5Bf9*U*u=B5Oh^$Rz~cKv-o~i+;{oHFcw8o1uaq`P6{NtoPdY)8;pfVC zl)y|T*s>2otzK@r6|7%4l}+`Gq80-CjwUJnU8&uBnv+X{x(HCe$4ATN+40>+Ha;As zwjIde|9-x2?J%RrOoOqQgYFgbQ~T}?-AO;8cI(^R(>g_ka++959t$HNts!ra#mELdsElLxpSNiGa1Bh9_X`gf#`JUAWvR5Hg? zJIzPojHd{uL^W+QGv-*iKkR-b#cZkdtRdV~9O)7-$xNx57*5-12e_%}x0Qi&HB@WD zQr0_L#fR=U`Qfrz^7Nt_?7)}6lJ&67$1I6&15MJCpmonUNT)f^FYjuvHqw}7Su!2g zzMZjl-W&1*y~7Np-Q19PaW>-!^E1hGD}E-qNS>cb?%DwV$**c`o_`K?FaI2A>CoN3 zb#N|gm$#eO;9RB&LQy5vAQUpw*z<|YL<9S8Z!cgSkEn1lvu%;q5(?-Gl~+4iA5^y} zJ0WhBdG_8b;-5B3Quhz-$R`{vNiFn3KWFFOe**sPNffe!>1;&&ClFoESyZ1`mgPx` zV2|B1vShRE5Hgp6`sJimC2ixMKqu{Roc|M@$#{8X$h(;i*22k(SeOGSIm@9N70|_J zCh^fnwyBBD2s-oc{5-3F)2efEv&6`jG5W54@~H%uh`Q0ym{=EMDcouj5=W753T#LD zUzz6 z*NcK!fFnmy>^a~i)K57nP(41mX;R;LH}RJlyPXOSD=lv0$Xv)4nOjba_-F%wbEc0l z`S2Q~?>4oT#_vPQl06fk$=ltUuz)rz2}OtZO7R!9|Hw2vJW7ap-)Wxm&hb$KKH*Z2 z%ItDl?4#pB=yNfV`~^ns5`7R8@A{x<6Yfa^@nLUJ88O%Wbajelyv25_v*gdwhlSMd zQhSiRlyv$9ttNW9iRhB~DK8IgvkY})mvD&O4Uv&i09;RnG8wjLEUh3veH(YQeCh98^ozLRPhWFbMj71v_8 zwjFcC96a|Jj28{{-js(|w_u(x=_ZQehlTERL?+t?WBdgnz^{krD@0dqyLWZ);JGs8 zmwJD_5lvM1L+Gg5j!eySC#8N{d;GT>?)y>{TK<^){Wpj4Fy$59H($t2%55>r?)MwW z`E~d0B@XvjZbEXhQb}RN~&T5Xx!!9;f(|0iv7M1Z_UBGlyw7QBQE@Ra19-pd?of zD9CLVXgqkdVCbUonIGSxYgtN$7d<@XrEd}96B@dP)?Cc6Oj{fJjL`Ws^YZTxX)g5r zPm37OSLKj;EknOGX+OWD61OEtsGzyh^z!fFsWyjv`iWrohylW_qZ+z&&sZgM!jh8# zUP$fdFrOaEv{=0Q#3qM&Q}_J+5Bsc-NPQx-TZe6#tb3NnOI#JYC1=}w;B=Y58B*Hn z&<6RPf&|trlYK64o@u1Y51+oAfA3*cg0PzS$rHiWTd5D}f|H*-dV6lThe@rOpRC<+ z_3N*pT&;nq>5MGev36ie%7H0KW_5me-{QqX(VW6qL8IEU(WTb+S3?eO?AKlMZcopn zHxjPDhwCUhU*yrSNYCbZJT%f3{*eUT`5vPkPa8gzm2Hz43a1`TSCRVD(T{RsWlcsKP%(Q|z^e zPcx3IUkM;npV8X`?o<(5cQq9HDxLVgJfXd*STXqRGhWwFv^gi6_ZTRz@p97CjA{#U zlYFwWr!1$Bu%nNbMfb>-7dwy}K9V()(VOLO6)mEjQ~Pw=A~z**Gu63zr%OxVIy}WGk`_PhImUb08Q=gDit~78x2mabbv^iKoyLa=4->wJmY2)uIl^aq$ zMo#iSFrNd158M~y@Re(x$9R83tY_bguhSws#9s`K2d+szQ+8tg2aSNs)oZH{O9*V_ zSUJzKtwR(p4Jh5avfOPY&3N;pamV4nM1i5haS8#&3uhYI6-G`*R3|jPsJUuqDJ>)M z!aOu)^s&xW=2jtfO7nxi=8f#Q>q4`+q|3Z8iho=LYqp7fLTJ;d!hvVLEKg}8jir=T zq&|1aVXdy}W20RJ&)gypyNjMpE|y`nLN%X$ul%-4Agp=kx7lIy)k67C`jT@mslNYX z-{Y1?wOcF)zcaKw_Fr@wbQc=2R2}kkjLCR?y+-fR(f(YgyE}Q+i`FYgtOAl{vx)Si z?#;a$wAu-gwO--_C*5>N?`>CR^ASjbF2ojZ-d&@0w^(A)C%(QI`K%~B zCX#UJ&(YV-oA2g~?hGdiJ47=Uq%Nk6Ux;|pw!>seUjM^>`PR3A`_ndr`5o!KUMM`Y zQ+^-y_mvNs!6|z2ReQ8t=4VVtpVHg^TG>@V&{_ZC_&x2qr`dLkWKc3i z^krMzcmf5TX%)3i!|D^p+RPOWyr_LUUiL6@S8brGwVj{kjz^0`H|``&^VsJ%>=2~b z>v)(23GYz<81p`o+!do+N!{5{c*e=_dxBN9^5aX{2X-FW+AvD9@O<1G>+}c3(pBhI z(yzx%5|kfqAl-ZTuZ;m}O1Y1sKRNM=bYA}m>u`MEQQfuO4pyIRG{bW5>{WVD8%0$T zZ#y2s6YUl>og7vjCk4NMvzV~Nt2=*MgZ$EFt|a2eU;RV-uTr-Q->Q`@JvZx|b?oYC zSLq#MJ}G-$L|xzC8OeBmu5q*UVYca>l>*ts3EfPl#|4=;ydn0DVdFFzwb{RK)o1ju zd9CdO9#z*^zwOOF|7nt^)DTy})6q9tW3%NUouO7IP+pO?Dzqx;IqAnSH7o)ukIi|t_$Gaa#C)RxY zMw+B#lbto#e3jK_JwIx#Emp_d*{%C(1Fnr)nFP*2} z_BU~oC2__hX06`Lj!kPKn;bu}Y$ihFf@UI>zmL^4Zd#K*@cQW&YrC-Nzg>OX7)OpU z80vW{&qBtwI?OZ@9!7mPvRtu_V%a zOuf&@^)!7(!}T9e%hJ_JS(f5!((TfI5K72$8pk6gPhRdm|N5z$RLi(({U4@`%xiQ0Exepx8JH_u!OG90sYK63b8Rr7uPm5bCas+d~eUjC_t26g$-Tliop|!uK z-o5gVzv+^|Wx1qziRYZCJwDYVM<)i>F&6!bZU;Z9yzpYJ-jaC3g(0Js{Pw%8%-8Rp z6Sl{7)V;E~aweIOO%x9KEt{vlsPpeKci>fo_NN4L@`Qxjrb>1ld=^C8WaMs_@%r2~ z*Eg3c|Ge{rZbCbyTJ`yP@2m0^p^nCv_BRDa>1Iqu33P3V(($Ml725IU`1*LdkK_LL zArUXXWJtWf5F#Y3PQIA%NwGlg;nE(ZXW|JTo?&Z&<~AaaT9u+%|21^ud&jC}hlDv6 z`hF84vF`^O19C(|b&~UIPwQmr%+Sb*pA@_7UoR&V-kZ;Eqc(b5s=cHn z7XK=;f6iKA%rQnOVD5+i`l}>fao-IiLn+7voYw5rKGXPhabQ#|%r3b(6ya$MSpwwIZC8cikKaWta z9Es_H^85M<;&zMISF1&r*w4NZ>N!*_IdI{P?#exDcGmP=)*(H5R-2vOE#PD6p0PQ9 z@nZChnBi&Xe|CGUmLT-&9RcBaqwUxI%;hTrNu~*_2@_g>gvuNIDtubyLg`wOjr7q^ zA&c4qdv0ZPm~(hvxRE>WKYk@k9l1C9BJ=p8Vz%#&`C?H$^{F zKTGY3+;hl&3qj?=uZ$BpZNc|{cv|e!pHDY#R{7eHSCH`H%9Fg;PPTia-}4017gw&a z%5hhIdb;Jq^_A1*iSwCX9U_`W6fStOTl}{_tfG{0@2a%=XmSN}Nd12X63uybWZ8Be z&w<;{e*A^ZYh|R4=r@au=qB+9pCF{l$`wGep7;ie7 z)vx5fB>!crxOe~8MOtg3)}8q~{wn2rJH_;7!!+p~QsVbi8Vk=k7~6#|)oQG{d>S{g%m^NJ6wna-PA=Y2d2x-L>+^cs_?gpYl^Z_o8H9=mq1I(iM4< zUgC}lTkBj&9S@Us)$i(Ya*r`dw)X1#d(bCHAPMTSv2p!1kAo?z9h_{m$BTGvh0_-Y z^mn-AsXov$C+N!Zk(uY#wz%_bS&RbznO}q!1!<#EMx7cy7f08I);?W|Tf`l+o2ahtrymLwf@yof6#zH<$ZFo;3l&Te@3NJ#v|Hm$X_42c~+wiP#Zc#Fc4 zxeNzEp+M^!YxPFA4KKe@6u*+v?<7#grP-PDDbrh;M@JPU+FsTH5tR2IcR0hJz<$Gj z{%h@jqilZq>7t<7pXa?@9ef1sOdaffJg)qIQiAq^p~T@+f-G13PtIH4v9-1P*XWw~ zp9o_OlwH_HPEq{(YktKq3Afqly(JyqzS1S>wx%;yrsOP-ysQwL3Ec^G-y9WRa$sA+ zJSQZwSC%46jic*UuctP$Oi7<*#|4>px%Y0Ri;U|sA82pB8W8Bpl_dRRJR5cCFSaoG zt);*J<)vK0L?knnn@RBV_%6$+@7pq^_{Hu8*xTx??EB6S|3Cl48>^Asxoc(r5u9BS z{Iy{DACanGbHH<2>G>a%b^Is6|DG(7qJMw4J4 znQV5SGqWW*DXEU( zsK4nqA#$7G{7v(dlBfRf&&94UpGuv3i8SbHpkc`0h6B$<7%&h5L@`ScC z*DR8ct?{N$TPG6Q6Eiu_45~er+$YLo{AIJ3!Y14-2yFyvyNK`N;LIVa>?C8W=7PN& z-ZWnypdSpg?-BlgE_t`FM^%tSF~N+LOU&l8coI{H**4(kG+&~H1wO@WrZXSi=q4=Foo(KL-rxSZZd_2GIOl_&rT6bWul1O5w+Pq)~A|5d;i zRR!78GP<`-iL|TckX@99sdN#utkIGFz8yWXnT97pJ}Q6aZ%PF!B)$aCl1)Sd9%454 z@Y6sE6;gHq7(-0Zg&aya*SY~us@@6Eke2__w4Wr8&Hl3_XQDm@k>5qR+K-Ynbgn4m-egv78!;?4lFgoomPAU>li{5e-%)@g0qj6zlAt^_GOJ;h(q zjSGy>RDZQmHz~Uj{~|~IhRP+bme~X^WOjO=GxwyOc5DAh>Hdx|hG`$SL4xwo zrgs=G_7rQk(*3Qo?XVKb7NX^31{{=Q`QM0W>YB+Tt~{>U<%WXjlRs|HM0U)gHax06MDc`iXH3WS zGYY2nc?CX){F^`g#%VL>^tYcyWW8BoyAY&^J5Y z($zwrGEXd0M;*&}R0L#q%|ZJENmGi9wEdV~ol6xX8Ap+aj`4QL4FNICKi zPtjAr*k(BR_%m|gMCTZ?4ojUtjclY@_S2_5plZ_I_7x2>`pffA1FYfsf*|AR!dEr3VL@Jiv-hi%U zj|r}oX!^6y_~wm1binRs{YYAQ0s7jQ71fOpI8^J(TR$VGt0lLKLzvtysKu{q3%)hA z0U{kb_p=3G#$L08o}TE{O_FMnoeZ;@(Hj;)m1;8G)t*0a&qwFa7&yDP`fsGfV{=c7 zZfC~OiM(7DWYkK+!|rJt#;ei7G>$|b@ikql^2&OL?2CEu<|liY&L`uT;ms)9HA*tw zbv9Slr8}>!t@S&jq^R04D@3%@f-Wv z{SL*M&UOYLq0da0-di%3h2o1e;~)F^T8z5|YWu-%@a}H93}vZ~!*pHr29ELqP2`6P zP$KVSUG0$QVlBpnH=ye7MC8$2>`?j4u1fsw{hjB3-MklFx?8FasG%OM^qJk$IW$GQ z`ue=63<^`-ySqY$15oK1S=#XgxwQv9RUY6KJX5GBu|j^>*JE_l4jLE=+k0vn$uBZT zOVwb(G;$_JmxDgdo>bpEWX1MJ%wg5=4YUkr8qZ~$OyoheqQ1CyfgPFd-OEG$r74j9 z*s_a}`q$YanlCYFXnBjs)}@?>vGCXaxM9-Rnc&eHi7wm0>^ZYSnV9J}#8Ijgr{Ndt z_SGo0{mc}=E;8k@p%!)4=em*b3ghcHQauXS5Oz68N1O!`M)3lJvaO_e+5o| z;I-VV&oSvMKF5p3YDtLfO2SqXa9p$#wFggQp|6@><2*UA!XLBmLO7LkK_8_bRqgh- zm#^;blQ8vLKpN)_WzMDuw$9)9M(pzZ+;~~KuXwM%ri{b1U#D?1bRcSml%9@&U=Nj< ztdQd%vOPZN_Fyi+*WuD!&tWmXZK7Nd$-wvnq-{IVwrez|ZK)il)GlC?=v|`Z`HIcw z7RJmfHL4a2ki`_>DM2*7kM(j5f0fIVhxwnRzok4-3l&~7?!9uT1edgJTMs*8X>oN2 zm(o&GX`0uKxl}Y-)-5O2V=yKDzQfL9x?(ddQ zmi166kZ1)UXaBc*0X1U{Cn*O_u&%cU&9Y6p%d|9+n%CSAF&fpv`I@SV(Q=!*5Ac`t zoM&E5ie0>8P9@eyx!igls2*ybm@#E4_FIjkS+c`Om5(;PD&J z&e?7;ND}4r(}x$Hq1KDlQnVT-g>`9aH=a|2RapY0LfoETK~3?N>!k8mK*?D$2u~42 z8f^C0Thvz6V5oH%{ejI~6_1K9JBx7?r+7OF;w!OwUrpnKJ{Qs8S2K?fh*9l^8%++Z zL}oag5Jk1ia(4+}uEa}!I)$!JE8`-6VC2K3tvH^Utv^Ii92o9r47P}SISCDgLk_kf zp<8|R!XCajVb){o0TOe*^(VGwbUCp-Qj%wzT9IX806}tjr0NQevM2YygdmeYI*$sY z$uFmb`1rVzDpZ^F9(sug=#$m=^RyYUZUU zpknf$lD-9Ip4%vtnvIm#<^YVPmZIZl3AL&av>`^E$FHE3k(yEESS^+u3+JPgLGmaa9_Z%J}+*QfjHpZ@|fEZDK3o6Xs2YTivxC4ksA& z!rB!{(Pt!0t)7a`=p<;7EY$S;Mv#xnG-in8lEv)uE!0W#2vP$Q3HO*=NgcyRy5LH>4UwZIqqiPAM4DAMW18fm zrdH3_BYf+-H57T!>1bgMo^Ob2O$;=H@#N`h+dhihs#8L3hepfc4gg{Wu1*iEv zi9;xctX?SNp&hYx_s2v07K6?EBz!ms%^K&u=%2JOGC-X~PvEKfYB+nKvvXX8PAA?Zx*?OsBQ}6?t&+6J-c{ zO_FzI1E=_sdGlo~og(Vj-|@!up}I-wikA73Nk};-Gko3ggh3>8h-n$M3xE+!U+qyt z>)OsWMd8qc-4{MKrHAq8I}VXgj+klm31GaD_t)SE)^rsmqNeg(9ZL+K&_??Q&`)lG zD60tTuFOz@75`{bXAkgYpHgBHuE_nvdiMN1;u8>zR)>p;_Ipr^7NPO|Fw^<-Skk`( zQcJ&Jxg1~4$C+L{ZpELHOm9WL4&e?7#l2zf!6@!czLJJ=H~+cbX`C>fc1}C)$T(zo zIBG%gJzn$;(_vD+%sJva@H`xKMb}FGDX9NZ=AtsJ&1&WjC>*?ARmjEEJZn(Ci+DH%W zAm1_{PSiL(=|R2cY~X`^)9CA5%0uVOJe5!vcy#?KOLWK?mL|$Y(4+TrYcP)2r2g-k zSS%$^)?0i|4X#lgt>-U{}O# zunJv^H}T0Y=iU;lK02(qs2yDKPb zWxiZc#qhW($CHzjKZt)thj zt`sPkZ^*askGdPT;WhnOZMslfzBmv5>9?0_SMz6dL;rX9U6;rAqZ0Z1v^tJKm9NdH zXI?rO1MT$3Kf7uN6lMdh71_JTatccxr zhDr{eYxZB}q^vo1h$xNqak;|}FFI#~d+0|ix)e;OwRJikEhzcPEflorNfn9GGN^%J zXAY1O+`@Cw_xsSGK!l|kUApZR7$_?@DfY_4v%0c74L6toV(R2O&ZI%*WGl)oKT68c zFb&OdYCu={O)*jFsj%hhpO41OwR1E?MhOkMopLRIQC_~N*Vr^SlQrEl>3UYtRG^6~ z*h!DxBB;9+us}PaFG{{;h()+c7rnd+y_9tUFp+IN-?B8hU~pb7I$%6p^!1m`yqGhQ zeuK*edoO=J&gb!Y)Qf`>xFV{c5s-&2la>S+Xgl~V`K=rqgc=^mm2v??o z)7z7I6)o;W4gm_d<2B(!*II1Ks&BzHYkY7D*So3tP(opU%&wlsy72ncrfyTxW~TG` zIYH3a%;;_b?BkFjJ*$g?3@KJb3fxg5Hxv8}3uT(==K`NVZhScUAJ1&JL4CL?!(Ihj ze>h$$1!mo0q8pr!T$Q1b6!Io!b>(UtwPhVqID}S&XcKP|B@dFO|5|9Bm5Y1>LJ)(G z(o~-!zkw`kgDt{>OaSO-25DULwgf4#vXGGdt?}zYk*O#+W z5PxC5Hhv;zB&(ZM|d1xduFXQw+XgspI*PwdYYMb^}5I*%E6qe zg>R1uAw}hzxLmB2e|}@o6@`~)_j9@Cx7PR!&Dc2v{3zRik0+AKhUMM)__GC?Jo`x~`$Xz!U{KBiki zQH&%jvpem+&qZ}lKd%92?)}nV*l4wqvT%VbAE;>^tK#X$2Yc3A3iEuBX1n{I zf#|%5A(8g*x{R};qlyMRAK`jghofB#(6DL=#_#6zoi)r{vX^-V_4i}(Yc}H`Wts$r z#(rDYEfH#u1$oafnPIXXAjs~aP0(_$sNIeAw0J>d?=XNbvPaxRX{T--@>g9?z{}E} z77a3Til@3xVQ+bjzuS3$lr|YZV+&AVfk*R&3tTe|0`Y1zF8=zQAQ(39WI{jT>E5FQ zr=WPP{&H&qCHEYU6TP62uJ=jPh9%(amIsnHc$K&J)#A&w%(TG5VYl5V_a@shM3~N==Pi@~_an`;9!F)i zf*6c~wER5kvnw7o$YL#jFQwrorD3_WairkHT6J|)MHUSdAW9 z{Rpgl;g1W?q0zS#-watwkGKkUn^(X)XFx-mlW~#Iz47tA#e(32C5ZuAmZpvt%Y*O` zbxxe$$NzRS>#qYYWoZeFwQ!AQ4G3VbW=H@kyB*&QCtSKm5}--nB$*d*e!NMxsxT_! z9xglX;C-k4p|nw|y>OrK?H;4``uY2E_!i;9@3Rq+kY$ap1>`fTk&ieSuBq6`j454} zQ-&&e)ucus!=#(x)lZb0?i0XK+g77mfp@<1qZ2^@Il4s^rgm(TH_C*oPaCV*Qcf|c z%uNNByF%&pK``;QhdS{EN7~NdK6biuQU)50uL})h8Og3aVbDS({W^IV9K$;dXTX)- zg+BTK0kxs=WB#-GW;%%?T1apnxdPw9qf-8VF!$b3O>bMj_ja>|y`^m{0%F`Y1Voe~ zQlp}B6d@uV1Vp4a={-?VP!X_Dq{arJhmO>UNRi%=8j64rS_mPKdS@KZx%a%!``$60 zKi@IVft?Un)^GJS=lp(Vz6q(NfRB3!8qPrEz*T&cG6RO9e2tx-((=}CIVW*rwB?-_ zuR%y`i0wHvM_QqSng)mM8wvrSt_UhbRgS?W1W_D#j_$Ndzw`Jf&StP`0_^^>846ZN zBh`4lub`YCjE)Lm8P2OD-yekY;+nP|9M5~Oanc8L(ZebKewusAV<223< zPMye)Enz_`j4 z6(CTqJev|2PDN=%6uH=d!F4*7cKj*zL&#`@(I3^-%kUU+6J=^ zz>&`4hBFGV-=dc{)gUc-WD^l6f^!&>3{YT}9Fwb0fN3~p*K7w@7iByTja|zQ{;LC% zY1Kx^RmXf_Bc8|4c_@D3I6>@i{k}L*-1ZDO#K6il-4u}rkIMgL6}>Or!Jvi&lTF(= zz?h3>5*!D?h^Q~g7&P*Dk>h0`f~o8zWdyKv=dES;;mf7Ms*p{ju$F?vs9@N~26Bvm zBWk-&6NCbbO|CaGvmBPPdZECGUJdTt5JQMRK_}_cgVhhtke;TCaZhI-sY6F=2|a|i zWje5VH@#c0<|4#4yjMD)FY=Wkv|shgX6PgILK1r%Y@nUkF-WJKE#W>a2DGq+)%+A> z`=7%ybj2Bx2mRT>s0GcKj0uJe%d&ix6!ujE7PlViT)|<^J}|UEfIL4IOtRGyQrYr z+N$jCRRsGsaJ7v)@kxC^`0SF5DbwX1)2! z^epQy+2EI|n@u6ZdgVLv2$nx*OV`~FxybYnMr`KN6n(ERHS3;t`6u*c4J6ul3$g z2KV|fD|9t%3%TpJsxjA{a@KdOAPiL3cLi|X^z@f*A4g`a3m_iQV)WhoNeVK6rPe$b z%1gk<;>{mDC8Cn#F-z`b#=kyPcK*oQWPMm4nT#MRx4exQV?%?^j^=_`!FYL&?Fkxc zZ5Ck~R?CHZ$H3s4=Anz=Vmq-V9an*~dHXU72Wo?7i$y@a!=%lh215(V=ZnrX$%8s_ z!w#s*01cl(DHKYc!D z3iE{2nk3I@vY!eng0b_@5R5r=s|5yJcs}R`De#beX*>1a+KH081(J61_!b6cAofRM z7fM5a1_=;}5q%FidYrJi&?{0ztvvB1DPoqEEDb9qZGPJK9hTmXs0N+v&*pbDxHBkN z^1%sfqjE27>qZ1I*gc))L;2u@)w+a--LY&8{RkHQ8&j7vx<5$uTE}l$f_WI@=PVAV z;m}I7BHXJyhI3D@_r4vYNkR$*O;#7!MT!qp!M>UKVitCFrIX`ee4$(}R)Up_!x%c# zeK!{~!&=uTUB=6^t{_r`r6?o|doaf`N?12j5HNX@ma<*$}vmPr0;vN$eY8z zt4=eo&Y#fO2`?%&nc{N>*E$_cR=191yM>nPa~-RglX&nVvYO4wTc>mrttS=8fu~>v z({1D;6dB7?z*v3Tzj9U^DOkg-w*ziLNZO@F5X<@QDF>BxR?a{ZA9S@-KT#N*U!H{2 zNLX_iI_O;lxcmm)T5|^OenB8#x17>Os@YjCoRxTgeUR&5ykl|wmxB?-o~$^OM(8s? zJ$o~o%!w14%YGt2W+YT*W20L35-?dfvyIA&WQIw$TQ$|D`lrb_VzwM0(Hdn*pETb~ zQM~X^NdJf_ZD3WNkPz1hX+pPFZt%8?nS!z79fKwTOd}=9d#M4;YuW*MB4F1sS}+6C z@IkkQbFdKR$stR?r#9}PDghK@O{XWDA=r$z;E8=$<-W{igAMm2?y@H2d;B(A(Xq#e z9~`3PV`dMxz$1KT4gi1>7qly5fOeH%l$FE9`r&Hl=Klc7!p30vUos#js#U&q3)LGt zA69+``KR4@g*!0&#TXr%ZE*Btd@P0&vtwH$V5;Ado&l-V9BWbmYT48N*`Sq^K4SyK zNn8gV0}Gq+(v#C`Q7ng_HFFfyGqhdMoWN_i>5Y``!CM>HauU6CqVR-%eBJ(Pbe@1% z2ru4RMk^t%jx>0UG_65=!oin_XvVH^-kn12ALo2nucqxB=V+Dg4ct2ol^lQP9}XTr zW%dNfi^sA4)_2%9ZHbBY1jv%JKx5zGgE<+519@R@7cr?C;vh&h12s2cJDUsTBm}Uf zEz9H)yP&@AOB)BwQ@l>(aLS{9H@K~XTbaj<6xeX&UM-v zjlRBxI)HJ!k+9m`NKodIq4btq8Yv0p9%F1nCMI2@7vm1R2+R0p7p`M`$C!@NE+9|K zo<#2ik2@n{ZQFXU&mbECtKAh^6Wg-yyT84(CgJ^h@Z834aC9ks+QxO;ezHCe+N>bo zf8FLfUqm7`0mswI=~{V%q{asM@xibKv#%Cm&FX_}9(ee4k5_Pn+are$(Ks)mt6cX> z!pWf1eE-Q>tbC?tM1wteU{vpJ>>Wo@1{eZtssM4hb0 zXwKrKy6+g?g^b=#nRM`4QCvcC@R`ivFZKYsTVk)@{Ito^$!pTl4hPR3is|zlJbMls z%{*3IKX5DS8tkz8Wu&M6QCMy_IR(4}|CAG-9-WPX-s?GX4GW+?7#LlzAjm(?=5_MTDadhV&c<8yUKl2yWG3JTYJf2==WP^M%`$Cnhws|fVuhIk+7m& z^^UqLb*jFXORp;nwP6fP|L_8rP$!8Dx0Y#!;KmlwGyF`) zUC8h+ONN_Z)PeE+B&>NkTH|&+9DUGUv-SrtnF{mRTvNC`sL`x=z<6-w(Meg$3(x>8 zhsur%pyIrj4j1s{Z+{`*Sv!L)nFEflEk`eZ@E+vyO1-xhr7u@Q{u5H80PzNR*R-#d zeW4_%dW6b%Lg<8=?N?ti)9A{k3GoOw?^Dc@ip)43cbzm*aR@x){uaz)z(;X=GPSmG zIyff~)m1$PrrFQ2R_ReqE};Gvl&zIreh9Ut5B{*5BFii>rVrXbnUnLis<6@pJRe$r zvFc(s>d1A5#aGyi{rrEv+zvxUuy!4I1D3NEyWr%ZIOz-=Buad?IM)fxHUtK~B6H0X zDt*m?OF6}ly!_a%}9i+%)nz` z)UzghNz>)W9)0C94pBPZ(UDkuA?JBt?I|}GSm0904c=eXW0y(o z;!5C5OTJkGd8K5#)8r4Z)@SB-b1B_6btDm3-ez0jNKE-58^F3K`lQxge95& zxJUJaH{`Ji?Y~rwe&@5iC62c~F_w@&LFG@Ub&pD(f!gFif?UU zK{)yyV;_P)2jftMPMDjT%M%#A;kl>}uV)%#9^7HcTBSvoBSkilAQH|i_$yscC zoukE7%(`qcHK9eHieQM<{i99CkOUOZobW3w5f^`i@5dYs(u&^+`xCYd zz2rh6aFUGqlcu(G@;>Y%f|ayW-5iWn6|)V1#h{^AkYIM@PiW$rU6(SSIf1jjhvBxj zJWfTq(&0T!R-}O|*LCeC0t~alfq4>P6txTd^w?o13GnJx-1))}CO%re zpsy$M-FR;(0l0Kk5{Bg(;4QW7BnR@^b-djB3C(RwX&*2BX=@L75`pA+}Nj4 zFiBJDZ?{{SVDYqk7Fr>K8}WM5VVcLg0e7vh)MMPK8v6BcHRk+$3VJ{Mi%L#NG)?$K zjoQFBD!4ftsr7V|+SQ~PI!+~w6HmhKOC>$RiuAWHU#ws|O-M?>AL7rDAQQ$w^kXj| zrcSiLPlxM#73{3w`2hIouTyi4%jp{m{Ce$-hus3j+Ed+V)(8EMRcC+f<*I#k|0abcXH(=S0O%}3CRI2E9l&*(T5dZ z6YOPilU~DUw}jJiw7dwMU^FN-vv52*h1!XqTQIC5Z-qeI z-h%Q9@Kt9&v85osg@>Q=})O5hlmLm8ez#6{um<{sbql&!jQT zn%FQEm^BTyG`O!=c3MB2%aJeb-l2|+8@gOEMZKhJwx@JQlL^cn%HZ$oz2{xfDljIe z{VZUNQ`r^(r10R-fe+_>qXGC;%h-_^(D$GE)9gNMJ)uULOR_kamXgI<*Zt*3{72fPu>R@Gfn;9;coH%{x@BhKBqf|Qlk*dG%k#_0TG zn!?|5zXbnvx<4*neuTWWJ-yURK$Gycgp|yEQB0x&B5!$T!z#S+Ut{yY3>=Kd7INLj zRs5aSb{o73X@r*dZ`;?lWVk!daV$Y`qWh9MCT^d}!w~jOm%uq`xUwPL*Wr%R5gi5= z{4rt&0${EykNjA0p3D#RvO5J2j26^|u@cOd1nRc=o0s84*ljQwx;qAh1wU;$C_=)8 zx*;~42h7*-#&C$P6qyB^$;hlFB)*~HZ@_dHPd$M~%o|oE`SGz@<`5FESc<_+pCJ_g zZkKQ9tU^xP-$N*#QwQQ%eRtNH(azKX4KTgLJTHP`EIPoTv=BX92$3{uUf)H*8kQ4@ zJ@zzE1{+bD3-<8EZF3MJWFFwn{eOYE{bMQ>F?j?FB=&rQ1zIUT_+-IC{^ZUxoa3gPXUk=2#b;bFo9l;LpAt z!vXZ~i`Zoa*Of`g!Vd!2j7e*+;#i#}Gby#qZJ2Qb3mmmzFEXNyw$9`dY zmf-S8s1<$u>p^EAmUWwjv?Uzm0B6S7wgjtmXp1ix z9;%AEDj;9u5WXA-I4+Z0dme+I*Qkm57dVaE)FCvpV76BdY!18Pk3rN;Bx{umO59wy z%5@sg=|LV7iy3o>pwK8E<8B~5nU}=q^TnB&c|bQF5dQ#7Z0+k`D5)^oKIMZu`y~4c zv&NQt#8dH|;JS@#wV2f~S3dfgq(aRcqO3N9|26Nf=>~z9_|Ng5Rc#e%6ApTN{ z|A>WTB%XUQE_@AJ{rUCnuzod%ueE{$Xfx{P!cUwZWjYO7@YR446j(_GoMI62TMIWL zAcP<>P$h3SB5X=*$;BWvE+J)4YBoLk)weyT!EOAH(-bW=U%+g<8WNFhZZ%BNu=yo> zqolxmq}Pchf)|RYMnS?8zm}rGsr3|R*g!<1B{nOA1XIjKHx7;rk7sp0S?NNvZ$MHY z-t|JrWh$6RB!D4?**q=^MrY=E2zl$Z$~gk*^qgak!QvTykc>W?>YPBj1Oz;TN)(u> z?AzHHg7o?1gy;uTWc{)7n|F3Y_3}$kL2&i;%G89x-V=i15Yau5Z$>VQ*SG-3?W|{ zu5r(|47BTLD_pjJs>~I*{abjRH~4idrQfcR!RAvN$oh#!3=dEBzF3caKD(Nba3}A) z{+X;NdV?w--P!VDIc|zOR`AonG#p+&3LWHocf=o-m3px~+>N3cZ*t|A=lJwhLD;j zd`-N&^OplzRp%=+u1rH)1bl+0YCf~muMHMI@%o9gB4&Ii#5&JO`t?BM)3+MF63Bs- zGRU){ZMd&`ZTDO-_b@pBkkoXIBc2SdORa~xg%BG+C1gUF;KYk>$Fh{he;T;^v0aZDP#CB_i30aH}ku@XLYdNEp(M^vD(bIudhm5FcB2dB&4< zO_V*p{}$oqaGClkK+m0XS^_uxwQK}fy1p$zE~_lR{4cQq>%BiFUVa0b&(O+)y{wXn z&Fh{Tmp;G&LuUZA4v0X=U)D0wmO%!C{OXQE$Z1yMb|8v`yw)@s_bb7fI`>6q&dFPx zcf&*7#h{%CdG+R)RZMSe;!-QjvVE=^!0yT_Txqj{sl_2oenP(&Ko5%yqGBg^R(Y~6 zIWbxh@FJS^68_?2IUh}uyoOqk0}xcHf~0>_B)Dmpb_1T$egM&T5Gp9lxc%#SpO=R{ zqiV5~2N&*BQDM7rM{U@O>Wc$6axu;pg_$?Nj%7PIISYHI@8s5X&^ulAvu>onbar@# zz&=6K?{uKh#FLcy zer98@4bFQ)Bu5&9RKSt!*AuQ42L%QysO@u*iG6s@--9&nnA~2!ZyrLK8hGQgz?6qj zb4Gw~^_xK+IHcCDL7JXxBM&hyP~usQ{b0WuEbP*P64j``gO$T?;ru%;*KE8zbq~1n zs?CpkT9|b$?du?B!rXfeVjFfbx(S%M0UU)Cf>gbgBX?-emSn?TZmPUv&g0r(-3+`H zl%M)_OT1ri$aQx&3cJYyo>CI|_MSB1mWTGoY(d0PxN;pqW(MSNK3YBnGu62J&Q1|a z(TzjW2nw!jUYX3)S2f;x49BX{ISqAeY?{v4KCV0AE_RLUPS~7P<3_%CE@LI8%8K63 znoNaQaYxOW572^5qo*Ob438&^14@;8)ecZDk)yji_N9A_$!XMym z)NeQeo~ZZ@61Wp28*919#GPGWq|{8ib+rR)pX+>R4#odW;}r#rznv*BC;-4qfS+{) zL7+m}M8tdpa+|OM9u7mZOVZ%&9lnQ$7~Q#h&BxbuIKm`0s^qudgs%LDYV7*IRbyAp z{<~`Ie}qLM{~s(;tgcBd->Uetqa`KUEn3G?y2cdKq%I4*6FPkH&z)KVHaUAx{8>Jd zj_)HHa|oY&z!?De}^4 z(CP3M`L?V0{il;mzutaP;QLdq`rCc-5a-)OOde6z>BDp&`r9#~-NfiSUA6cG-m#sO zb0@2UvxHdDvfHP~yQ$~wru8IvaUu#obJ2Pao*rpB!NBaW9vt?ndf=;|{Jw5&gS2PA zp-cN)MpK=to$m);nV?YH^HoiETP`f+2@K_#N7P@+v9XD#l72=k5>gPuB3H{WHPMq> zQ;5w=S}b#EKZ>K5+-UBM!aN4|Fg1oh7EEd0XEUZzt@YsPVuIi%fi6c9aeK*1pu9f77|fDS-Y8UF6_W5KDO!Gc zS2`s>uSxwFp3*!gP+8m}=xC;F;1`c+e7WS*uJlu={qE@ij!=tV)nB|trQRh%_>&{} zFSmmOtY>FupPX1m$PFGI)70AYW8$k9Z~I@Wc5~f&2UIlet9Vmsyiy-?u^)tsI9_N+ zW#sPp;3YF5{4D_@=P3Krvm%q=!=f^Q=JnGX4}G@Nt zgMIJj1jd}kZX$Lz1bUqeK^XQdi-;A)sa=2IPT!-^rmeE>VUDkx*q3phBDY;&xL0&O z_o-C#UoN%0p^_F6R?aeyy^?peu%D`mc`ZIwd=OA=8QPOnJpOhR{qlENGlE`da~w+> z5u$>eR6p9v*425^dVG8?cfRxXsAEpVzCRC(9xJ?;Uz6c$*piI>;49;h{$TNvu}s&Z z2wKzDUtY!Qp0$g)znZme^X#Zy?9!DY6fZX(5w!14dX|V^`07J%DMdU-TIcp)r_a7VxmA?(WJ*1-GC`=F zWhPdV>|^jw&9~%yt_S1ww$uYgkJ+}0gDE&O?wTh3mi*BR)mfZFs#%87vJhfvO%xCNmpnp{jb~D%bzA)aMBkBY$ z6WwC*mTK zU)fKd4-d(hdL^VIkDTj5pS>~Jw3N2wBS91+* z-BNFs^dO}Ib5dpU<-J<=5M3_)5rt;Zk9`wxDOQHWsoi?X;!JKOP$>0tF)0WYk^ zElzI;CvFbqm4cjok{KQPH!3yvb8F!4Kc-kiU1fK3Tiqpwmb%XQY>tSnMNxXi(!RYw z4T!(}GBrBV{Ap)x$4plC18QrH+UwbmaR;_qhC9T32+r=G9cMN79*>Wp1lXcGlmu3^ za+{WWRs#zCpZnm{oes6q?Ennrg?{DDX)Ma=(exWxwEYy_v2yUJ&PK>3(kyeE>Hv!} z$-2R$QpLQS22b{=yv85Vo(}sLg*s5OJeG2GnBrk{c*?Ul{j$pV6kfHcT&?kKRluj; z+vS{{y2R(R3vxq~gxZfh-ciDb-ZNYD`tUP6$@gkl5qb#I_8bV$P-n`J$Nf>MLF4(j^Ac0*(W!?=Fuq4~HSEQe&5)5l3T zbThkks}B9IGL|@Ux515a4ZD;JRFB+u^*=l3oKKh0Uz}IBI+vv7Jyc8$ zE{2)SWaQ#>mkfL0kfbGs_}bv(p=8}zr_+;qyPn`>IHUK;);>p;ma?S1{#O5Z-o@_yL zBIMaaU++PjszBwU$vcjv>ilzh&BFtWYC1#7ua3Pxmk`XWs)!ptU?oxW>;l0>ZLexF z=Bi32^@O(G9%CaL^_!9F#L>TJMex$5sOO3K7t9EY$l3E9D6eH}g1aowpxlY%jJhKG z-J*L|=Cc!YUURCj6rA2~}Wd%;QZmD|0G_@x~in%{02qn-p{Do&$n|kYtOfRdqs5W;!yNjto$q+P<2)cO(BWgFPvI z`{TUo^>}l0H%xlmOs_XOv&+MM{n3d+d1=$4KDG4XZLMilI_V*UHy>RIpKtlqA#oW%q~B*gw;dnN{aU33la1?@Ta>zuR%Ymq!J8wGz`A zGw8`;_WdJJsg=S1b*@@cokz9Q#oJVKOK|V-NE7LF+0O&>rB6;Y4^++bu4lV;-(Kx@ ziOt*AFI6QIRQSYHuEt|`gk7-sYxnZ&;jZbWH{Y4e(C3g;tJ!A#4~AiSSk~S3zAE0L z!E_#=%UNGQ+~v#wsOFVBN6-Ce%f2}jby%#QaGJvhuEb$#?F}|7Uh>8>se)Ovz=zh z?;lH%{hOxaR?kT7*-kl;&>@bq9b-*g?im_N{zt7fTI%%6@g%R3mA@s1YR!!vcg#>? zTbB=98cKfWY)V`16!bP1mp`L)v5{_a=__8q<6idf9~4MGyOilUHwNSwF)A-8uTvO< zR~c98soo#-9|T}tFJ+&utoh4qcrp9o;+S9i{bNtHjT})y|2mX5h?kAXP}7OnDD~cP zUBEi~%NtL^wk4O96I~kR=MPz}Jf`iRAt5o7_{<-%2|hc)KYQJ-%lWL%<2o|^cTbLe z|8%U0iNpW?-j9s(^sGtxkXFL})A2;h$LSx?jm^BNK0jRo#h#BDHhz;8RrL`bKfKB4 zq*!P~I%*WwK7QaUBY!^3J~gC;tY2~X8O32_?_P8IK_0rp4wVvIvH-8hzQ4W(2HbnR z!-J`gQN*2S6Cv~#EH~3Hi*x(;=p4IrmVST|Ouk{jo5%U&_?h`ytGTsC?q{=u!<*O` ze2|HjpD-rx^X5j#g8+hJUe1nG7cA~bEH0Trws;Bj@x$`z1FwZ_;J2iM9USkOLI81Np_PsY6#)qu@UGjf#QVwXi z&v9jijGPaj;}}wdv5y&72RJaP7CFM5aEL%?Vtz22w_eT>m~3k33W5#q6&|ngT@3p^ zD7k$qbVH%v$F%69pxN-->sn<7K??gjlj|m zKEEozxySSq{h$!b`Am<*mb_>U0dKkwtM=7EFyI5{F;=PjMZ0R1(dNt|^<(kMqr+>& z->SYk`v3OZACLdz7K!>dn8^hD-*1tBSzoz)*;>od#{K__X5w(sOtOFc7n*65Y|!et z|1+7rF4b14+S4YLdM3#?s;ABA@cX{Kx(2wXw_*>QJdKX7#$s;!kJe!Bl_SOpzIb_t zI%(Upg|C|)~svUW(Ic4$Yf8NB&7(e*c? zs{k?gp~t`jkAY~9fe4R*NRP5-9vcUVt|G*?6qZd)t45=8&Qx;ESLN2JWXlF+@kZsU zD3AEh%4+cW#~yw{#J15WoAPgogycsWN0sk;#Mdk5OeeR)|0a@kCz2(mk`p<8!ofQ3 zg2a4fi-3<#G10N7+-4jlIOhKZ&jgV(xtp z`?Rrw_G0m}K)?F5c!f^)@5Grl8v6U};$Oj9`OiI!zx-Ee@|*TfAqotZ$MSeV`Ncgd^Y0uiU=h?LPUu~D(w3j5e z50l$Frjw~t$-eO5m~xw#mP7}c#rL<6wL|i?L%V8+4%9-3^bjhfm?xyzEu`2tM1eBC zRnR_!DBD`R_4U_9O~{EHpGrRd(s%G%{?X2Y)p~axv1?dn3X!7T%p@ zu1sod;D>0aq|S^-AXrCh{**!zxD!tXM(EZj5|e2k1_OrN-niPXH<|1^k!%TlRIgn1 zh&!#SVm$1})eda%RKULw|J6GdA>5uKZrWFE+G}sx=WLo|e)~bZu>o{A#IHrD_Z;eIVZt-t+N67pNXwxzzhzkWOaCr@1|CquaK zSr~a5dDKAHzxKe{Z5mxX8U;K;_wMr?nD~wF+~;lozx>b74npe1lEQDGc})MKd9MAt zc`UX5d-MFkU8Dc6t;6On&)c{CSL+O`?WjNh_oce-6}HKMYvw(XKlm+qXEu^AUaiXR zSX&&Q_$eN!c>De~-Zg=B5>b2G_B}Ta6@2a`41L(fBXIh($HX!Xr_IB=|MsEI&;2Wy z7+!(XpUx%tBoG!^;%~T`sN==zDTy7 z=flVBx;%uTR}fl}X(Xv^?7~l=w!P>>QSUGeG)#uE3kHVBen*CZL>|!2d~rTl<`{z^ zHvk$6Eb!nCda=DYSE#NGgH-O{Ym0qQdUMzX5}@gD@PEcfbapY-KqGJ|M#&V4fsp)> zRB393(fqhtDk8g61yg~^2+{-KoA3fo^$OJ>l@Ekg%T|>!Wyt=lo~=5uJjB9JsElKk zLAs{0+*m8Kl_lK&!2sE>0#%KK505J+EPva;T?=(Lt;B_Fox)=cZPU@&A|u#^#S$RH zc~g3HLy59u-5tX4Vx&ixHELBUr;kS(q5z$CtdlT`yb%iIJk=4lp=}S_u!#%CTd7KC zz%y$=o!2ye>;EuF4W_87-9VOeEr(K|GN^_GO3tM zf+kdNgpX5;9B>C59=9FTaOmuj6fBldqaT{vhbr|2ARo}^LJL?~8v`ic-9G5d4J($R z3w+EH9sv0s2zxc)io41(6d%DlyD$t`AR)+H=C*i@FQg~*g-=;R=b+&W1~zb&9TYiu zDu1YdGJIVhBfMu!a2V^1r6iCNoL!(~5^h*X6=_INqZ(MkH!nQ|a$#rayt^wVyN@>3 z!)hQg4VIReH$tDoKbwXs=JmxWnIZe)d=18Umr$kOwp!=pvbh!HR%mxAvVR!rn6iNz z7G59(rbDcSRVF~~uKA0=p9XR`v%Y?gyezA13((842#GzGX*~L4L84-^DE79*!kbTkY zp6vNL`Nwjwl#)@E-%Sz6j=9l-DI+tYkWo!uC$>|fgGeF-N+>rK9*!5RL zT6HI5wUgqBxSBu6`Z4O!VQIbeRXHr=IVNfCYSWu;yKq`hEM(5EICV?B=HRG7s5B5Zu~c7|5lhYsNd9s_A16!9)u(G?XLo@P{?Oa3xuwi53hh+hzG(FVii%iW}l_V<&d>EsBvG`Rx)azl$Pdto(-NG|CR^^za8FYAPOw~Ss zlT?!sQuMfg8ibZ0etKo13&sdlT5~TF@8dIX3=|8c5PA&6tubpUzkxe+@^>BZp_gos z-684G81Hk1K)P@a0FIT|8b!M~+PQk>8c@}*YhM)xfE+CIK(vjudxpsE0=tu~?hro8)blTqAUIBD=OfnZo_Cl)h$8RLlGy;| z){Cq>2q?NkI9PlW%3~{gW`MB0)P}$Z<1jc(Lxel+Uay2hNYP?`0f;Y{j^_K zcqL`;BcC+_x=fq;fd!jbPJ7N$;S^g(gJ)Efi_5_J^YKH7Lw(#Vu#>W8%ERAc?K|g9 zxe`K}B=#`0V)s%RWLNXJGqRM3iM&tLdDloB>-X4y|wJchdb9pd~jZB$nJVNkI zRRIrZB);o-R`~$< zpp3!z^F2T#9LnQ=8t80DTk0!@RH>iWzXJ}ALa+f6MSU6u0WodGqs|aSabn+Th@Lje z8Fd3y3!?)I(S=KIhCxfsm-RR!(#ozS>N|)578k~d+yPUzX*5biik)7zhv`ZgC;}}+ z{jy#@EL!|xhoXfmd-NSIfI8Kr|I-8lj8%KN3$96=t7MvAe>&!GgdQR zL}qQpR5(DaY(lt1$iUV^0GGKm;*Rh_8$NNY#(ert&>x(uXI+Ve#CwjdNzX+X%2{QF zi{;!+^DVj*&|tAwn}E619(2wWFcUOcF)@(IcOB2>g=g5DbX$$7%~aK+b}i13QSV-zP^Hxv86(s8pZ zlo{n(Ym;!6lB2B*5M!xm8VV-Nk{JPG4LpGaH&n?d&2-$4njgbl*y}Nw4M`Btv$p3o zOiSq|-dw<7n?U)lWIW>+8|V7qUl+ajPj>cg$F*TO)( z#qK1B%7PZE)8+CYC=O;uBr71AEiD9NG~1 z_eJ&pQn0sF8FEj2f4Zu^OM>AbE%PO6WiZaBrkC9a0s+oICAX!8JN+9Vom9iPkxpC=PoZ^f?rqpb@VuET& zMk#-I?Z5 z)B!NFplaV?Ur@EVV+P?=Suf^yivr*o5?g3o7|NDIJz0YqZ+Z2G--fc;f8pz)>^ZhV zi>a_`|E}QlQ>Tv5oz_PCLmQU#?Q7l69vlCOtL)4;lNU8Y)9-Dk_-g|hQ;6mI)-%}G z&NNDY2m?p3G0I0Y2waxt@(AS+gT3{Uo~{RD&^vgBWWO#$8QOtV4)V!9W{lv#_7XT+ zYzC_kWjRHc`b(H!m?VvxKSd|W`S76$hC0tzo$jNPM$3;5yq2f*rFS$g^=B?Cth_a~Mkq;? zE7w6r_p0$bHS;Y6cNoDSe6LjblZ%jr45y&Nq8OXxYNxBYEo@bRvXMVm{BJ2Z1uUmN z-%s57mKbxqT=b1?o3?@dvR5#7KeQjUNC8%^lXZHhLIV^WInQ|m=d)G}4*dv%(<&9FI`CTEjGShqO4a^{(=+7 zan1s)y;W-GSAa@!T%)x7Q*PU$dC6XGY2{YIkdC-`qaQ+;H4m^MCc8EHAQ7Zkoa#8( z(24s^`B{CUCTQS(GJ@u~R7g3?fRJmYRUP(;KXD#xaZ5<*UTlMxhD)2K8}4aS6GBP1 zwzND6pcw)Ff#d))6Z3<*6(J@k?D>S*I(6S-!t;3rgjHNbqnc74qRggK$rZ0$3M z>@k(^HkCj=Fe7h+ON|-2UKg$n*hX>86{J!W`!<9WMzez;>VBq?4#`Oeq!6_`;h-Nn zGzYPusll~qX*Bj4t)dVJ2sKZQthg;WKh_?JrrUr0N(a$Y8;AKf_nGs0!{C|2_-En3 zFNZh_Oert+M?ToqTM>XQUE;T;z-^>l;|UxWutlyQLmyX9?mvzI;hAkG5;nBxEyZoDKDNng6!626!!Z!ht66yxWFW!m zy`58FJW=zz`yQTEYO@K}+ULs1qmf{giY=I+TBm0j_*b)Y1k!5x@EmDbPB`~H->+pW zUzbdV9mY+q^$#Gkyi+l+-bD0-7PzJlPivG}j*UV zIo<%MVAzOHDoDp$KT7C0kYq+eQ$*O-Tl<17*02D?p>ErP#qAV`RgW@EB{46WGA0&UkxJ2f12IF zy{N}O@DK-bw?#fgk~^=2qJg~O9devIKfZJ-g79K}4AsC*AJNIleS_3hEt1o_Wo+M< zs0zdp58sN*aGFrw5?Tah(S+P|8Y~C3{!y?aoXuKZm#f(&!ZB8gwul3VRrhH7hgeXgWfm0@Yj2izM+#Q zdv9*^R%Z$f$@Q~#%S}-)+7-yk!ybKe4hO5+fHR8B=1FI{Sg65~fFKrteAuH=I0*3O zmFmORT&_59({3IVS1t|R z+hKF^D60f!L2=ViJKWDXDQR5FX{k5Rz=x^v%aQN3w-$!VWg6`4g1(fR08>6rl9&6G zoVg-fR@d7Uv`hn4MmAk24v-S@O8y|ZRnGkcl$N2T5%~1-%U+Op1Ud9sK7eIP_K39& zNUwY+mVxQAUOx^OyuioN%qTd{BTOo|*#*{~i@<36;;#*ADV>vPaPAz8Nxgvd^$T(X z5}q&>#vE0z_9O#nu5rigkfBPr@FFlsRMk{m2*g> z2s`Xj@)~NiAu@y-<9Tm~q(-l7iNdy?ue2qOQzA~M<+CdU-U)i(E{O<2SncYs~gCm30mZuJ&v@EW)H8HcQXeQ;bsY|dn&Ow{? z_lfO>Noqtz$ODg}X^aNPh;f!+3~)LLcgV1yzU9X^Oov)Jk+Z~M0#MIJf-*LNa|R@s zLjiV1prYwZB*Q8eR93>qs}4!{Cg#Rgz)TSj^iFGF$DJIA_E zT1099NC=D>OXe`pZay%88A@&8fJ$Szrva|c5{r%GC}$HACW;ldHdB8F7LfI`HHDZP zv&+vuFMX)wJRkWENv1dAM4ButMd?!}i-_2Pf(u@p^Ggl;T39^31F8?F3wy@c>0tTy zAPTl~MFz*Rw2R*0*6eb#sz2pk$5&K<^29Njpcu{PgtOet({GbRI4H+Zt#gXdIKl$^VILPMP$Y4sEZ@}7cvf5J5;>2Kq z<2-rz9U~n!Ak@G%5KX%GI|G&8zam`0`MALho?*XMl^IQ7pcdTiU&2q;hM^iP-j>~0 z1R$63(AdM)79R^0GAl{m|EDjvXIbmJ!JcWZju^xXXt0>uW>H6qTq3c9aegMRt--i? zQsDqBmCB|Exkyr+UOAlfcBMt>?qRhg#5s8ENr+qV3K!bRY8lPna(IR}7$aEF{(zn^ z5(r61^4}Ndd1jt@ec$E#t@VBXwZ7#{%Dp$2 zd-mDw?0xocw|ahA++=1KQ6dNke@89t?*S;OPp>yjtpYv|A_WIq;+0^q)(=2|PnI|M zmI0$E%qRfZ>mZIaDhtgHqVhZ;Tr+6K*vzo2O$pu)x_96DIr`Srf(buA_UXx7v;Y=& z$;UKwJM(<9{pK!yX9SeOQFnZ(T7~!K; z7u`7~;$!TvO+4&hW(l_@7WRF@9ogU30HBgZW39Dpok{A-ewuTq*=*GS?y~b>>H?iB z!^1nxk9~@M!$dAzy2;a_A$TM>t%c`sI8p57ti|w=aQ>#JqVg_&dVy`p0YtIK+Z#ml zKrF2JYbktM>6MXw?0aQ60SPST>5xfkF|s~xj;2`x>X_TH^qXwzV0H<_)WwFV11^i|@cYH*3k`>*iZDQ1jwK>eU8a z)j`=k_q%-*28>;IHU*0=dF?I=%!jGI(gWyBCfXAa{8E-0J_hsA{YMm3q&OE|2St1d z2lYL(r(L0j%SWKTY7;XCL~&DwlqmKJ=?dM~fZ9P+4FA0R+^^?G;K?Vq zn)pm5AC3f_b>}>-K52e9AXBt%UPrL6CxAwf*uRHoTLjiUm2`R65GKp5g2NM$9_>VQ zs^Az*9#fxl1<_!Usl39@kMTXR@8-|YbHD6!QEh)LHomyMfiG+d-P^(S&>Nb_lq82i z&5V@A#fBBTTC(0C#35DAJA!9(T{38#`prjf&JLT#WN^>%rt2i@^oXzq+x=eSad)g{{cmfmCEku?PCd0 z&s^kKeiGnAT~07zF=Kc`W<|}==Y*+0qULkYt%E8h8+BtI7S%B?9%3J4-K#MW5=OgX z1c2$hj;cd5n9&?hh-d#Y`lB!^`i;(I;7Jipj5K((Wu@tg5LM5h-2he9#)}E2OJau{ zhXKm5I7jL>Gz7r;yQzY~W2NE2Y32#_R~3c3dAo0gyHy!q08DYy#1jw{cA1MZg|ML{ zPY4+8KLV-Xw=>DVTRb;HHKnUa2aD>^-;|kM!=?G*tT-OXSY1@+>GIZ}yMOjW>j>U0 z-l~pE3;lr*j?X*dD0!$6pLe-o=-2|q0m|nxS5|};RVmR}izs`J_aKD*Ckw;B&@zq? z&c5LTM;>)h5dofY{xlX{--8k=N&5vLJOi(ZN-kX}JMoT#(E(4z^akc2OvxwXte;>? zY#G;4sZ`ZC*9{Qbvt`7})RQUg>1MMJ7PF5K0;Ow7m#a9ZFc8t6?I9+Y_>1ve>$F-6 zIlGLpFH2KRb1j|804bMPys6k?^3&Z}@VO<`cTz6-%e? z!m3`w@-h4&;KB;!x94quI_E`R4tTR^g%$wa(m=qeLghbc=&C5-`xR_X0hYNqnyFZm0V#q^(%MNpUUes#iJ``df`eGuSF`MMtPM-cKax_!z*ia5j7zj)n9 z!kkS|D6q1G4i|>8&>O-&$#eWOKsCP&UxMPleH}hnFq?#O9HbN+f7v#K$#ZMTp4$!S zMaLe{!%x=h>4NzcA$S$Nf(bq%4_QVz$I-VmB*i-b(8KOH-PvQ1mA!4A0knJnX%c7` z=v=A?nF9r{cGr1|Rzv5_G02)UN1cVr^Ccf%aJ=hm0f%rQSoh^jy4__{a7UFso?p5U zM!_$?M++IHSI(sG(@3#K@mNGlGBa{48qqM$U`J5B$p~Wq$q*}dvDi=YDUv4Aq2Sh_L=I<5SKrxO!x`%&rQ)#FF)RbvptRLJW1B}cfoLO zUC%hv46Z@hfoRYUSYunrVCR_1y7+yF4v$3f!V;*}3k?N*L2^p_f)o~weAt2|ed2vs{Af!kltv88_4^hJY5(>$qFT=zOe1Qn=31 zg}Jyb3?d=0pbq8PFY0?h@7Hi;n5W@VVQ{D{kS~_WHAVN2A3&Wes(Ipc83wEA;E?!1SI_eacjFjBhp0a|*t6jBI`6r=5mNXj{T{Us00puT7g>5im7`%6 zpktEl#SZdGi%Ir5r^@-Ui+7d`P~Iu+L6AUCliI2dArY2kkQeILvp~kj)zh4&UwxyH zMg4&<5<}Rh+&vef!M^Et%t95r2`vILI*ZAQkj|1F{%{cjA?pdGZm439Fp;Y#SXfUL z?zstZaBP}1!h#&_tVBfPKYH~>8jvHj<0s)k^9F7}TrcMxrv;K(;b}@aNRK_u*Y_cE z{{(9~2p!YxnXECo#^Z>GN%bSUt*1U1f0+lDvg)e7s%ZO5;KO|jEBoX=yQzvgA8zfX zkJ2@6E%OJ!+shnn+D9aPEVLqp7dvf6nC%597<@!9Tz`c`2zwTcpvF!*dO|wTKK8;S zAaQWj_W?p&n+m1pG?HaFNi7tB6o#|?%npiSAb)}xvMU0w$AqC%*O>x9QkGtgC+L}d z8V-o3`f1!6fkLj4?J9F!UZViLcUP21Uo~J-7^^!x3uA2Vl$xN>e~n~7c#(c`;FHH(-9rsR1^T+tFq1zVh~E2V_F-4lD^|Qpu2|WxL!jA ze*$K+Q^W}-(PxbCA+kCMzRQv6Lk}fQo(fc5fcYU&WD%%McDKRt{tF z$+w{>(F2?hzfNMVb5i6Q)Zel-1(zx$!1qfWL-4frpP)lD$S`Mx0O&7$JrMx0(l664 ze+sZz10HX`A)0Vv>}*6YOmNpRQ&>>D48^xa)N=B;1&SS!2{zSH2Tm;Sx7#zW>v&3} zmS_sRe@^87p=%J3&>y@8?Awt@gujI9>=BAAWv6gOMGf!pMq z|E1d+hMmE9^iR*RLd0aHl_QWtFAhHjPmE$10D7#7*XLb;g|pv_@+0`1+jn0H0tjcu zN`Ky2cyCYB5s(J6P>doay~Xqn{jHXBRj|(!dU(x2c+N@xAaP(&y4rSP*CQU zDrDFpRFrm96g2H|v3|%ZOZ@Q|qGB1dU65Gq<~b)@@0^4QRG;f(#B84qO5+}IL8d)< zdSwe#;S;g*JDH@2O>$FnhVme9-ksy`>S=&r&*N>1WLCTQZ(y9jNtilbG_8Lbb}4NM zCH$1DJDE`^lk)~bVWyS7F3^%;2vf9+X>F|)#EpTbAeE9^0qGie+~P>o&b%l+bGLJeh3@24$5Av2Y;T7w@}Ith21p z0va}sbd>~olq*>$BvHYRap2YI#F*m?GnST4}jR2!By(w5zv8Ql(t_Y?Dhff zQ+8=}axE)1VY<-xgB~o)72GsN`2ci!x{gor4qMP3WB&Y=Du64F^`}K3?@`V(2HtGJ zmpX!GkXvnHhCg%%n1_Uw=d)`;u^8)Em@AHFTpp>AwXGK@Ca0{ucmFpeC7FA|@1Bb< zBCa()*oTmQ@8;O}?{~s|WFPmiMtDS)Sgj|+m)am`@Fo$NJ+C^)vsHM_omh7H&s52% zooIgvDaitfSV|snb{Rh2a66ccgu7Jh*Y%uqx!44Yrjkmqu`evmo^YT$NRIdx{}_lb zu$-b0psjdyKg~3-0CU#y5QwmdbUwS{bPa{DL7op})T8*4>BYg2X1*V25e$nSc>LiM z8a%ev>~=4}TXh|-q)0&yZK)`ALIn6*-pMz8JCX_}T$6#8qsn^Px@d6qZb})B8$t?z z97Qbmfh9)FN#=4agv`Tv2OV2_5cX@XU_O`84Fi!rlBf=wv^qu_^=cWH6U=%@dXS}b zF!DLr%~v$r!~X_=?a`$iGe9`;Q^E;!^DQomi9&LNQrfU$bRLjWC~a~bzvP|pc4}q; zz^6@`^)*EZSc3aFEdzM52~N3Nmq4ZQHkxb$)nODC6FCOCLw7u<>Ig)+S=ZW{@JKH4 z{Ok0C@UBwq-kV>)5>3DTOwSj2@a3+t4r}PUBC6PLKV|BV+?6N1 zhUpmHD39Borz=3jM%qYGcIIiqr+a1iWl0s-P|{gQ+FF?acBx8{T~UIzHmV)V%|U3L zI+6_PUhR!X>qC%y@7H827k@2U0j{lc52S6AV#2*fAhm~geGN`lRETueZ|DT2982h4 z;Eo*@ge-=RL!u(A$1WOqL-4YNnyUi6TO0dA1>lKQq&tTo+fLE$&U?L@3ieof1Yt~1 zPw5A+)p)R^|2`lg_9h4bA(Y$#!&jF9ez3&T3E>)E^t7IvOz~ow*)@8MEPAH8qpd60 zxrGgWK|O@%wh2Hs{oV9$_M?<5)zM-A~;S z9~q`Wv0s)XNm=3sZy}N9pNN4SZnGB*zd#b6Ha{a5g*@{T(F39_ijq|^M9#DLG2EVM zofJ?I^(@%6*D-N{4Ko%lr7ms`S?nI5BL`& zC<0My=DRKu1nLGnJb=ds#XH0x%j)ZD>+b?h)pyRm1?VSdA zydt`@v!)axLtaieEhJsc6#%;@L&T}5(<3B*_00TRnC%hj{?qh zBC`rB;))k^?lE&fCCwiad%}59h9}a3o?;V}_3J6vrq7eOVY+VW!6nfroU109N8y+j zv&Bo5li`-@A4Wt)&jy&o7pi&53dF!k9#@Se8I#kG(aXMREhY1$wIfV0cM*=jLN zj$K%s@5zJckd3e@ogWaJ=(axrcu&Fi{fjP$di5M>MqTxfUkA*ux$+JS{B#@eE??vNuFW0dWYHGy%|wA}#ZR76bxm z-jxt(&wptSSvm*24IbwFre+L8VA@QTwm?VAv6g+1z8kidZ=0NJ#?OOPcuC)9&wyLsI$2}!GvuO;?F zBJ~h0hz9L6!unRAAA(>}HCQx9=I{wf`K-S%3ioi;N}PpB;i!4+2Z`*@j1Ga#TO^wx z%Y)FHZL*8p3Q5MZK|O$ON?DSs__{!P2V4FE9M}S2T?D;+06np249g3sn7*8TK|sZv z=Q9LZsysd;2zP8xe}#MA7gljO8M)s%fhE_bP~|b$-%2qUe9I08CeNS<0)|#Br4FrY zXi|pzfFP)DvE-x|dOGh2Ku@jMom>jgq9u*V!)_7>T)dDpgr1ykC%u7D0X*+(eqN_fm!By-%)gyqf9*f=j_qJPkXwEUoKvmNNm zG3hz>+04OZpT^tNju-6vhhUd($qi?SCxp#FFC`>+Vu69pF6_}XFI;MFp`3KND67+? zyln@dk&%yoRtF4TUh_+*A*!t=Kg$IiX{I{NkkGkQP6 zLpU%uFSs`xoiKVhnDzS!)|njWap0|ktzGqx$44DN^tkp2!0cw6kc0irCiBb!a58N$ zCn4#mw&Vc~FgSh~xTj|~0qN_KtH?=*F0xtaGC8YRWNFA3Q6yr|!5)7aio(rQw7zul z*bL!u%oR){Yj07^c?ZbkI~#2y6ZDkJ<=-)Bk7pxm=Gbbfo@e6?K;(Lc>iGAlH5qbA z3@_(tqujV7Fwx%kH+di)14sJ@QI15wAGn$ki`3LPDf)7($p!5U*b&)N91a~X3OW|| z0}Jvk@&UlL=R$Qda=#dCbwzZZ4LR)Hik(m4WH!Rmcwq`RcxEfIsfR2f&E2pw`wIhb zS>N4-9TlvWBTvZP(Mv)_WLWd}FNMGom@iHR)`Kcl2bYSkmUmC|d9+}wru3o7cY=Dc z%K?U+lgUHKO@Znzd`onEd`i(UnDqwYN*MLS&Q>hJa~?azZe(sXn!2{Bk~ zVTd2>;#?Xqhcs|*f+}WRQJ-!LY_PyY9>rsSPF_@Rg#ALZAD@DM;Q0!VZ2in~mwi1H zEiINrmK@L0cE0K8=!Z*d8KjdTc#NnmO{8AHe=Tfa(y(v~hnR^;jdD0_)a6g~`T<1P z#B?2ObRp#_KtH9Wvmueh)2)eaxA&x@OEz#yZYyBd+ zd~1VZrdftr2{3c>OR{MSHqF$z8+yr#C<{)5lZ|!hsb@Sp6~YV|$;stb^DmJ_^2#D# zmK|U%YVWC^iMXlpPA5er2YJ%4z<^EiYqe+j8BfkbJk?VPdjNWbIK_IY zsv{GU`GwWp^wbz94H0Rz$3_rh{GyYJfmHDJ`7GF5hQ*=7k;HP<0x*lh<}WM(*tltf zF&1D^Q%gCp&B8OH99reIItoyWmz6;sbYw_^*L%p>8cJL7n1+OVWFpMP6ck*++Xr4 z`lsv1x4hr_=<}6r+XsGqB^kcwcV^Sb1N zQ*Ru89HX>Kc#qO`gN}$*X5M<=zzDlM+^bOJCg7hHzM;9>-R48H!a3r6oz+S;cH!<} zyyD*J53Kxh?&hl7sqcOXz#qoOQP#!}7)k&lBmZ=S(lSRG<+11@!eOC{MTOi#beoPZ z7!?5`jOp$Pw*6jfrf0;t_q&JVCEP-M?LU-wrf`#7f&|=>?@Q3{aPjof?eS+WKB#R}NOSJ6JV1ZFE{97ql3jtFe~*tmUwKf#VIh-SFACH8H0PLJV_J^e1ZHQF zX4_V#l@)QuX|u`tGJuTnPz{nEN`GoUsxK7I{5ecvvdwTlED91EKjY z2VN~`d5X9bm*j%5C{rQXxCGPZZ><`lBnrvg<}~f|r#*(WWNtZ%;)k)OZjZ9dTuZ`d zx=r6djZ!(Crkag1E`9oFU*a_Xk>hI5D>vQr#8ht{Gm|pP{n?NT8_2sYTKJYU(nuB< zkI2xfj{DBHJ`hkLHMGi)(fLK_7qHQ((D44yJ*HLMVfECv%~_n68nn?vg38ldj~L3^ zzu3oIFLcMtzg>Pup@nx`#lXwt&>0f?%)W9Fz4NjqVwraj1}3$bXf8I5-Z^31my{hp zlfMmPMwRXsbN$SEOFzFmDRz#iCw);|){)I2F*vi{;l`N#HSVvm^w0{%xVb1DU7UC8 zgAsFAz+_+7iNdqI2a<?y|{YIqav{SD(wY#<$8Dhg|g4gXipv6 zz-t}Wf$K;|MvfSYGG>{dK3iYSE8VZfE?(qkUD%h6HNqtD$)GrW%pPO2`r~=#Ii^?R zD)P_Y3x1;_e@l1j$7*|d!_;d_h3iHti|;I#p2&Z8mTq+}sPTT*;dIxbN0E*+^hRZt zW>oOro|o^doLrZgLAg=Sx|V+DO*UUI=T&)8kc5X^3 z^POE2Z&Y|$W3W-}qLRCY($)pd9i_{=1f^TXBeBvwLwTosJ2q}M3DA_8$gX%=L;dMO z;Om+I0XLzbgK;OjbOPD)Igdr!alb8Yo0cBua((2&q%{;Dr;><@S6^~s3fu$|F_Hl` z?p(VK+}Y9GJQN?Egx)-f4-Rfz0cRt^wz#EXW1r3C>6gXJMn;RCsNA@p+93ivSjv% z`dmIk$aohbjOMLnHXUDje^bKSbmvBcHWA61+SjMH2r`m449bR_bI^(pPZI9G6o_tE zdc4#2BexRW?T&hHX@UIc)f5|vLe$_X2@HzE#;1R)fbL^vpP(Ps-fX!GCv`0J-zb z{qefbrQzijm1pTa)r-X!@RaxDkX(n%cSa+q6LA$cU!IG^Zdl;Z%XwdTUzB=OhV~=m1|Y&1;9bZWr@XP-F&=+^yRuwfgjk zP4C(1(}&A-$09R&bw;=4C6WupJAAtr-jkit`Jvh$t+g-(btiA z=g&CvcXIi?ZT4fEi@g6_6Q!kpa)z>L^kqcVqel&>d8q(YAtzsv?y4+G~Dzr-Yk>?+$8JBKD6A9(k+s`GdPfCzpQ+!sWTETestkFf9Rb*p>mD zO@OsfE|z}QRM2F2-R2mwNJh=X?B*Aqj{bqS1vL*FUh^%`Dz%s+k5!ph=$*bO_sT8P znVkFc{sqAxRFD8h+`1qQ8+f}Ryz#>%J(_oCYi#CmW7$|Lhk8Kp!XdAC94El`{T&aL z%yK37bI6}n7r22w;m+X|Zjcs387er%zE>w_9j|cR8L+#x`Q!@PYQRBATeV0dsC}*N zIa^0A!BW+ak7_J%p0OK}vo|YitCko91QJXRY2x=MKNHutV%`rH3e}mF)VOJ}J&5CH zqk$2rXAVBCwn~q9e~0yXfU;luvceh8iEhnoT%1_Ty=ajC!wO#gegx-!iJD&+8X{*e zT;Z;tI{zY3-drP`$g{tOh_ihErZO};Zku0(?zIe!Je7zXy}2@P{H_z~c?w-Snd7pZ zmFLaQ*?!U5t)wvdbi>XO(}@rMm}5a4|AUH=OI?vW?!NdjrzR7?#lDK*swd$vb!>TT zgeKX0O#arun=664P1zTIn@@E;C#@6_y4!a0rRFD_ri(-NyOowE{df}2RO3klubpK^ zYcmOVz0};!1V(0+%S}jINoaTD_ucGQy!C!5hVyjBoD~;3qw~e(1y*rG zt|~_mpUHb0B`TiT^F;mLFr(BHAUNOTdh4GKCvuBRZXtI(V(CY7A4*!ZD(u+C)2k%= zDBpW}P$J*EQmUHDrn%h;`}FKIGiLFG+@YR3%S4{3*6Vj|#5NuZ@9BD4Ng=*4l)HR3 zJog9o5Ot@X`{?p-jlyhZR2S*s;jiA>Gs?&wF1+~Q9nC;|VOsQEI|%qN2LdKp%a9?%ZR6Sa!<3aoglT zcW4HN3)Iu{?@Q13Dz6~;lAjB+D7QEFGA^6);;{1(635kZGI&!`r87Uw4C>q)vze=G zDLEdfxx!qzyhFRN?EL+uXPWM}ZmS&C@ciw(kpG*g*9UD6bmnBMZJ|bNAYMJW1U)@p z@V`H9G8kLkxw!wp*TH`!`;?F>(Pfij=N*w&f5pt>j8V#tv5T_qaa#ySYi_L+ZW-A- zWb>iQQQ0`MBUlqH>Xo}r4;QDYG(TX()0^om`RWGw&}POl#akb)iK#k=`{v17-NdBw zvOH%mSr&GAZ#*Qe^T@J}f8>ZS(SY(EWk|)p`b*m;I6mA>b<|9c?EYiy#9go3kE=mM_%`{=l_^l^vAwfGV0lB%1-@&48e`u^)rnUp<-tH zG<*kCB&hFbuFG`F`MH5UFHZq$*J~mh-JMPL3Hqy)h`A~d-e1a#OFniA=Op@f7H=9% z9bp_yWIqYT8K&-Q5EVKdh;d7rGH)~7GS&Wv@MfX0UI{nlw38J>r8(<(DucNzYmVs) z*ma%07km*v^`WsTeMYLxTtk6*`{sws>XFZ6US)02%Zq)qJLNaxUUX$D_u{$4hTRh) zOY(mkZV%d9f^@T>E^+0=f@^JDs)mA^my_#cqn}_edFV;?`!D-;6ehOpOAh3*8YN?} zgsI)Cu;oF-_GK*J)+hVVr1ev)Mz4oVwLOg4VqR=>ZFr8@zESe3z$Cw49>t>Sj7B)Q zS^qN)hv&GHg05P5-nfHW!p(5ITMM1CY=*m!@drXQfKzQxZV+?`llkMo`9C7z|Nrj4=mY2T3DcZ%bZnpQpjo>AtShI* zl@!0^&$ZHzV_7%tV&fmLb)T|INXU?cO(TN) zT(DPWzlx1jL+DIgq=;<(*Mmbd6RqL@^(99|nf}Bxty3iVh`Xk()?j=56;HQ+eznr9 zA}0IcRp816HS(zMP$R7(itH^;pj`YPPKaReDw8OkF*CVn&-SZBXY{=J|M?|uMJge` zhWz}f%8FFe-#?rl_iTTR9K0JuIAc7!Op%&JvE)<+FjliDo!()#UW~{r%6j!f@m)@2 zDMxNBX8_Z*U;szGC283FifE>;@$8+ir+DGO0P-Wa0o;)p(ZYgOH6@(KW8ZfM`J<&Z ztn{P*a6=_-v@PXRHHG$YskixTe#FbP1+RWg6anbkk~=LG!cZ@zg3mr;0?^`wWb zXW-fS&zJqpvR|FAM{O$ibuW`_XA#SJAdQ zW0X~XRM%bQN6&7AGwI3k|K>zsk$hyXkw=9On*Yg(e-hyY4V(6Nj{0jr-#oL*p#S8x z|F`+mfc%oxbH=r6mHYnl#To>J6#H-(PrGrrR79|WWlDNW?;?24^Xgfn^`z-iWq%>MnuUz{>mez;i#GgQY)$J+cU zhkw%fE5Q)~Mku%{zW-oG;JyDF#O=71!B~~n*_R-)|MBuCtMx`A9LFlG(nt92U&M?! zN}wRZk3;mp>LoZQlT1X8$ypgIZ3#_8I|=gh48JF73sMO{z^_s*OE;7IN7m#%wO~TcU^&~ zxxB>j%vA;WpDze|IdJAXR++46%Crk4{om639#NI)*=%2s{}>TqN*ssUaks(EB$J9= zrP)6SIEg1l6O4_$`48bj(q<4&Ln!t4504N#@l^~xFUP2`D?&iWw*EPqKk59H;D|Lr zDEOBx`HLBWVgGLsH?8B!B4QMb2NA3BA1{BhTK;~7;}~{`5dTF?F=Is5A9rCQ;ON&& z)C#X6wwPcDicdZo-?6F!RacEO!T76Mv{@*>)wD`KWGWGw&3yeJ77tQByDG( zT(I!!pWe+s2-tzeOX3Rh7o@b&{NSqqr-=Zi{{CU#Ut$QpkLQXvKMjjc_*1|AN#{Qa z4i*@Zs(&~(tIP<_$TtPeQQxo@v+N5bRRA+Z9&E1UyjXJF9%ofRV}uRf+P5qet&oR5L$th4Lz~mL;kNATEwmV-)IDI_HgD2S^r^5zFL-5_WJ4`V*YNDSEcz+uZKZKe$3B6Xt8Rf@zcT}aR{IDde=VECJ)gp0h^*AWT3zN8|^xn%1UE@idM^pGm3|yVcfvdGRMaDy* zfb&0MNRNvpSUoo0S;*PHeS~X{{Oyj&+0~!T9tLerwNM#bz1_bK_1OIRmp@{f;O2U8 z)!z=S{`9}Q+v;^+pX3{Nvzo?n#Fjl=G@S0=bL|B(ENuY_@{5q!a?Qr)b$(b#ulws581(^yzofr+|QyfgL5kW|iD$di@sb z6@*`Im-A=b*cNz``_S{f1+Uj!c)ex%^+uJ~d_gYjY+W|@xNz~!bLY*kwV2PcW1C^P ztIvhjSW$0C?XgtqzP|sBr6TX=!xx8Db3Y%N9hNcwd`x}Vw}VOwxF-$!w`A8Hy4@fuTq~1Qzwuh#v4Mu2 z6}2jU^?YpG4CzglC+n~OR3@``>#JQ^uS88>?PT5&5Wll0_Kt|>+&282kl5UATtXV= z`-ZX-q%QElQXp*e#Ji&{4Lh=Hm2cPc&eZLLh}*SV`GNZNs&$eT4g4#&6V|eh3+z9> zC+b6hlFMxcS4`8^VWD_+4NB(ENJS-q$?kE^9Phwh&!5D!TAR%&&8v z-%Lmx$5E?)=B~M={WHIfrFzWugWZ<09@nLLhflVB{wa4@LG<$x^I^5B&$b=hq@Zen zd#~eu7j3CNeYD2@_FIFQcWB}2^GP+<18>b#-?>&)Yx>oY)988MHx|Ke{($4cH;->0 zj0@Xn^iba@;@GEP|C6CRPljA530LuYVCxmexBSpTheG(ivDkQtan~LXt>55gxo7<5 zW`i3d3OBiyzHAF0;g0yZq z|9qfr_=MAEDbZo2q0jrPhCMq%1%7=daDRT{`k`@48H4M`6f9MiKK~d#EGP9@!f9Cj z$>)PZ!?I|(Rt!1hlt8#l+ykeU`gKR^B(fX!%+#t2*Kba$J9w=@M7377qMpmIE-y{6 zS4`vhj*;Vnm2n|wjKbwVJ#hRKw*KTpy^|4=CBeR4q5NJUy30dyn0~JHGTbRLYt7>B z(~W+MHVSI}bg%N{?;|GzLP`Sry?#yix=&mF4XY!YDYoh6hWZ;je2#N%ea)Tqdadc} ztxT5<;x4?gF6%w#f56Xg5}W72C61FfT|a!*QdK!F*xM*{w^4}Br*O5C4{n|e+gkF_ zv?M~@E7)^6R7^*<>^miYoXq?#7PHa*-f7`Xd?$+us;tqF*)q~zt=&>{Bm1q%?ROqC z)u)7O?5@4lA9&}lT799S#&+da0;l&oSxhz;6?pwXz2ylX8UB!0!Va&t_rKc9b!S)l z9Z|zOJ85$Q(sO&TbCq^%!|xr-^7l$U<~v#J_bP$khhb01ME&ifZ?9y(^SNDpai+#H z>8=Q6E5&Hy!UE)H`Tk3u~+8}hhR$-=ot#I9uq=wxCwQ8#M zTPy0s{hSkm{f}>}IWDyG!+qnph=WGK?w>+MK80wU43{l=;7}6A<@M0eD?)m?SB_Ku zoh)YaaSeCf;ZRL3SsA{N*XtZ!Z|;B1#pS}C?y}aa|L_}S}64?W{@eYLImmC)W-yUSmRY2MjEyd$W1hd*LY*m-U{VXoXRjrZ-P z(05*L$9Ga*2}r)$llV%+_s+J4J3{<-b{F3f)1BKvo)bhRq-A}lu-KS(*B`a7C=gl~0{rHBCBLB`&-N%#^b!Z61?$#_N_^>1QXew zF(yl$jhdCl2cZLf(0vv&5!ChmU0Wj6U+_(8Fdo5M&5v_jD;q4{5$0-^&Mix@L-8sW zci10Aga3BPhq0Zbile%tuA{Mi`x`A9(;LZVQ?F=eS2m!kb?2gzWctNO5lfoP6!vM^ zU%npP32(ugA9dUR{AU;O0{i@L|9-<#G*`A`YQ^R?S1z|bq83mKMnnGfFG*}td}{UI z8<6eX|9Gpw)iF)y*7~gxd&~7dy*agUp-)6*LB4#w@85P}Us$vG>-^Le z{BwT3r!S89zxv|z>s;A+N+4+d_W9SB&L5(jxmD9-N`2@0bHIzITllV*ChWZwGghx} z@v92;GDD#3L%uktxb&V_MBP+zOHFfPTg$eUATeysjn{LWaK0#?S3c80j5=skqG5pQ z(v4zdpu?tu7!;jGY2v=l2u;GuK!kg5tp=+56vg6-*}+!qR4MeTIRp($GFq|rVse;F z=)zLAkbvsaxdP2;N-fIEv*~({j+mFc7b%z}a?7(tAG6HFY;>kL^l=IL!(vt}_Np&* zTtV8>^q8}Z9NC@I#GQ%IUu9g^Jv5|-ejZxEWWPbJ?`%89%hZTwlrnK{dU+}iw74S9 zRs03EA4}Vvs(^Xv9`SNX!85ay$Xir?z7La0f*vtcN)TfJ=YebL6U$sAzMYce@O0WB z&*iQ`5^Y*;#5-$Fr!#(XU|%hNiO$S{(d33=(3~r3NXMRsQ|W!m&`HJ^rO%)lW)N*i zX+y<5v$+-iL<+P5^7Sq9eMRAN_{iqIl+lx1l;}e+g~76(X>nABy5W|ZFsea#h<@nZ zG7ayG!l`BPKp-lGa}-V^Epu{5@idF8o|joy`=JX?@j=XxSf&PayHU@=+WYhV63rNR z<58ZkK1#vt?9z3g?$mWx%Rssijb-#Zuz5NQ;1->@M0NMrc|4J`1?g;56bw%tv*L|; zd4uEJ;V_$Wvz#)O?sH{<$V%_?hIT?vm_@$lV0xVLS@+7$!!SLj(zOU!^v9J9k2fg% z6m2=3_+dk(ltDjs)0BiA^a}#YP$>j&WO_Sw7srsl>001{?PFg`t#WpNCPCsw%%UD< zEVMl;brppr_wz!<-ql*{WEfXC5T8X=aX4>XN9ueNQIVtW!#h6y1IF;f|DB z_a!bLdEFJd<+mSi+&^&Oz`P34f2hF%uPHh@9<8feMIRq$biP;SxZ=+4Rt;3Z-KAs< ziYA?SImzr*B-&dXAKH78J;48koY?olA|$CDTvE&+}GIyvcf-Iny_&Js78YsgG{8cC2}oX~9}a;_1oqoqsU2B1?XO)*`% z0E<)eu^C`-aviB$47<@%vAuxRN(l2mz%1gW;SpSu=!+2m+#{FNCC1Vk`3N}u=?abp zPEefFo%XRE(6Q0{OV2Fq7zS#OAEJdm^&kMSZj)3+Zi9bqLT#Wm9Ycob?@B9S|)f<~sq2FQceP67E))nBrnyXct}c9DrNu$wGja z;aSu-XfcW>0FI zFcjjq4XdH|q|sXqiCCLO@7y+k+g;kZ5YCbaZ*YAPn@KL zs(aXr0PCH-TLcPyl;;}lfo>DJO)v?13F6R}#kIljFwE=S?7aZUbVUA@0t^)=&YX!+ z>(fm1=YNK^(eICeBJtwv0DeYv8a}ac>u5vArkL`pPz+h(}E$(6xt>$ zT@y*v6NSPS+?X{^A>W}fAm73vjFa`dA0|g_a(G*Bp1X}P?R`Us&%5dI_W<;z%W$cj z=}D^(w*W*U?+NxLYDdL8fXfCx5vG5JV*9t0?UjIJ6;cn)C&F&)U58#9^0_f6Xy7p4 z3>ds^RBym|QagnMXw+1fD$^Uz)Q--HrwSA4@iHnxfQxnCb1Dp2n9@*Q11KPTDuqxJ z@9xY3c#M3zp&tP{|Jey=sNjw5SA?QJb^4MoRWE`NvlXV6n5!9|Z;_}xn~nz%Zo>%q zc3oG>!zSk1fCP0Fy(#GHGLY-Pg(W9<7tK%YI5*OU)C13OxkD)zzmP8Qa2h%p;85ln zM|J=OuMuZmpqEQ>bId7J>&i2>6SZSNoUaWT=xy~#;I}(DAD~+7!&{CqaGe9I0FXn< zqz3@38l{&7kjk=S%{qWdIp7^(4ZsuTy#uC84tfr3@3kyB*DFuOpdj(%>|x+xY>|uu z0Cu(c#sWr*chCIOnVz!-eM^E+{ohj#2$oB~=leogXCuiKiu8J;bf}VH1tjbZcHdRQ zW{|FUjka{CMSMa(#Ld#`u&uiRvi^3Sxfg2v%zH9G(u{qoErDuF{E0xdc`;QeI6Wkv z0mvb3!ZO=ooGo=*(vomXmffvN`G$$T{?;d;IB(xh0w!a!;JUT|+-*3jgwq+QDt%=W z%)!LD0gQc)>8v9NS;PGiw%)XMb{JDPN2QW)7M0<}E$;Kl z7NA!nlu?t%FIOdJ5S2Rf?(5bc3Q@>jSsbA_XD0yO?-6--3C^&E*=o zD1IYf({%Z>*5pry=6D`^1~=c^Mbo{n-t5io>3if_uKWypwt}J)$ugO4ii?1mD9;7u z;C{#}8L-{NF}v=8Fl6@5Ahhcz>w#(tYOdZjF2C9h0DHqO=O@y)6io{nS!1J2gIe*>cx zPyFRNyD#XCH@ub-o|Z(`|L}+a1<0%2}8#Pq#|@J{DCF?5J1~h zrm>ZvfY_hG<^>Vk>C)5Fj3xyT#y|UHw4OZ9P2=`A&r<8=Ce5t`*>xV$_3knSLMRO%7nxrSOe z_#DS1?DZ>G9?z5Wx0jO$pm+SrZpQ#xvlYDqaE`)GvK!9;qJlWu97^n$Qg7BniG8X6 zpe4X*L?kaXtVGw(Y%L2Wm&Lk}3KTtCN~>DQ!KpCW<)k33_;( zBZ-whQM5hi!Z?_+hAwAlo@8)qOJwYGhdbn9oW=w=@~xJ)JT*e zZm1G-AgBvn24m8ZZWX8MOy-$bwg$NCM`Uy?Ay3D#R%{;t4d$dsG*ayBNtCi#U}vYK z`AwAcS(GRGH+1Se{+>#uHE!uts$K}_<9g`{@KdTP%^hI=({!Iv0kL=OvAqWYj?0fZ z0_eyOM05e%D93`I2{47~OiC#j3-_CBxGmX&dyspgr2wc(yRA;hAR z&Xdnf7$&HPOF}=p^+K^aP@^j->kZ}JwbHQ_04|_0BMz!XR_GU~6F20U0wCz2aw~aY zz!fo$25yO6U^~%c;}(1cKwoFhcfoYL<9!L;cTm?BJ04m3Uqyu(6<93lP5%rI6-iGb z3tAWS>MZKfa^o{C>}m}Od5lSxtDa=Dw}WhgdL}^56r08tR{G$dA8QB6w!k89RdI*-$_6k zrc;D=QjlVpFr=HH8$;>Xw9AAaaNHm55kvu~&X<0C6QG{-Oj&W&aDF~?Mf*_zCSF6#l# zErJJo4-M5xy_jDN&<;QBjf2Jok9>jxQ?O^b3r4}>^x5N4paj+`)*ww4*7XA-sG$LU zGicCTrAv(y=`;#w>-Z*?)_$ky9eUsdh(_o$JnQG820E$FstzzCeDNvJDv$W7!3-RMt;y5ifPT?3 z3qFm~Q4)DzPHG+*13YX(OxYiZ`{Y0K9(opWw1c<+X|wieD=1JAb|!RfaXd-nWn@(L z51jzSr4N2Ozzpq@N@pme%tlTrAGq+AXS*)La<;OO#6Lz}$ z<3$+vcno;LjD=X-9Q_ty6ZbhyP|ZUsnrJk65f@v?&62CVdWrtrMovm6wGd*Cpo zr>{Rp7yx95pHt$3y46@Nhd^br8HJ%om_ImtI{RGD!nq zJs5-sTLFT0vupOxsIZqb{mt;Ctxq6sJL7ZTkH`JF zf4}eJ@%{7nM>J#Rysqn9=bYpIEGRJMW;h$D4mz(0dN<}mf-Zck_zmF?QGA6A9^WE?g(9KMWQX2pHT z_Jw5;f1w**feBZ4{@|P!cs>_w;19>BnYe?c>P~gdYe0+81O$+uCp)ZLZcubS1hpi> zM*fuO(YB3=9ybp*Ea#Ex;u^HC4}fJDW4yT~4zDb0rw7*H-A(KF3yVJB+E}xC&~65) zJ!K3`w6iJ&fE(oZ*9riC*+SR^L)_Kdeh=@eZfP$Ai+zo}9)KBg^OX{a1tt^nPr%oR zuiXEN#pw=|W%LT2F+Ot}P$*Z1uzNKMb-pRkqZ^zY1l7^YG;yEoqt5Zp$xoG8bJ)t+ z5qm_(N+_+}@wVFUl}5%6uAnV*>nhh(s^FcI%ec7Myp3G!d)?)&pMkO9Tf@)IyqsC8 zhSH9!V$-HTe%C8tW1yQqScbXoqNT9SeO28AeF(Ds%3grJ91gvd2v{C66jeABDGKfN zU|mETNXLKS$BWe~2DlbLGC+YRj84F1j>QETQR6>xANB$6D<7-j2ari~m2^XJ#E*s< zf)}%KMQW~b9kiWjeSeQ_9GezE{LV|5Sjhfz2xZzA78Z28gdWJEwyz7t^S?c${SBm2pebM`O+rW=0HW*K&rq-elG-t!`!t zX8m+&7+8szgO%)8R=zZ{H2`9dsr70OfSr}Yl!17gF_K0En{Z9!IKDXPU@>%I19S*V z|BtOOJo`sB057^l8Jc`rrTG#7BP3GV3=~@D%S8YYn()A^1{M1)pDo3vcdNCb&Kbld z;9gBFO-HrsDhOLRCN2TKqkAdcj8T-Y;0(}16~iGZ7&UPVP?6;DSL~EdrxoA8L&Lz# zBW(bMGI3^{1djLEZW{yBI!qvq)v{xzX%pA<&KsC56fIQx*#);{EDM> z{Lm}yFeDj@r9QN8kpsNqkTKHib&W;bYJu*^7xt0V%l@K-37^nNr3fz8v@ds&<`BKx zJSvp^0e5@qiGfn^taiiZZGBMKENWs7 za6+u6Ti+7)bYt9n<2HwHqse+-^1Hp?I!n|Ij9Gw|+2GBm$CBRaz?*xj&TE~%?j@Ozk&{`8Q@`s)Ob>>$Hb94nY-5dHi7D&k9>jBNn9EbUkDz9>n8g{@MuxojA7jZE^c1cQpdIMC=aEfP@8Q#5>T|3i0DD z2Av`|o=7AHBRA$CUN)g?CTY#|(k zj)xsFC(k$;2LFOFe(CL-x^CCrlcPq7+6{6a)c&UQ(X?PwwoRBT{t{SYyMvgZQ+33{ z4@^{5VC23T-p8@OM#CB}%USA~&bqN?TnP(AGmnyN;RILr*k&2*zLp~u&R{_oC7Ho- zRW~LN!a%|pX&Jyvv%LAhsv7SaXoa;5Y(vM27u$J5w;@}<+oHH{7?-_cx=s=qb$NMT zU_LHQmhBfMB~XVIG+3%Kt^qrddjgX*iuQW$v-Tczz|JQ$dUG&>Wn6u)W@S8eBXad#l;=Wl5^Rf`QAK0#2e$V?PB&sX+#59eR#9 ziS(=ZrUvue-mn+9{<3rDkH6cde*;C;)UVsfKA1f0ea*Ck^o__5v@M8L7r5LCKTs~Z zfs#Qy&wG3vBSk!HCVY25Wp`zSv^hX0+h!~anBlH4XR!td2kVsN!urJoY4IOq0yZ#F z$wCJ`+w{Krc=Vwgu<4l&31Tc}EhuA`l}&>T+;6pg%^Yxm9@l&auGKf9)gPorcxBe2 z!yGBF2A#ceFJE^og2<2)j-edoT;xo3H7@ESQu->TtUO}Hnf7qQ);0KP@iKz z({(_ppY^L(ZE>J9p0vYVjWy6{pRpB(Rq*y_>Afnv|HFTO^6&=hZWTn}COS__k3@>I z%i`2Fm;vB__m{B*Q=qlJ0NUk;Q#UP~O~XnJX1egl=QV72Ce z>8wT7KweHCsEgsLXRz(KEM%3sdKxw78Gfd10@57PINYe%Sx*>9Sn-zp4K_<3g*XW2 zzrC3YZDOsZ(g6YT3u`!Fk03?e=S(gi_kAl|8(Oq9d2%hiWw)wm@2!w5*f;yb<6`Mb-uLHUs%B)T1Y3_`N z#8fa9hcb6xg!4+cXUX}+ZD_-`FfN$#&VUT}hwmvm#a|8KYDUmuJk7iHAleRNNd-T_ zS~qYb-=&_n0|LT%mIE?i--m)5Kytf`0rBwg+Dj2|4BDxr0Cxtzit>M;>wsQ+Y(2o6 z8IGOU33_l%3ne+B$qls^f-B8W+d6&f%X^f};oJQ|Ag?ktJ~J?Q;c6vf`)t^M zIqbZDC|s&UYCjfJZ{w3yMM6n1%^HKMhNEs=Q_m82U zDg@}p&1{3a0rh95>HtpX?(PL)*EPBsaIK^^6)6TZXH^p|$7&wX3*XL9AR3{Ij5do7 z7ACPJ-U0bcZq)}OpPD`qf|tu8)U5?_A-d2QLmlOpF7pN&1eg;yZrMpgd2f|#CBOu{ zZSA&bU5O)%oa%~^oQT+0DjMM2YcQJ%=ae>%haH5RW?a2*LU$F$dNiQ3*QY1cfXn5f zqz=dEsCBOa($E@{2*+aO9QuM83;H9LFLaqWuOrKO0}7z)dnf2Vo*(332Qjm;X=`Xr z?h>Hgb{KG;u{S*=D-)5U1?1A*b0Dng*q@Ex!$iBMnvqL+2`_N&SVzzSdeo_%;Cra* z72FRBa_!uD_`q_}3@^{011R*;GN{KO?=4rm`&LemM)GCQ;!in3e$tUq*CkIS4p$w4 zQj`sEMC_)eO~XO@gY=y?HE=q|#CKxfhqQ+8A1k}&55!$Oj3u{;yoN@&gQ4jYUOtDC zrb}v)+l17?<#3U~xH|{Jb3{%00@y%(%~c5gtXq^H=`Gw4xnCLj>iUg%_`2)Z8*t+) zxB(sifYkr_xDTxADHnlHjommqT5}Hn2`8Gh1uZuxKUILP*pxVH8tmulKLsFeV<$Tf zLa?*a_A|upt>5XwQ6VFH2K-P<8+{15Gp8r7fcI&tJWO}{9T|_CaP0{JIMuLqPa)tF z5dOIs+H{edgkgYE>e!`s7cZAXaRhr*lT46ey@X}=rxD75rRGb&*@Jl*J*&K!84|E> zrjqOHx8L`J@IhfH=;JoZ2>>e9>1%X{6Xm6WNH`3;VWO@TPQv8gGY*+vy%A(8);rfK6#mFrtRC7scHA|QFoU=OE>))wR8#K z5my5KW9pR~8vvb9>N&K>kjwe=0}m_1-?!@p&!XeUZ!!QHUk>nvt`WAH*T?`+`$Wy! z#>hz9V}{r&1vH)I(~0eL)HrXUXr`-U;y3H4IpwJl4pt_>#}ph_>#w*2(2X$i7YKWac36MtyriJghr$Wpq}_-Ot*`Uhf3pv|9n zVNlAj<#d@n;8~vWrohe|lf4Txsu6d?3m|Dvq}f3;y{e+VClF|K4?4FV!1jON65^lA zAzk_n$7h|17gJx|XB%VC&T!$vpP-OD2~UogQ@)cj$j9WHKku4NbuL#4(*dIqE9m7q zS#{8*ec*WRSoMeNVnr_q^oE;DLDBvGpyVk=Ff$MDN^Cm=w|^Mf7p0@l>EQHL_)*g5i~dR!$!WYeoO8<|m42%^Y=j;s;)u zc+|dvb3!oVkbAm~gzMsbE{faS?z@aMCNV_PnBdVzI?4Dw>DczKy&NZqt2P!~`KwMg zTV`tu9QI%AcDvLgJWH=$rwi-ShSyjM5k1QF4Hr;2KKAnni5!!54i+Ux1>)9xUKpTP zH^s|2Rl=3S&3`m8pe{`Bwa`ruCoqAV5S4vn(9+B*;3@=1T(o) zAf7nUZGwOCfh-pOsq8b;BCU-37cgpFuBU5Ams;Mt}< z#Wi=oTxB8xG*w>KNr+sg1!}>?zNTyQO)$Ad+DvG&G`hN)Z1P5q9=J~tR`t#g^e_N8 z8Tt;f=lsp2Pd-Dy`FjiOBqau&Mdt;Pd9|M1Y`BBE{W0Q!RNo5Vf2;+Wxmw zSTJI09Wk`X*0wKzjzmra?Q+1#C#N>uMiOyW!{{JG zH;e=AyC`hdmTo%7|MUslxUNWiR(`$s3BX`~5qrW5x0I-h5CCp1aK_G9RFyhf*Q0GM zP8dqsE!k!%fZKNa;_5*%POi<0N-QyT&$Jfej0F>!@3jsgrcK;wO5$z2^Gm{RNVWJX zw{9ccBAw^-LVtq}W@{>Rw<+PQgkZPI>LKV-dgYL9x9q#-lVf%ZB=e2ydin;}Zuunc z6g0wfRSK0{qZzUTb)m;sQO^b5T>ICRhOpmS?Xe>QGu=i4*NU1OQa`}CSv%d#X~u$9 z)SwEH(6!R7wiH&Mw zBimKkkv;rmT((2M^AuNRyf9vN<1boRbO{)6z$3m|t+X4Kx32ybT-vN>jKc+gDjNek zj7cD6DfD&OwgLJS2Yd=jPlwQ=6;sASlfb|6I|R%ZChbdNI_e<8F|;8h56d?lvn4oR zZQNr+$hvlo)&lXMr#H_+^Wl#qV!+z8*;aNTICD9W@idQ_27j){rvM zGR^_iU>e=WKhE6MX8f!ohTL8iwyby5Lh#u_)&NPQGL-JJPna|O>65}3oyoI24Y;5u zo~~eHt;~M(7{mIWufai29GMpf;iknqAPX*;wSFK{aHn}OP}&4y_7KZ-`p4%Q zII(J*5av$Wv)QSf{0!JRQ{`xt&nQ@Dw&fQa6-l>oGK zTI*L>Bgidj?#zRYs%2yh8VsX}2PJt;;T6x|eyhq$`i~%T_Tn$pB>$Sb_=}wg^af`_ z{V^JneNTQJ_({Qb>38X}Zt6ykkb0EX^D+Qb_j8R?Jh32JNe_DV3`aGu25WB`gLAJ( zD-kv{S(l{Y2HrOw1!E9{%BlSu++)VJ2jWVhOV4MDq=R5wMmI?IjfuMne?;bK)RsPL z5a)_E2uP=^1RjM=uB$E-qTzXK{V#Hws;DEWcz!iycnd78csK<@TqQVbV4T!Gk^dUL z%TR{paR|I?#Z|4p+Hg1=6i0{%<#PWeinV5%xu-Q-54K$#(-KY(MU%Rw-fXQ#UdR)?!r_j(d zPDOj4#@yewv(8G(IO*W7hIxX!|d(ZQ-P>>X^VkNw|@zhq# z)y~d&=}HDssR-18E5nv3HuRh$wS0nm8M#Pnd=O;jjQ6s4@p5!Vr}>b|Ae5u7m8e>- ze;stgk~(v9;1M7;Isd*+K@w#NYr-Aop4}cOkvhacFNd9NjA;aKhfZ>6}T>+ zMY}4amD-?dH&u4`E=csVETOT9`9hZp{dSTp8)OJ6Zuv?!s4DxQKXNcpo03_|u5v#?$PSx3WbR|#^yDYvup81T)fP#q~wOOc7Slo5<(y&}{_ z!Hz)<(1DBVHN9n&s+Iy%+z50PZytUmSm$c9vVZ}3MrpT$zQI{h+a5M06xA%H5?K)hddbo^ux z-dT+{J&OTTAkLq|J#M}D@s31sThLSd6RtMzMXyFkF8CBhXj@hC2$C!Z74*ALiuE=K zm~P{sW>?FV2(@ZzyL5|)ORw(TLW+HI5zq1Egl(lG1 z<7?{&)z!DND63rg{hj5a2%WDs?wv}m#)Z@>F*Ne*)R%_L3th`=gy_~dj_fSS#kQB0 zfifT6JzH)DmXx5XSjho`rW=Bc+P@^D`$ex4s4>yOu;&^LlWrj?GJ7u_>moGP=Oi|Z zR72nU9PJ{UALTs$4jV8fxl0zp3q3|1aN+V>Kv{<1kHkc0;a<%7A00z19ph@y5m>j1 zZp5YyJxH)&x61F9bG$|1-jlDZvc|ji&s5XY_ zFF{daHeIxywa7;Z(D<%&Jj@L?>I?({v-z+ga(oznL>tSkcj?_MFv7y!4HT3 z{{@ne?X|SlI)?XP8`I6%i}LsHag)6tWMtO>EUHPb0Z$%fzM2uj(yDQar#Wzc}Sp>X&V2foUW;Yjsj92*D15Lu7 zS+P?MKJ7Pxl4eVW0%-~`QaFM*c`k$22|(3u$PzxP0as7iDe0GPOL83dojxidmDoUj zD?q0BZt(RmCN>)w9Y<+75n=au{sjUF34uY|q$TUa*aE{rFwgKHCCF{KRWqtJ?N*1h zzb?YoP<(V?^0pGfxqJlqESzhM7xmz z;2Mhn78eG5=#_@#0UG2GNUCLP3~;FRgOv|2KvtF~f?R_3iYTAfAH0O?2*IFE76#oh zKXW*fz&q-a$r9iY3}PV*)L6){Bu8)3moVe1HHzOMSOqiF2wb&?i}dxmRfq`?j{lj~ z40#5?Be*YuFM~(&8zDfD#6MwwTv!8)8Uvxg_a4JZ{NZv3vx1*??vDA9M98GAvxfE) zrWsr%!7Kw-qmSp52E14*`FFkk!GNhM{FsuFsd9yrF053D#Jv`*)b7W zBKzV#claIy?z8g|jF=Y)?C3j$0_H|Sj2Xny7cQ$|A-XY=6^9NVK)tF72=>0CoF7Ao zba~OtH336i!a+oZmvd5PYE;lT!#fuQ7|>+R&+`FSZfnr9oF zM&SJok_V6#xn7^3xfjHP2H2`L_6QMwwc29>Y_(mYp;7&ZY zt{J^526E^ll4+vmC3-68BQOMYS3-!g9j>c^iHVjmx2HD+89IB_WbX-+kkX(Sb;BPl z=k;lT{wxK)Z#^$ob9{*eXiJ_!2r_hmC)tDc6eFj$Vv@Y=vmX>5VU+SD(to=avm4AV zIszD`oWq(Q1)RtkgEzB(;z8ueFCqS2-`BBLB3>c}q>+ z6Bu(J2L=2CO_Z#rpD0Yi(oq5k9cm?{v(e%bC32A}nNg}l9>|d1DO%nlS&jevF`uD0 z|C#^!;BSOH%W!28V-DEWS;sUS)P^KPZ0^1~XwV0yYHO{8EBoeu#z2@E)_DUn1m2ns zaB>CSHqI-#5}f?t1>-jUEl5%NA+aYynHHaMbDy8vM#AO;1)*h<8SoQ{AgLCqUzrF$?bvG2SPnm{T|zGPRDaEGBQ;f@f0 zY@R#vz#RsB2;>c+wZIsiBpV6RhY-yM#0ck`ggyVW)^KcqKf@sfhU6zolrR#G8epIB z1c}s638W>)Z1McK|LYGh5MtER`SE~;1|sX`1!n#HikjNZPY+po2!R=EJY-8`$$kC> zX5K+yK+YD3xZXTFk#e3y3HQCy03U)C$$HLC2YLfMoh+G8Ezh$4aB6=4oaO!H0&e+kfB2Sg6aKj57hI9dx5WSikREL0r@W@gEh?5wG5$U-!N z|MLhR%hO~RELiFPA5~GO|6LU&KK9>LQU6!1VRo$iSH0+ax0mZ%HdL9cS-4@*Pve#0 zClc;xE~Ni7J~DVhbC1S`zmD!XS-AcF->lGqXCk zyfS_wPwiP=R%wajC#QnI0w)q_LC%)POHmT z@0yUhc9quFFWmTZlqptThKdya(4jU=vh-$8zgpPJ3aDPhcxPn0ZEc!j$?>}xAvCSh z;?$}=$39e%f{uGog-5@ur7c>hvWM1E_7tzSz8OCp@X+s0Y0!1vpusxM177OE{jHeD ztDfC&r1F&Ua0z)1KWw zUw!z<&CMt7v=6x5Lhern zZVsGPTN|ga2~X>L!LzFG!#geI@Y90V;sT3S_@2P2{9}jWD(UqIC&kBC`-$JT31_$w z!_B!0%1hr_6`Z^8!a98Y?6-?9I|4rNycZ6R-8<&=Gt#t$SNN5()N!Bp&vgRS>&eRR zwkq$&3||lVbgK0D2*MA)vpaWkBCg=v_csoKKSgxGyIWY-#3f!zd)N1i26rX%-IkeO zk5qdi5r*l~e+h$LCU48zh{mnvBb%g080PvvyP_yBZ)xmO#YW3@V}Ge@TypRh8(sMO z2)X~CpNo50*P5^!Q@%xaOy#C{U{F^|yUvu{=Npbso>O@zXLR`^?)?HqN`2(e zUbWVqS^IMfRp_#>;`_J_Wp`X-7d-gjBvVh;J5#&bdSA~(wAFQ=yYAn$jw(;{0jqH_ zlc`!jU=?F}M44>6ZIuL9Hq$9b92{dQ=ZEUdQGQbPdU>%%s0LT}oUHKZQqCO5UArDJ zYyX=Oc=`yHbF*=Y=uEE-nZeifWcKH-^>#9z3k;t#i%p*B_KDk*DiWO2(zNELucmFi zj8?qqzAZpr)j8RTx=f~CZH>y1I3D?5`p9Fkn|AMNY9QS?m9|8FqqWLVr{VF%58TQH zHKChO$2nswEW=yaTphD|vNUa=ZuZI|#jp~m``zy*1J0om&!+?wmkW0Mo@`N9*-Q+4 zupoAv^@g;ERo{Dr)3WGv*b}u~n8M$Silf-4zusyp%(U5j>aqO?rCsAqzW`1v0vFJ`*=ZyyLhAHuNSKd^u+~1Isy--CE zs4|qj#l)`g`is?Q+1OoWRxFw8MXoukb1}9__l6C7nM)`|G4cH0o=de6+OX*zvgu!5 z(jDt!LrPT1nB?GFh#u;-XQ_aGObLX4P#C20zEEaDszt}!h~k*P@G$Yt-@Ybef72A& zJ|`%y_f{=%pLlzV6=u17zxHg<1HX$JGIw+d@ei_VHttFuJsRn-_Dkwk#elX8)BXOL zzhbLn`|XC)KJ7U+?zLE3bH_$P_i9Etj6i7t05kZ-+mgtJm(MgGlKQfQeoL-B9MxBbJt$D(k% z2p7ILrCF&-EZ-trkJt3H1*bST{Ut+2@5$?Y4Nc-aR?sr38I!(hbxZ}=fG(VznO^wDUcbS!b+WTbHfY%&oH<2m=Uf~Q>a z6QlpvR(XPbmqvt@W3$8h*k(RAUU!F87FO@Dc)VeRW7#pw|@*P>2xYQImd^=8Fwxh6U`XPBXXd-urp1BI)e7YxX+Zyw#q zl>Vb^;=TW*xO|CMl!XZ#0Z{ zYqJaPfQI2hVX(LiZF$Y@uUE)De{rDV@mUqu=*e9c&zD#1(lU7Yb65Mx>SG zbB^RGs?nbq_1+jnqhs_a?hdrX$FwT<3pYjxjt@Q`GL>nBofE(Vm#>DJp-G z8Zbqbnxsb0IS#hT=lIVC7w>S2E53%VG4G90?}?%I#f0|6$n^c|se`j2U23{_v8_LJ zYeX8vZTZLm+x{Mcq7F_`YsY0fI>lf0J>7#cJCSK#Lq8Ym$U;^U2$|S9$J9AT*(s{y zBsC7`{)w@z(v`2!Eqs90d4cuW$QWB&(&iA9={D!MX_8vk8`D*#Tlfs?Bh46-Drqwd z%4E(tq9>_}y)mNix`G$j*@cWTnUbh{>NQNb7OnEDMs;XkjA7|K$xv+0W9;lo#!V^4 z*zS_H10`)M=RZk!1rPiWz674A1J2lm3m#w{J&b=7`>p02?dKf5gEAF^GNnqcph}{E z8}2Af7hZg3TK_;yscuZUZcK%){C8dXAG&V6F`>ONEmPEhNvhnOqiD{tX3i1VLA&)v zD5k1RQU@ogj#Jd&NvhNo_5Vd$GOWO$O!Ax~YLcolMOEyJp~AAj48H3YKEbxa&k*dT zDqa0BY-_1*;eD*nD#qCQk~XQJO!YZO{YmOqlK}6`B1~BG*#6y&YTr^13T2=qob{E5j~Biu>qd$w1EREQr{5kZh8M9$aFZeH zg?J&Uo%h(H8$1Q4aCb}%Ax3}^zqoJtWh6`_h6puMqEsg!@buF=kxpa};|NoPVj&mB zGEYRJs}qC?Lbz{_TYkAEPs<;n2?*h|ltGQVfjVZVmg#^{?EU*=7224bo~3*EXtjY zq5oL>5Fm_{<_$yEJcNEHRl<3;)HPcFon__y2Y5+_L4JNadH&3n?$> zXpM@cnP?9Kw>0{J16S`Zlv*hj$L^NjvcGh}V#CE@{z&Mm%~$WnLi>OPCyxjjqwa1V}c{Tq@t$3|Kik6yIlxAruYIFUQ zVxQ{{+t*2L-nF@YaqD777-O{53_hk96PW8O^&js=r&;Dk++DKc?}f1pJ0`tu{QW|y zoQ1KN`MIDDOfI$hbj<{ynf(4^Lo!>ia-N}!WzYOKWB+fUnRfhZGiqtq^yv8KuM^i4 z9+_N=)N%N$bk=mo&Mi5wj9g}y>wWjRcf<7C4%IXHCT)o~bdl%Szy2ok5BK>S*qr+) zAcu5(y}XxCVAhW^Es6our@$OQbg-feBs(^#fI33rCjsu#w$H?ow*boX3I4B{qU1)! za#fWtjO4Srj2nb09^d#Gt->5cKDl{xwpia)tlS(E&6o`t!2!h3FMdk8K2^yr3!fYV zz&T;X{FF1=lvv{B2OQ(1Zr=cI_23y!9Y2N7xHs}{BVR1dDS?NiBokeK!eC@Zs@kuh znhQVRKigkIwcZe&CA#7Z37<@hvFwSm+2B31`NpJTQi(5jB8AR6;_X0K_POH&&%(Av z=p(kUbplwWS->5_P4sj%b2oP5Ea@a$$_0}S!sjp@!e{#i@mbsupdEe1eL9H>>2 z&w7k@jV1$$R^cqq%)6^Ym~bAITNGFgU`Ey*@}D07h){Ez_#fO#7+*%dJvADU8gXWm z$Qa8GF*W2C2i5|iB#s4cS2XG(LDrbl zFo@=~0t57pd4G5)t4tU4V!LC`{eBQ}8@JSis#tt^%HQlTAA83qVy> zz|`jAsR?@+*a*@70@+(QE+&p-0%+347*w+!fOARKT@$`$M#VB^Ta=Ci^(&$aDGd2y zfx4^s0vFy0i{+~b4A=t?1;nmPF({6Rr42AtDfBd7iWKn9 z>^!Ok%GfWC1nRSlnx}FFx}TeAwyaNa`rWwf(a4b$=+uKt<&E=`0+xgLWy0grE#c!{ zZ@3;EMCE3BGC*G$`W6Y!S25}U<%-LSyb2QtJjQtofK1JZJbS`IfuKLn4CE1E!AkA5 zQGm--_aAy^{%^foTlwF5_kV}W-70z7=pl2BG=8XHi~BBMRcmu z(@GzEXJrvbxo;!mz6}0!l6$ z#c2-aKf!z;suX#D+QCoB&e*f<0(!l6cydG?iX5M5mb)KFCIxe zmAlfnnn$;y=%&2cE2^B~5-N&9+ZaJ5TSZxa=URQ6vC#J$zpD?Gtxj)HQ1kzUT^UbQ zIp{|K%!AZZ~32V;hdvWjfS~i#SjM za9=H7Uoz*&VoBWw{w5EwV&2sY;paoEG$!O@xMg`kQMC1oiKqCH@$Bnx_dsawbsM5v zb;#ej$U72dPQFtD<(9Km;tN1+-LGNEa!9)_gRCs2x$9DVmpi?Lq>qeulQyB+aHr&I zzVQRGAV#(bAf3iFDUcjQn46FV7UENVKR=(5Z%UMcvJ2`2?wSnWrHp6+RRM0xXsd4k zIo6g#P{hISp74Xgd6qzGVcni==9fseaaSnA=ouSb-1W&Qb_bKlN44{f>L{)J?Ac|8 zNen+;d*b?GZAV`l+vj+zNiV@`$q+4+_5p4Zqq_vqd}h+ZDZoL4bH7)?vLyVGfx5%Q z*_H-$ajel65JRObPgQ>QrSqYit@)vmT&iLSKDuir(QAmbR4wkOF{O32BEbc680I1h z7S1#c)ihlKan5UU1(6}{a9<_XV&KupQiB&21Jx4nZEE;4YbSr0W8p4(htgzM-V6M%<=tUEn`*i;OW{1l4AfG+60&ReAiJb4XuYl{!*_gdPS_HCl()#*jM7XvZtJiPF9BFX33QB)}6 zzE}|@ub@YyLfuvs*$`j=)Cu1J;)-(aEC%+EmKWhJBkTOek}9!j$52%MSTkVi2+jIF zNz@}U*6U_5pD$nD(dDOlDvr`LG$q6O^pi)LigCgPT!vH_lh%3~wgx~FhFG%QZ$%VnZmaV(fYtmePJpO1Uy1Kz6dlhn|z^EnB6-4lHxwBYqwHS z9&8Th3?&Ir2Mc5MCH#!-S_VaS6rlw?X2xUSuY#n9f41z7do#2uDXtF0IpW(nrXZO5mM2R6uCQWx_LGi zyM;}-oP#<(L9x<5l=r>&W|v5n#~<#xIKBfC*aagxz6Anfmj36I7czUPSutgAgDEgl&Vsf@%Bf z^i*&p$en%GQIVPjqY+O>*x8{|7Rm&py`tvZC01=6jc8jvTYlFY{79%0MH3AJ7Z!A0 zAEsNeSGQb(4XpT(4_XfL_M%+!P@CDP)Qc-X*>|yDbfOgH?Q%|W0vgeY9n?31XYS9D zy@?y@WWC?-ejo^I2ygLpGan{(4_(WHn|g;$x*j_~VtqUz^EY%8V`4MZyAKSVz0|EU zD7)MBF+NS=^~;)W^Ylz}})ir6&>jW~VpbG2v&o_FJ;r zVb_@JuhP4iM0D&n=l){a*JAaHgQH2u$K#u%_pE-4ms9lSIsuRQ6`#yiOi`f(f*7Th zL_EBD&_ig=PZ>3hvgstGFnir((5W3-{9+~a50Rx?=}=&K#y1^=hA^$-HWH=J*kn?ww@Rm#;zg9FubtZ@G@X-a($=Hy%a$nT8Qx;w+9 z^gdmqSangeS4Zr2`r<@X(Ydkh64G}BXFP~jF2t-65WxJQ$XOB6-+2lZ>LUy|f-A|<6c0SSmxn(Ou+c;itC7Q=IsAsE9wwkvBUeKYo#&l@dPNSlTS% zNY%`bJ{SA$M?>dFSk}#}t%6S2Vf}CZe)ZXH1jfBu4uke!Y{rQCyFrc*>))t{U-UwpL2cl~J{sUn53`w#wda#_4QQR6rBiig?AZkb*un@nuI<`T6XBr^}tZQy> zR~q7%Eiu^d0aGBM9|5*--ZNBA019qvNREGhZ=pb=BM9sdUpxU=CFvcFHh{F1uJ49^nLwR{y!>)- zADb&>9e<9?_w5s&TPdlW)Ku*kg{JS!Hfwn+(BSMS7D)~mn?hT%QC26!<|=zlMz)-(|pkWd53QD5~#|YsaQSD(JC1HfzLe- zJJ6^r<}I1j5ZRd7cqR%Z^IqI<4YCwl81)v8>4n}pwNTnD`}98l6e|0{XYWo}=+?ff zoFURVEk!Xz6mnBV%b+r8O_fnNSGT~?=rrU4J9#HvmRPHNTp&~(ypU~w4xF5*B6NHp zc5|*6LXASFX$6gytZ*Tr8wZyAOj8x$@|hR(LzROdsct(IJ=UY(oL=y$%Me_@D|X+u z@>8%TO#n@IPuZ{u1g4G?2!8j>nYvfX(>YURZDiHY5+)A)YIKKM&-S1>K-z77SF8l? zqx;?~0Pnk5_)J*x*!_-q$$F>LEba&K>eZL-7w|Db%gl z+H-ZF9;UWNxK-4go6-;EbN`rj>FxGJTCAKbXUqGP`eOCo1Oo!XT_?cF}ZisZ-%Yp$lc18O3{Q-KYX6?f+^o{xAv$V0AHK#n0q!RC`G~a4Yh}3H} zYfnM*VL|u91C4G)TD7rH@%)}b^&><74`*)z4)yx~51&q_oKl=}$`(#XrIIGu*EywV z(duzX~yg2wAx);Y}RgX40B zUk0%ayKL7C>39>`P#Qb(If)K?cx$%^3Ig@~0#ty;XHNre!apZP#^8kGQS2seOE~ee zUyL|U-r8WTJ)W`GQou88bnTYYj`?;N)T1F_eWDXp^`1hMs34dPK)MyL^?IQoYnzsP z0YR`4i(4nwe>Q5@^QQ@fCK!e3`ImB<%_=O`UcrsWN_45Pn{?{v7I3?p8dRn1++(i4 z9*7*y41gjaHB%FS5Ak{RVz)8Ut#{$`_buSt*M3`c$il09eH8LLm@~EGihtY?E*ZKZO{-DS&%vIF_TN^YC!MVf#M65lC2@N|4F``MK9n9BbiU&0%0Yi-+ zfUU{tT#jNnH=wVytP>M}1TSyLCdfNQCoxgYHa;2b1Hg>38hHe2M=@OnKB+<@KE+A) ztC4zW?bu@0Aa9yL}^&+$eZ@D+qF0 zp`|u>k9zUwV=3w*(;ba;WZVGBqXdp<19zto*9Rhn z6-Lfi--y#AZ^?;W{oBVg7h+6jsQS+qjUp^B0-AKv%NMRH0rGqZyG_KtT5gU2r5WqZ z8F``O(?7!{?g=}^Xt5~1nQZxlfVYbqjfPT)9)96XFfy;%=irEKD=A$q@H+pxZZm}O zJdOl3al69n{dz!A$>)a_o|nvb3dOVB{Lt~#;)|fQBkJ*YV9l2^k3xKC?xd#;RJg^J zLIsn>a#Jjbp{){DS**V&z|Ijkv5R?6>nLe%fnzoXc6!XVc?3UFP|>6Hkzj8&@6rtL zLB)&dQLthI(KeWuofdI393HsDZNP|v8e>pDs%D=cGVn;e0f&C;Ry6` z)j95`<&@N${BI|2vu z4WZT$J5f1@2e_fGzMJ^=OY>{}uRzt*o;;Q|(3d!ddBr!ne2ky~F_e05PpG%Eu`8Ti zyiLz@j*@DGV@M&4mStoJ5dL%X+xQVgzpFh6PgHS1L)dUMNT5)!7zs+641x@xox;a2P$8bvjHiLy84@+S19tD38F-kiOD*2m3zGTX za$XDQgMs6NP`tbmS)Uxo_nGeSBDzVtGngA`i1iIes#b#zydgorwC{|z2esej>4*le zn5e1>pt{Td{s^vR_SIU5%>+!NjGJ8TOMTtDlq$50pO_oINhQ)-}QB# zXSoj@^7g7c6o6Y;yxag)y%H&wbj)RA(THr51SRl zR))`*o1=3>$H%u8!sKW}=}g%g-36C;X^Hi1!*nQ}g);_3@riAF%?W!1bW!#V7%!x1 z1K5e<(H5%A!Ehh%9a#Zx{(S5Yb6}Rk7X23`PG(of-}-@Yw6^I37ORCT7fMGof4GYz zwVe(@ub|!?lNb;R>V~%01YpiPMh2ue4q9~o!%d=zavp7XE>@RjRs%OTbF)Xv!6mVh znePWD;pI18^Ek0mCff#XS>grrC)fe1=Nf04pp>*{8v>C2K8+>-quVjvaSU{o!W|-) zpI7UoAL$@ScsWd>j}zaq-6=Q00TKAKR>JhE@LwSaU$0dQHyq!^X^ybm3V=REb5AL6 z0ORD-AaVd3O#IOfCzN{{k$a9uCP2UFL{_}6R?E8kIJY@fYVUp^MhxdBfNv&uSwi)n zO1+p-G)}yu+;b0TyWVvO6jjNdZ_5NFq|O0rux|^QCE%7Jg z`L6GmM-+kTaiOz0Ah%f^RJ6crDlIz#2Ah~U4EFqylP>TbF{&D7*hAP0eAIE7zY!K3tt?+SCG0a^kuAKM~yPN8t z8G%pe2YK3x7gL&dXC|}|n%}xH0p7oE|F42ME$&0#ryBT^*u-n_%UXRT|5xCYduoeQ z+7kvtE~9dA`P1j*mM0LVRelXNJS>%5ZWs?-_#eMu)yFVyifbO-;8-chZ;1j7#&^2Y zKSW9vjZPfUQ)Rs)zqZM*)mInq1x;F6(t5=;!AMJ|iN9xTm-a)>dFA+~v{o7;Kh!fZ z6(+A4wc#{uW42fTSATCUTA>`vloN0H51RX8r!NSugO@XaGkEGhQW|%UMf2WY5pV;VkC#P2?RlW^A)s-!WtlDV?5#2Te?f2` z$ICi?gBPV@WZ^sz#LdpJ^-$8>=&8<=uvYSPDcp<(Xi&h~uEL*LChq24dUp*tPsMfy_)9I@ zWi4>tn)*B@CU{7voQctx=__NxSm#2x0E#ezf}c}1itzLMb9y9nq!?*`0DSkYo(;FF zN7Bx~xu^KF@Gsc5&N0%3oMzPtO?S&QU7~n{IZn@VU~hpAkle~Grz45sc}cukFsGV0 zO~}`vcD`M)H4=nA!o7bvv@K|gPkh1{=e)y#c`QB|XdxYMR0CP#4tJ}im z>5MeF2W*mRytO#}^~^Zy-f^YPppd7@k#cSFwprX+FTezU*Fyx%SAI(l_$wwF3vk9h zwY>z3?{z|+jME5-Mrjl9)5O5~2_XDuo!h1c$HFbhk^6AKzLcs6KoZTNnb+VGckEFg z*vzliO#X^+ao>0wUx9>HjhTBa;CiTRH=|q|up~>ADXPqta5vx2wqHCx?dV#x1X=_t z%K>HYe-ejNJ}8}CCl05DYc36gck1G{Ln+*h5VnQ4@$|r9TkerUymTZsW^y+uTF#; zxMO?@0WKY5X6V)s69~Ac=h&Fj{7-c3tsq=+$l}1sc~z2D;urC}FF+%pyTog+iG-_0jT0wg>a{!L^yAz2X~^6yN(0eVSY`jH5l-L zX&2?k)H#93(>XGcM=NIlz|fw?E-&eF{gPILm{o*i!8wM7bixJ3;>V^@U}Uw_qkzqk z6gCc*XP+0Z0*=^UzCCKd$5tNmRECkOM&+J=agq4p+n_WL%D2AfcI1b?zcp_Q810I# zZ@FzsnZ{}~54Ze~5@=hbH*x0zBn)VNt|=fylH^wbZGVfQ{R-Ch1aqI)Ui=8R%>ky( z#(ROrh=;zqd=%O0w8R0h9loFPGDi%Wt#LP))aJK!QF9{N_<#y^9W=Rk<`2M)MifUY zxP9wPS12Sn;R#>=#f@-HsVrP1lCpge6W=C&A|!{t&*#<=tT)N^iuK3rwB}V62-pH) zN$`l~AZD;6H3ZEq3h5Si6O62RKIK$1^FwKTRg#eY9nQS+i#D!|X9)*oY(B7bHj=Hz zaFh+u1R;uK*vu#D%1>$}a{`V%HLj8Ym$BmW$9JLf)k9X%+_H;z@Cpo;E3PES$ct+%(GKe7&75OozOPftVvw$9AqH&kXR`%f8G( zWFtjkB{<#~S`)2nynV_6t|>yEO>5P_o$B=4xFCzF1Rgd@>+F!>#`5^rEJC;3<8Cq( z?OyD^RWeT0rR^W(uI_&{&Tar~qnA^c4#Oo@luZXDCJc=@oQ6wPLg(CWklJfj^=WX; zO>f@}hJ;N$br47WymzCH@hv8*TTZ#F7?K3u-Z~pDxtPFbtK?9X6cn&;IEn?qf!f1NyPcz$1n<-gq?6D8~i%pGbjP)FGQGH)Sh8uxMiC_Szd!nCb5iDsVKL_ zRrRzS1E0t{>Q7_fy*kH-79~fg@9$d&xgJ-s)~N+fLk^@6VG4d93O*9*8d`B|e&4gOm6t^qH(jZ-as zN_Kx=e$Fy zTfm^31>>OAh@JSbKm_dA%Q+6G{OF9lc64Ijc@_twAQ4&<@RM1hK){WSn)^-z^+FXH z09HSKaVP>5LU*%l^9NC)Bl4l8A(1C>y2eVbEIy+881AL+UoOx^yS;6(*@JTX^zr9U zahu_`ED<9NB8$hz-HDGU14H4yI(6%;`Pa>mImhf zLcoXs=64UbmWp^?ZI>v)%Y4PT1O}on;7zr#@h5%Q?ByTd!;0gc%I`;0jF8U#^IdO5 zJ>lYO^vw?1(9a`rT(ZLzzo+>a`Yuf)VU?NoH?B-U@PQ`Ms5o)vam<_`wzJ-QBYZ*- zHvNhv-%S^OF$H-h`!zu`Bwo?f(SvB62Hh>^q#FO{+)uux;rGO_XXq{^4!`E)Bed<; zjRic9lgtjLyJbzMMS0l};V`9j+v(ThbU|%Ehft5)OP~(fkH|+(^)Tf}^9Vz#{0(g> zm9wAXou&T95qG$oNc0@sr3lgzEf_oi$vWJyb8xUSc`>yP^xyK#LCB+qd=f9e39fx z4?lPAULl1rB3Fe^XMQXVQ()Ebv+L?rSy)lxVU1W?;r4ls| zd)_#aJA$9g9z24U5GCX$_@$ie!I3I$-z&!I0GagLgrltGVb~9vAc7G;_@O zYT)nIp`9UkxT>qgAJS;5T0Rq{WL}rU1BW-e&r<<(Sed{=nkkT@m;si_UGN+ZZ-9La z0q$K{Cy!TXZ6wFCd9S%mN_PHc;3+&ZT0a`;qpD!Z9)#d&-?R%JXwq?;(1D?Jl`;Wu zHl5-H2@%sniw7|#=w|KZJ|B3Rt>NtqXlrq%`OP}z5fGzTJty@CNdXDl$%{Il2+h@X zVE~ab+~o*~d8TG+8Q@o{Kdc3?Av3dJ7j>=On;*r~;MFYl=oFx1KA-@@kkvs%Uw89|^O0uHY83w~Y zl}$*&jifT`pwE`B8Sl55_U1QjZjlgCmLUYUiiMTy0>x5~T>tB4UReL5Jso{8pT5g_ zGl+EMvNYX?ny1PbBOKk0jbEabAkH*fDHDW` z@I7#*46x_D+0SC{K>~67b2AKNJmC;Ed5eJks-V2!T7e;e$PKN2!ni*$$i0BatFEw2g5#!DA3S zpmLBA{JJ)I2O&br#g;+sJw(mn7wtSkDWH*{mEa4pkEo}o5k`oH_|&u%f1`8(f#??e z;h=O3s=V}V_C4v_C>!Z_1M*-XgnFH?+C|&-d#-e#vQfVRIzqUPE1yC%u1h~UG8bz% zjnI-bJolFs3g(u>_vS>ei{TGEbfPyP%3$Epc#%X4mMH%O)boTrVG!WKDHn+imR`z` z`1rDelqyCzkV=9gppy8o5Uhkk^*iQiI^q6_0Q(a|YvsdUBDZvYauiD!B+M-zAUKPU zwvNsIDX2Os;=j&e!-0JMM%4(JWhkL{QmdO z!=5WI?fG&+2^~S6G*Dp|@bXOQ6BlDP!6v~kQaVs62Vicgk|tJm^HkFEpMoOyUB+{9 z4LM$ReSlhllJ1c!NgtNEDE>qGwPjK=FlylPw4VPe?vZo~nHMGS9s%I&Vb=BIMnyJj zI{~VhcW@9RE6FMql3_M?2#_Gs=y5^;whZ82z$&a76#+Cg4Ez#=qS-<_t3jjYhf2pP}MI!tgr3J2sxgWs-4!6phE>E=gim7wvy zi*zmXrAbb8c*;dt9;Q!d47Wr56#N>N{zY zmG@REbj}$Xv&9UHPLL7gaF#|n9bi|^LgHFxHZ+vVP&1WbBqgq(sDdGpa<;U|WAtfn zXdF48bFvC@>ew-700L!NjNZx)xaxQZ52sjIG5dm)L$Gn20@&GfH|Z0x?NWL_lJX^u zL;Lujy+>F}^3_ggW<**oeE<(gm**tO5d4&?ktODd2g?GpI-7_duY@-hm)R&SJn&RFUXT&$YAGR*V8{-Ig()w62XJPAxX2CQTYweu`Vw#| z3Sl25>9WTCBBFhiWxdI)aAyYahaJ0MiOH_gUgMv^6@Bfj0oaqG>VS z0ltACfV~ZCg*cm4k1Y0}avA$U4eHWj}# zBTL|oK_P&!0KL!$q(1>r2c89H0=7IDgi3<+xIbZpm(X6rB`NGIAUMIo8HdoIEQzBd zs_+5JpK}SF_Vq)U^%XrkRVM~qe2vn9HTiZRD{?1q+~YL2{wWz z-M#J?^$qIo%2k$TYM_qs6IH||Geq5y2*i+(AkwPN7(ckQCvd4q7gEP+q`#n9kZu9| z?7H-V_pJoSJGE25^GHblczIZus>^E9m=$$O4FF#=m4e{7d<$S?tQ}@)P8mxncRto4 zXe0%Ty8DwaUC2HF$C*YDlf#g37aF;)EeXCsy~S~B_|x1!ak4VuEV}{8gJ>0FIs*~oqqe8lqHZ}>5yWA-bv})@f(>oV9L;M`MRzR z<45khx}C09X@|@M=9aIR2wIj}Va$SW07{BPiurQ-YVNYfXYrTeS{AuXG2+Pyx#EcNFdk#t`7d4nBB^e@>LmpazLzMhvu^?{VC&XGW@hMQTPe>B% za%-duNs+tmQjq0^STX*W1ARgiXD@gcci<8mq`JrjT{0yO&=H>k5TW~g_!8q_n>;+) z;)kFB9wc*7(i|T^t$bdZr2!9QfW_cjsW-!;fTI4rWqjnkbeT3fS>^SG56%YQVb}oF`lUE&oQY>gx?{}`2f~~ zHkh!b7BD0QiINgqLh^!HPK(e$GQf60rHsU}*L_AOATYD8fKOA#gMDZ8_A9u#WUqfb6l6^%F)wcNz!-xKcd0 z$L+dXkndmS>Na+h>s|y|eYIu=XLd8O+EEBCBzYjo8j0aWI!d z@Y0z&qB$=CjVwgR36VUyko`k~2k#_ocmEgBWA+ZiJKrT$=5`(p;rAnuV zq((v_@01vSA$4g3>kZ2yl;KgmX6{nrpoQs6Zke>>3Lp^Ahx@p)5Yw5?4tWQnwn|%2;=_HVX+NG(_WE6_N9sbO_M$j>zBWz41GfHidb4L;SD5@I-=dTF6|yZq;B2^kyp`A zxd3=ly#H3sb?m>Yxeh)2pVeIdM|e{C|Ai+t;B&>HXM@b_@2fQ}y=8whaFDwt_(kKu z-L!p~I&arS{C4o4>&03--#6|2b^WT__1p84S63%|`~64$_VXuJ zxbH`P7_NwopGoQHYiPdl;X^>sf=zAh{Vsd-sXaaZ5C63-blxyuH0ZUT`FYUydu+_F zed4Fq``F|eU;5Nv_c5Q*@m!6;7S_xYvn{>ZZ*)5&z2$x6GjD|?&vjToD&rw|S47q5 z3&}*&D0%A7*tUkaKd;*CO5I}tJ!UeSpXy!s{@{z!)wDK+j?Bj1>(}Z}>=)J?T8`F4A!( z&ppzWf|m{H;L^lR%zXsx@{kS=F@n>j6QtAK>eG+eALXx4n=X}Pb;aki{$Vi(Dc-? zwtayn%ma)hW1|rM1OFmIRihazseIl0JD=RMxRMZYr+giLo{c>abK71IJu5c#p?-M-6tukU!}%TN>1*debCfb|NPVbP*ML@;rsa2 zx0s&|&X+#R2^JjK|F?`n+V78i?^>eQa{8U#MU$@1%zAe(u+!FN6YrBV$`6m-fsS%5p@wu+5YB7`=qLI3f zmsGpycn5!goK_|FwoVBCu^828FUz|10(O};B>((`Q$S~7UdaACIOWhnPK3tyjxsT7;;Z(#^j6~Ki$zrT!2h*`#V}4&S z)1&G7hO1#2?E&VmdPS4EH>Y+@wDy@ap8AU@;M#RKb8OmXKIUzEPBEwbJJYLS*>ZM% z^TChVH&JY#zg0L!OI9oWncc5WrH!Jcl{i!J6Nwt zmSet*^|b zCM<=vwXJPc&t?{lX6yR(_9f3?&+N`cGTzZ)6TZ|9Q4c^dNC=WEzr+eL9RqxRh}*LE zq^9ZPkHQCr+$n24Ka{V>rKDdKwPAt{4$RIZ^A&v zYwe4(-*TUJK~b|O~fC38YNM>JKy;7$%!|&Fm-45RLiVVYWQ++Ki(f>=*h+0oD%E& zIs3MA<4O+-erIe2b%rn=Y_+7a%sV*tR9v3?Jd4zb`xcQ)V*EycseK6PptU2aY^*3y zt3+o)AgE6U*=TVXY9D&H0iwIYRzE471zGx+z|3VZ@MQ2 zSIoDBX&$2BZ!T@yFmN#KAGLX?CJJ-FUvs{FUBQ88^R zZL790wWHfU%zL(dDDv3QtLmKOCVoEHP{AXyk{Ub21??!oKkWp9AzJkwwuPe~&J5|5 zB^2)ck|hbc@$W=yd+M{f%A;qIj<9Xd&D@ms@l?B9U*|GhdS@c_4%Q)0Nw(waSx>&^ zq+XwX;jj;h@7j8-I#IRbCFxNvv#-bK<4%E)_2XXHiry6GA?3rEX4Whlq(`ryJXXEf5z+Ct=RK^x>B?*>+pZ($>^_j!PiudT zv`Ej~;}CY{^|QIPvXNw?qe@p@TF-(t(-7whZ3x);YdL7NAFemk=2*8*a_zZ&yaDGk z>@>OcCdKIYMb7AVtl>|Ezp{pI2R5j$F*%s5&L~jyK(Tkpn)K)-?88UslLnK`wgidp zq^`adPkgq}UvzD1lVImch58}KJ@2Pl4QuX5@OPd)>3tjdwSL3CT9WGST&eaD{KHGK zq>eAQz~ks5(ab&7HQhR$kqWFoX@@SMnR{hdZn(M9chkaFRm+p>twI@Rcc1?`b;tMn zg2%2)0h9FYSiV-9q;x#ydR4FqGu(mlcpp#p@|t`5qS~=5uC~k!PiauT{&O5>{Q6S6 zYSGu^zKzG^U+AuE8ZcSeEhKC|A#)Bth#rr{()r~(0zQaUZ+JArQ9{D!j|lp!>N-f* z#^&so>nKI{J`SE791jl1hnn3C!T&s9cy{<`+re`y=ErKcc&cysv?o_M;GII@+P$tZ z-kuk>xViVNr|cyr{hhDz)rLEpx-(YaqRIU=E!6_FiK`MsQb>aH~ju!b))8a#KWjq>n@e{|Ymk;(0){ zmhjdwEX;S|DS9$VP#`HrhX(x6;I|BJo<@DeKBJz;zm{AVuMo;E9#zKf1sr=d~LqANey5%DHlCvq|xdSG&Isk!`DmxW8#xk0LG`i+7utM@OfP8q8rW zQEz+=ISBh)H;|3CJ>)J?$?kkX$%pW7>dFV>pYYv2_aYTJQ4MpO zX0lUZ>3~jRL&QDZiZ?g9cOvd7 zu6VF8Q&4h|S2Sa`Fx2JA#$20@6>mDlv*WaQa~M|B*<(otXVBf*j_95$fW#44T61>* z=!!5GC!Jg2kgB&4H;PA(nFlNvt5fLi8MhokNllX1WXtNoOgz4Joj$T`az_cE(hQxh zuP^4?$L!*da4^M#?iuhoVJ_d^!h~yI&S*Me0W>XVZtt-=3-?Y>OfN}+V=_sDhdB&; zzo#0Lug8vaeS-lRhY>SfBc8}R$!iRyewEl;)c0M*=h7npkLEJhUhRRPB&S@%M;Qr6 z&{h_(pMyZ-82@ez8O0xw*sDF&@D3X;;=56NyXDCiPf7^hVWY4ognU6>4eG*VOWo1Q zIQlsQdvxzvSWTMXWnn0K)Jvk%v$+`7@X~p@2p4b);B~Tnc(GmZbU?nb0F0ZP0Pdg& zRG!Iyiiwc?L$h0b=r8^t3cU20#lT;ka7TR|k+|94aIB54LIsQR@#)JHYjT?Te zOgZ#^%Sc$8upvppiT<(A-<5BCxH0U9eOKV$HDB^iLX%bPxexD0p>r4OLx`G-MPONp z&ib?D^Hy64hZEoC->lM39OuxhH;>NvDhBujx4FJgD*K^V>~(g5ne}j8jH_z+8#{d) z=;LfaWRtFaUmz!s$~9_;W9mxCewl$`72)`DP5-b6$T;2q1{yhFF3;lTyZ+7#sE?9% zIy9^L@o=~N@kYaP=g4!=q`OJm6xumBjUmzJpG^_3;oS|?w1p)G<@_G6=LG9Cm#(PB zDPqlMEVBmM8Lz8=S+H&6|;?%&=7;FnpHt5aw-Yy(}pH=`_dBpdVs%e`G>;TtB7oqd19EOJ1S7 z^?Tf8-6pd`&;k1}?zu<)6!D;F|4L}QIiTKY!|ke$vD_6QqcM3{6m|HTIl4PNFu1lM#(RJs@?1gS z<@7djaGYooOUyn9gU)j<-9_X5zCFKY@6*b`l()D|e`jaXZ*QVyVBYa*^o_JLJJI-Z zH)mdE6g19$7lU<@Zsb?JSs-m=bug(2S{4WTczUlFOjHeAcK*>%&+^yllCFLbYnu+u z5R9p0=#tV)HGCSM0ttO*{T)p3<$nA6`eUJOv9ILmF36pGcTdCoG<01Rp`swviQ==h zu0aFzfztI6D&qOGBJO&au+AW4ujuQj`QxDjfpI~ksh}hT`2*NEh^9l5^#kMCv z>aVlOvdp+TxwSJH(BYf;^LYp)w(vXy?4Ymp$Yt*y4m8N!b@`PO>}y@^N-3W@sU?0lUDUEEBFd?q&qnp6 zLv6?d+=r}f!qn!^)8$1_f90HJ2HC~L?m4(K1I$Q6y1KyLbfe289 zSa02^P*geipJ0*QXmnTYE%alc}zc zsD{E*iU#;Xuen7v=~!Qe^fF5>5yK@>q4@I?( zG(xMpv|PL@w7ToviIWp|)5F4{1Lp0*mK>0o#;hnnpSd@uy9{#Pbn5yyfdckhCkyNo zuY+C(ZQHB~%Ek!2JJ~-(0-#wIlcKISj)QkULYu2=smq~_L+^}Q51+V>Q&Ymh_*rb@ z0j^6z-%n_H>?0Y~2Y`a2H$2dhaYJ8sF|86+3-NcoQicfac_DcHz81O_LoyT!Ho8(ZnA>lS8H`()H$X zB#^4*)2vYl8D(dKN$4?5Ow?*KXz41d-R-3(@G8~xmjlGCf3HMXocEN)%w$8C9Odz$ zYXqK?Ps%SY1W!%tuxRK|=hHt7>BlXvKG=6aQ`1_Jv>G?!9k5ORW8B%cI2D9@_Z3gW z?<41UxO3(p|A-kRku6u4V|K4eaJjk$v|?n^4~7wWoz>*fK{PpruD=r0xL_?xsuB*P z4U%h#++Ajtkf$f88A?fFKI&d1o!S7(#D2HAU^ z;><(#*6qeZZy>N!cXATyu~SQW%tzQz1Dxap=!A{pO1Qggv~~3Rxlj^lQ5oXUS76Kc za{>INDR}|Z?drI!8&nV<(fbSG2%cko%Bxw>>Ei$|7t#}JlC&>F5oKq=2xQ5GB=SQc z1Hpn*D~X4K2Z4g-_e;=nvGMX%=!E|8X7USM*X49leg(sGm^UYFy14A|+Uw9)%{^@w zl(KjtPvG8vy1>W`DhfKuecphsVx8~;l9Ae{dNu$LItQOG2D|0LZmfnB)sN2z8PHp< zuW{-Ov^ez}ruisku8$$L!XdPd{`lQ+udf$E?gtlM?#Z%@$-i(oWm|Uqv1Ee>54sQpR6Fi?u z2PHEX1F2VnG0Yv%?YG%ZzKQ~`An)(LLPtpL#zO(Xe{`E|t!U!qR}&0C+Pd{4?t?J1 z$T0sTPYa0qkp@|Orj~MRpn)E@cmUE5^@_TnDIa4h8OWzHcaQ~l>M89Kc|@K5bR-NA z_co?wZh-zy%75@ij?Q=8Pw0LO2HD;6C%7d$v+5w>!}E~?Fl7(<64Zvb-yX|^LM6bS zxd~3gv_NqYN3tCnP9n+p^-6SL=VfF3j0&(`D>r3)1#)iTUj*2n19M?edP@JO4q7#& z8{Z9?>^+^8(hjNBGoZj3-EBI+2NgPmyRLpe2i`3TdM^8^=_Y*VeOCpjyW}I|uNryi-F~K_wvR zlpRcMF;W%WfQksoJ6f3`KSjI|dS7O&d$C$v{cU(bX~k}2TZ@W2B}HB4Ek(>1AvD3-Kz{2IkJkM zSpsYH%&t+F?~Sax1UzOl)RPUZyEheIEbJ6gi@Ie!&22 z$osszU_)kqd;k<3=k9;;AfemqxBM#Zc0foq0IhX3ya9eO+N0E-bYi5miabfgU>c{k zFv~uBpRCz2hLJVQVI}fmawT!cJ`rwBk+a{4yuwcs+QFrg6>e&0c&Y__E(SGR%2CZ} z?~J4m7()dME7M*XTH8DBmaF}sKHa5LHOKd?@-8YRV5`qh>=g-5=$#kQp-JCnXT5Sr z`CRom4H)h^Is_D*-FH?SxIa!T8Yro*$xoo}u_P_Bl&rf%7Ze2(U1tM!y%GU9Rm|b< z(A)U>goTb&7c1%dsSCW`3s~=@DVC1(>o{*tzzNVKc2~cFm{xcntpR^314)IFM^?_B z^2ll zPI1J36*!lTD$7H;w{55+luw12L`hq&9+^)hj}tMOk55a5zxXWV?_RfTXMvSl8Qm8I z=ne1lLqcG7NtZ#%B(`~WLYdj{;=Boz$G&+X9c``AF{nikxt-cB^SJv(v?1y=w4YBi zqe6C^Ue^$I!AF*^@#q!^e+QSsf!(VjhC$O+^dc6rKCcFC;ENuXgd8wfa{wKZs@4r; zwZ~7$j}sdW>qohd4kxy98jR)X;6XS57){D|z_Ht?FR3wr)&Aog1`E7jf_*2&lr$ND zc4ej?l7Y#7FM~sAH}`byuW$ye#%?|8UY{q3dXK?SrJ+NA%fpmIt_djQ7b&)JIM>SNaTr7VFEwH{f=wq{Ab88lS3z zl#Sj-=>+A_wOWYH?`z4A1DF5cCgkaC9|`&Zs`H;F=T@MG^(ho2mo?&=U4a@$SFHul zQPL=Z@$%O~m$%5$wI6{N2K>ggFkYd3*A?|@jN!{j07jiDm#h+aUDM7(OBb8138k=B zD*NXAU$7H@7_cRBjtLEG_eVEVxuC6KvNQ{Y~C@7I$ zoKk_Ki%QIuF@I=Md3n+a40e9BJXq=-LOaMB7EI1V0ajt)2SNBF=+NyIz00<-{BxG6 zjl_I!HUF?d7@W3NHW*Z+1YU|??uhg2yZ&(?~&b8^CAof|gJKxJoxLlxAG zk$OF}K^yPRd6tuILDzCOeR>f6c~j?cS9$0mev}Wzllsf=*1Y3Z7(U@|b0PRNwTupP z<>}+)<(v-8^bSP?DymnEg8qv<($EF<*^bi%Wnje=Jx;m&ixX^_O*TdJIj!G8A&ClF zt~3@ae+$QE<5j*~0n4Bt9i9(ABV%ksBqicGG;W-@o9Y2zCl&|eKS2_$Lj_+dV;56S zmqUG?R?MJ1EY&v{(I3Nbc%P!SKs)Va7v71Wcm1L43$j0^eVSxM_P;U-)}&p}Z5ya1 zWCjBZI`lD~SleJx-lEV5wf&BH11-||#ae%B@YHBI_>GxvST%gy1@Yw2!rpM@4VH^^ zCIxY~PWg~3@Sfo$Y!6pHQIhx1Ipl;e8yg2UC>SLMOHrwK2CS@md?-W>Ui?w3#Ka22 z#XF%M&4&*=j{Xnu!)0V zt9opPMC;?|d!YvXTh^+@aQbYJqOOMDRpxURG;~+zF@yLLCyzHx{m-$iwyO_Q#ZK5u zgRh?xRG8~=hVIk_yH78`3sH_!p9c_0lqI4HJ%|zN-54lx6#0I|{~YmZVu);912XC3 zy$7Ge^eWj#pro4da~6UUGe5(M7P2MF5(Q%Wa(7r1)SEh~hXP!KTmL;Tz;;Yl3ltx= zMZ{?{l;MdU_I&$8=j>QR56ze7n66#zLC$%R4c#qzwqv zP?}$QA;S517ckH@falR@6hww|Bxha-C$quBl$~JLGL1ZLOc9$OYg6w;xB6)Gn3@BO z?})0878nlHaBVVp?vk=vBbb>bGYo2;pFXn+=p!XoJRb#P5#wgk*U=1>3%|&*OrE=$O2` z&t}~xT-%kp=LtrW|3V+!Z%tZ(l>D_(r+=k6(#MT#q)4wZT@)8!KVRs>IeCv{0h^H7 z%i0Cxo#;*3RzR?9*gF7~ubughCi7hle#40{cQG-n1kef^0$MJBY*?&WgqTa`&^<^8 zrqi&HKRs!FNg2SL8eNw0nAJl+7V@O?YnyS^hWYU}ZUH49edc(hWlP6cdBZbh@sTe4 zMT#r%i`hnq65Se%+yg$Osh|m96oeTg9w2H$LVX8jkQpBWM;D%5N{Dnkr850>G&q!D;U)7KjaIrQqt zX{o4LV&)br4Z};WwZxMzv}_!i^Yc5^TVMqi=wKNhbh5uiGC(s}3i6?hfU@dc3z!8_ zl<2|x+J=P-+-)Y~M3gJ;I_Jq})`ORdFg{T&p_3OuA9P|l-f z-Yo}Bps>~v6qNk#ABNDscaDt$DUR6Sv=tsCFj6OgDlwlF?E=asx<>=dlp}TMHqM(s zCjkOS@aP*9@JW=MKPcv$I%Ex~f$*tw$pI15v5d>_atV!#Ztu?k8|M#!$Ye;kk)hC> zSiOO_OyKo(@X zE?dFuSi-_i3}?TBt(3AEiJ=fk;_=tDBi>DEPrmW7e%+O~!X=JA8jN4zz3h1FVLrAz zisfXElyTK9?lAEsfm7{(Vq~dQa}I~zQ;ot^zh}8w33u`wBP@JRbWu<8A-MZ`aND;z z8NaUs@!_Iui>`+pnx*GC z27rBC9J>SP1|)Tav|CD#$M5gLh|^T#e>ql7js3Jg0dinkw*D^1YFe{&3Ql}&Gg-n#=^}aMM#^0!1^LFRO)@p=SP7Nis__6y?vJ> zBCvqK)O^^v$6$&EUR+-bpo86Sdw|ANmr|gy#&`p$s4OR{KGfQ}BLMg?WPzTthJ$>+ z(Y_zfu2Efm{VRIu#(Ahfrs7 zF!rphQ)GyWM4e4ngYmMv_JZ5=-Fs6;0u;$l)&3Ob<;Bd+jX=niWQg3q0m@n91)Nq? zTt-ZCsJ*wi{1;FL)BPYdT;k-zPK^bSiMF|bVaS`0>ePbwSc9f2?O6Mfadql}J`#o6 zR4FT-eSb%AqPu!pA%iEfFm+}FvD;IsFS=fIHU$}5e8w;S8#|6GZ@P>HYwy@ z;AaTWMB&8Ra0c`jlq!vp^zSv&zzoex2G%A4K^pXM%LEf;j|)e+4f|}V35`DmrbVu2@(HOuub2ACf_|YJhht7_sO;jngM(6 z(Qr-<0K^S+;@}juspP8RI+&mq@+6PY`1_svJj|NuG90y4sJYTW{GjwBYV~VS#$uGpY2N)hZfb2Yo4l zsKsG@QInGNFN^j2qdsAy(4stnps-!z>Bswoq=lXqTVFV!&euPr{K+A{zD9TmPzDza zdS~Fpj-qFqh4&6<9Ns*J$)>b9fbooSnb{68Lq$r=?{I{!%ydi#!P{mbR$-nKio7)< z8rM#j@d`#G42vhib}pk)>A4N1FNS(KEM<~&8bSL$I#hN!$aXyawU(CH{Skv3~E~-lr8?tO5 zHA_*jAu3IzL>CKD5uzd>AjCpPKtMVqDoa?3h>Czn35YZiB0}gPHbg-PO0N+qp$AAv zNd4Ur_J7~IpMB4Hp7Zg15L0L79CM5@$DDJ#?+Eug8|6t51oyo8fz^gXLk|uefE8gM z8E|ZIw0cSoj$D*+o8#2n$t8uyVbR2E`&3!8J>$z>3swqQT!t-duCO5;;sarpe#MpF zcydayHWo~cbb7n=j{ za8jq-11fg%ddYs!o0;XN2c-*xPWvf*gB6eaoe$Rt;|1v9g*TZIwZr-$5uR>X7pp{~ znpWO;dB7iz=sc;ajWM0;JU;H|3y#Rrc{O9xg=COACkDF@&@pL+wTvjPWf09!0ZviU zf|+~3Xf`C{pwWC=1#LV}P_5%3VvPuGo}smc9p&!-a9cCX6z0O?boT$W3If1L`{EWN z~&F-7HsIkybN|BhNJ;sSw&EjBNv0to(jR0o*MB+Jz;hjp+>^?&^l^s z{60l;_nA`?v_XhcN3|!FfRBqe(ZP6&Rj?}NnZg~GBR9*m7jF1;RJ85+^J4g+h~~5hylI@@Mb0<-=0uq71~(#7l!|US^B=c3AV*p#Y*5~vg+xT z6t+2Lx&Uyb-wELU`N52CA)$*6Xog23wy%i1UK+D{F;8^JXgt>KhM#T6#H(M z5j3pJN4rL0YFctr{sivJfnX9GNjjFL0wJ3%#as>I)@UD~L=BC;9uE80jh5=mpt*W{ z*B@}Xr62{6Ti$$sH2)PD)w7+!mYdc1L_JW2=rcjb|M*kk0-Dz4#U;0m^- zL)Qonv&LdGbzzgeRay6U=;MxG3J|##+L=PEURb*t4g=X~LOBRsYlD>Ty~T$4@L-+K zrJ6~yAd=AY>V-<*=9EGE=1jt>!hKU9y3qV-OIWUMHDMvXiP>@n2sN$u1;H6=e@!6_ zzt{6mH84XO&9)eVTuk1KNB~*loRvfwmmlJ{6*d)O2H9bHn7R z$mcjOqo*8MM+GhC;}Ng}n6Wq-%WeGqltZ}^{1;m@97n@;^a#rW`@}xNr0DhMPK^MHO)&ZdWCVCQX6~rPC47E( zIHnU8n*Ig*T(}5fqyvPOmCa1MB%UB?<)$aFaA{?vV{isuWB2bW3=P9Mg8?_=vmRF% z-7}BpU3~)yA*~VN%+(=K9Opc*r1&i%G-XSH_PKQEa^WXySapIt`XPj61)ww_iX11D z!6{uUgWM_&+tSbkd5{3_jfO@f?sHd82(O93g-is&weSU72aSGqygb~X1Y%5W4zyQgSn%ML=y|*;8v5s!)e!Wa+3t>G&X9{+u&qZG0 zdw^B1n%2E#R9P-ak-QEfk*vyb;Fk|`j3Q=1Q;*%DRt7{o`yuO`)Ig~eUwA z>grpg9)>9pHQG;j%lU(wEPGnZ0GR#cdb@)%;52_piU4X?J}SHn3&!arJbJtK`S z-tV+`Gp2+dwGFS$(eb-0cNba}jusB{J(ajBNf%_X6ua`UfI9+CTj)L^KQMy3P@vUe zFn%2rEUgPG_>O69vOxofx2R@N8pgrnCPch-V7F#)KF5juoh&^P1j{uZuLHsM=U3kl zr$zMD&iRS#$|D9-pu36aE?MaAzRgA&5WfX=bnL%_d+xX}=JMUu&0luI{mq7}wACxG zxQjQ54V-7Y(djy+%z=O0{X|-Ri2-%tTp^*y+uE`3JloRLC0D@2{ zRaICR9uB7h8yb`1=-b*#4XXaG_bEMYGVp##yQjs4c0rsYGe5~J2DJ*TD|Q#l;%QYr zJX2~T=7>ccqaj!Ys{4&`%>fP@f+o<9;^=ZcH_eJ&ezB#zys3EJnRqa@ClxdU6*?wz zYS48E(y81c(+O%{fjX5!#-x8`8hgq9CT;!*E+Q*VzqS3 zp)A`|;!S1RrmSmwzv7;=_q)Fiw@>K}ow*8AX!pw|a1&nC^T(uSjp(=n?|9Z@anjHi zBJR^9sf(hq^(3(Tv@!g5g0 z(dSCdmqn*r{cz_$%XMQS_b26E7HP4_^Ewcw;0|5U9>sX6DThIvQ!z9JL640$87|}O zh-8{2bZ0&9NWfbNCk8H^gR_X~zA?DmtF)qBzm3aw*ZW=#9F&(WzR@5wu``;7#qdir zwhwXv>iYANHRu>6-AL7yUzo-Y$yUE!g9KEn|272y#XOZa+;K_3Kd&-J4cfu)*ijQSw~dcwL_c@IA$@N1ecp z{X-RvXHVr8vCf~m3%_8D&fm6^@Ba9gFsbMX+#vh5XO8Z9OURjC?|#sR-P$+i(693a zx_&P|cq|9<=i+L;L?_v;XK4wGa3rsiVl`$Di8j+M*rD2ZfHrgIXeFT0*%hzXIiVL; zwIet4A;s%1m6HfFpOxaxFbNsz=my zk7=x;@K^gsZf4mt8t*5RB;hLbLNeB*@7YyA9mTT}{!WjU@hxA!iK&(UxNCv^{WSEs z$v#~Jjq++Pi82vi{g+;Exb%1j-~Dnp(@zg1(^eIV&qzhbz81dlElov}rX7&rqEvK1 zs*!!bWB7m9$OBtgrVP10N{&D|sD71*Hybe0-h@^>426iiu2Plfy}X*ITjpZLjlZrO zxLOSYq3?5udo0vyJDg2e3^(_3YA;9@=lo6E%?I6|%Du{rs!V7mmnR=W$w#lL`n`gtka0Hwr~5cM}SCt@tU4mI{<*7zm; zML9o(_?(3+;ldHriWZE2AnW-5f1G4a*)Q!)=ubX5G4H>*NN~UWDgG&FX39F z1bVc1kYK-cBBZh%^0nYQ&XDm|j3BYRdBIs2tbb}n1c(5mFYXA^$Ty9$24WhBocj=D zBQL*eiB4q-vEfI<<2d0*yWUqF3uTSs4`X^EDGxrd_XLOyq4~lhTFgOTXpV;ddtL>{ zP*|Z9hw|`OReU!T4f4hNK()S~&&T18u#hg&f52@$X_kOFi1)A`_`{@@(oyVrRth#P z7WJJ%v&aFh&i|@*2|lvC0#aML_;}#Gm_js`CX549%ty+Bzv)Tb(_`ZPl^1YZUFQ&`6X+)Q z@pEX(Q$GZO2;`ld_R%bHa}X=RB%Ff`13eP~Osfb1R$BOhaQFcP0lLR7KFwml2o%cm zC+9thdUe%T8bha4FTf|rZ6^iU4cbs4y%(GrJQyOuRCc6A_Qp^&*vLL;D{Nli>81J6 zvyqD3#};9FRH)L>Qry=NH$%Fsi85qD@}B5~{!5ZR|xK(UnE*xBU0h0s}7|v}MTL|!8h^+xpUJ~Li zs76!dxxQLaH(7PH+H(!(DvTE_xDJxXRyehyxm(G7Wk= z#JA8<<)smV9|$coi2@3zDFitIHo`}83&aA%Hi_p1P!UtY@~_l5(32%azyqUH7lK_f zR|agtU}`rvi)X^}U&{803))MmNq@{od>#C=SSP}T9+thLw{noWS@Jpe9>qsIk(V^i zRU)*zVyP32#ovZQD)_bex#gDo*oY6@F*X?`-Vwjuc})B^@iQb(gO>=cgbXrkVyw`+ zXUaDgZZTv;Nqafva$*&klmM^&pHqQf204OJ%^X;%;f>a95Z%IWFkz|oA)53f=i!MQ z(3My!<@y@FY*PL`mXGcE5Pzt`=mkvgfdC}NE@fptAFFlsrt1QN&nzobY8PruY+EdZ zBSihIpTgm(@cmg_c=$Y70Nq-Lco@3yHHpLnBOf@IXToskhzSEU}_n?2wU3Q-2 z=zU9KN`lKyP%@xMg`YYKep$6J^nqBIl)aE)X&=8gLu?5YStzddbR7n?!9~}eyh7|E z(f7oj6%7~UcAn{TOR}TGfrVW-uvde)%1y=MvH^<}BAlfK&Th;Gtkdg;h_r_iThA4* zWw5yh>rNW8X&@uP z8~MmF^J@5TBOKobX^ZQ;%t_y+mwrLdgPjP=nhF0W&;riG+ zI8x4m#@vOQd{;ImXrggaSM2zfoIJM7y4f=2@OAAXwbJfdMS&=%Y<7|WOflfMC}-d- z6Lhk6puG)x1=$7AD>(HB=|P4C*tx7&Ho8kM--Q7SkwdCH_tTRNX^_o)-SfKTQX-@c zcHzX*G}STeJ)nUSaRX>J4IYCZEy#zSLRMeZs=&2NN|&-^gnCQzE5Cs&-D4$k1P1E_ zX2g@JPMN?W@8jaeFm(%69rE43b2LgfE+kql*%kqE$QDb7dm+UI*Ce?lNXn9vEdMSx zb*35QrJcU%DKKb(p3X0UKc{4Zbzp>)7X7JScP->rp`-lN@mG` z#UT~46jC7&QY|zoLn+Ygjo7whL>=zb4VHV!Lt0%YvFuIX^@W83=(9~85exkrnzR7} zEm(RC$AuuVf+bxGHmrso!o?oEQvE`#yc`Sh@i$|2-+oBHou=(YVRTCG)&?$e&y0xh z29B?#PSyThUoJLTdGV5kU(#;EL$MMQzy-Uy8N%f@xGDLib?a!YBk8Mu(wU`2Ve^vy zDst&!pLKZsQXtkiGVQ6-x6ye?1t9$vGy|$;!C%NK2mM)E+|W`>ZM7c!Mo^VL5DzCA zq}N63pb#-1XZ5efD&T@1q?*Yl!<3zPGTr21GO`yeJl9JqBh;gBp1X zJctv^Gk%|rl~Bu*CD)EwR}^b4JY6XcUfjQo50GJ40|*@~3v?Y0JRUYs?uw%c#0Sn8 zz@XNQ5(Vfqm7hm}z@_Cs;8R=euU7tM zY;q}f)ponBJKQ$O}qAtX1rmevqCHWf(*+GFmN0`Hi0cXHj*6&HB z^tQ(*cdC7N+I>)OO7+j3xrJtxzxAT>w*TdK$Dw*>*Q}k*a@8mO<}C-5PyaJqVPd)e z;M{oKl$U;q3(-{OblXI@cp|b9>#s1&F9cbUg^1wIV zOeab7$(23M7emnv#soKu@RWOTPxEX%F0I-AWHSv{x%}wBDT!4WpB*hs&7@~j#pkAG z8a=x=hc)c#aJcs3x3qrFp-9&4Cx%`|)s`a3<#G9)&%9flK1}ESR(Huae)+2Ul$~SB zMHem~MqV!4%#B(7IQ8K|z*?59wCe=0XsAe+0fE(V4lx~_tBX!4GT8k%CBy0dvT0M! zsTRZB)3@$@l`hWhI1~3FazJG@E8Hx5CApD!wcG}?^+wQ_Y?(0{GvT-CAC9U_#$caM z@*AzSLDDlWW!4+EXEUQxvyUO8-J2dzaAnIjQ>s(@v5r?h=pXi9eN*u4>YAmWmpqED z!iO9f<9_rnE@75%GdBuC=~G5B6P@R^&2P=*xUSZUlO%sj|0ch0(2;XJkZSH4q`Kj9 zP@`ogBe{M?)_!W{okI6e-CgUyANq(65{}XDYQ(K&zdpaFO5af8D9S+fUB?PxcjO($ znF`IIJIgFnO18K$YM=aD-eV$@4T^?9;?dI0mBX^N$*BWLr?A&(GK|*F?r7kr}BtCISu< zy)l-cFKjC{ZdADS=Ea@#Uib9hrcE~Q8f!YzFw^0EMU{75_sxvayxi?k;hn5atQn1K zpCz$g?>GNiFY%eDnmnhREn^_^E54l0xwlfGR*))J(0k%Ey)cp9JtVR}!+5TAzq3B^ z&}P?~)2I3T7m}Jq9F23*4)`?G@Gv_-cb%@ZT1zAr+B@C0G6^^{nf2#pM-=v* zK`~=!x1d)8f9=+SlMVr|P+td7mCj?|PFmyJIcs)m^a_agxVdsm38ny%MPCRD0k zw2D~1{fT7|KVVa7C^@%_+1fQpVYt34sE_XC(`3RMaN&OGcLT_H2mJ6cx+zD)FN01U zZ^A?fUo)^Rx;#V{3Ze?Cx(<&FBu!l@N=(<%i&rNsGv8R4& zrp0-acTk~onN&mZ&q7Axw#&V)NpJM46L$ySn2X5FwTgb=EpsubRp~b+U4cA%_*+=F zP*nS=%097iea9uWpUn@b$+5?MBs#@}E*oy*ZX$jgSc1&MEe4&;_{j_^mIqLgmQHCN zPfG6wYatgnDi)Z?XJHKfW6y3J>b;6^%d?81@Xag}jdd(uv$Ja2!m2*PT+K4FO1tXV z1q&DHK*QaGkm|qt%}}sxjxO(%%he0P_-O;f^S?sMGjf+j#;jX?6P5Js$>sS3{NJLw z8xqpqX`j+lLke$|FUY@V$#)(UGetaJmxk)6d;yvUFw|*DM)6r){0-|ZX9Tlk;^q0Q zm!-88#Ff248#ZUyyd7|2hcqrrBQ2~9?T_ELi@(@-=FPPa9(9fr_8Ca$;rMQR+Hd_e zD>W<6M%4~)vdcjuo!qH8z^)i+CnfilJ>xoj+#atyyr|(7zeLjD_j5w<*Ez|4AgTC6 zGA)fzNHlse%e(AyS3=bqCnF(@*4(*m=fsw-K!2a#3Z)xlGW6@O1nH~p4SuwmSfAD@ zQxeo?edTh$xyHtCRa$|VEqf}0Iz!j+Qi9gB*baPJzqTiNj>I&7trm^_lCH?Xoac!; z1s;Knli0u|1^H8~AoOEYRC*lzcrj=1)`?LJ_37oSCv%qdzun<-Blygg^tIj_46Cf( z_Y3J}EtD%&%Qn*={?Wpl+}x#K)$d+Rn5bhJIn+-!f0_+j{{EhFCRz`3V(f_iLev`G z(CMzUYwIKo^i&Nrc2>2|Rbl;qybHa$5V4ZicYlELGjxoXk{8(=H-jApmXPKqYDZAH zZJ%zk?e;i{-)73JPqxqqMeo`knM!PXY4N6-duKe>r#x6lcAgUPqgU2k8$0FF^3(nX zhicY6t;{^-j??v7?eOr>;0(!q6HAk4fB8}1v0M4fx2uOWq6jO@T$JDZ{Q7NXZQK8= zkUJzpMX3XV>)$4?-st~vV$)beawIpCV_`c*vd_Bw>g~X?%}Eivj_G>c2bqSxk@WIB zrT{b^OG-*17ElXF7RpDfY;hGez4lr#aKEN*goyKVCl4rkMr%nJ$J5Tz(hm zC@pVcQam7H+HN}Y<>j&^m0OWUAh;kpeP>62s9* zI8G%XT4;)|(Yd@hY?9|K3#+na{W(;iN>f^^thIh?23m#sTiWW<@(o5WFBMVZU5SQ;zm$$KRJwKNtr$JGV22ph!|YyM14odC_cC{aJc zJ}U8f2la5jzjd_0WP2;tamS9alH<}*;S-nEc~hI8WLVZ(9Euh`N!~q;3a#6`X>yJ( zx#mswV%$_9wfNiUVD|Ub4{4#7md4s9SCX1!-y;_$t?%C}`|rkd^{WpC)EG{0 zA?h;+WP%59{)Vl@i>K~W>8~GM4*$7Q;`1g23I0!|bF&wcvhS0pudo;MHcmD97#%2{ zarFJiFtGFb3S~w81Me33^pj`BL~G0pX4cv0oJ;+byvTGk^q^aIO!?a8owPZDm(=y_a+?>o<9XjjN={S8I z$UbiVM?8!9H#1A}uK$i_*I-YWm|%_Fu6X}%xmge~H;dxG2|xO}?{7W+yUF*MjJ&+v zyBGgBKW#u|E+Y7md#Kg>@85m->0?O204uv7DE-0fs@&G`8F#GrNNBSDU}Ne!?C771 zhm$@g>7i=BWzRYvh|=)i6`njf*x0uoI~urnI4pw1;T3R&&fb4(sPtc&@;vfGSeNL% zuk5CMadz*0^?vK?<7HRP%D38A6?Ta~9Qr>``R0KiuQqyLyxuJpQz%5^CYAKyUnP%c zgqu+!@&^|wSmVz~glRgiH)xm~5x`g&LU6d^P&5kRg#9y)2p>3&D!`uw?&n3k0Pht0 zOoSF9U*r!7@jT?QW=1mdO+f!5_kKc%I5ux{Dw}m~{*V;1rS{vwjbyooO+{4!XLJyAvJqTYDPk5TW( zPL&_|;q~u9qJMrN6?gf0X|NY5G_)H+X{H@J5y*t0*-y>cGrqJ7b2?3@skBN{XD8kL z?9Gb(=z1TrN-kwV=`5!l-sNEZ*tXZFG5v({@Kwn{gN8D2tO@z&EGr4tLuWFL3Y9Nc%DDuXp#~C-Ve@_C}EpKsvgL)A$IZY2E8a@r=%lsw9h`KiWNM8Img(L)*|#5bTE7u zxDWeMWWsp%wB;lk3*Oq-@3Roj-;b;~+)CrQ{`1*K$SF}Acfm7DcwAIJh82E>fK1@> z_|u>x=o}PV$$x>HK7bnMvSFmcZ~+aEf5E2U5Su{cDse`)pSr*#@PyUvLL!0iU5Moq znq5W9em{`~+(*k%OEy<}gWd1A%J{%vNRD*z{m8i?^iE6jpjt(p<%TUQ4BxESaO2hr#h=S0kGxy{f91n> zt{V(W)TEz*c&z_JJg5IHp0tYp7SBqtOZwkRMIh1!rV7g9m#Z7>kqy=Mtx_17_B*Z?6*y;RcF891OMlv7Ty>kyRx4+7Cg#hnN4X`1ac-$uh<2k@FRgw)7b*&l(^4lSjGvc<=P7 z1ya3ir=rJxzBG-|??IZsgeoLVSSsU_(H-5qOrxE^j|03;wByWN-oXOGME?uitNK)I zGv>7pqS8j_FkjeH#1h;MO=32REXn1SmJw&3FMU(FFl9oT$h8!11vaG=OLQx<*M=&* zRDWRd%jKN_SmA^Rl5b5Y#scoF8_LWpA!}2PU`W1>O8{40eTW$ zw%zLu&@2HH6I&oKE-{U^;_>5g-v#+U zXf&M=!3Z~|-4@*joIw-MU|?sxWPraZjhDZn1GCWPDY_8-68HK&FijydSD8R4lo8m< zpiaLQ=JHg5&q>Vb^t+hJicIb?C+l|37!fg*h^1k%Ft^Gch@slT@Y6Zzd{TAOq$LiY zAKHt5wV-z_A#|p5rlVH`oJ_rrRcWJGs^#-sJxVI!0i-8Ztw_ySp@NYGUmLAUHV{&m*%uZfD2j4^Q zr-X$Og_)-fgB+`vi;Yl^3>D=*OtI4gRvkn?CABDio3mT3`Re^34Bjc`yF?Z_AU!p1tC9*3JF@=h9X$ zTPB_OZ}K~Tt$&fwpxMY(ZRYvFp^*~% zw%O-x6>kj=tMUfMZCw6#P}+&^7?rx1zFQP#Y#;vCJxUPZ!BcOV^Lgf0b9gt@+?;26 ze)Plb=DaVr&FSzU%=*M05}Fs1dp;lbNuaoSq&10VG|+?&CE<0`);+!Eg+VV>P=FUX zUH&`_QXpC-H4;&t%qsko`#8JsgJ0mFd|X#!4?xGqPA)*+<`p@tjWL>ZV#6t5GqG_L z0pCu^xHw;PW=0wZ=#vdnui?_hx9)o#R5HNv?gDE;=c{=rAN{L|9>0`%s|f5h@})GH z2RQk}9=rr_7qB+#^YY0brXZs~Ef)6>l2L;yaRBMnhXT=%L4lU7e_@kS>t)0%4Ot+3 zJC0U&EcVze&XIlDwT0E1F%N^1y3_BLsHEK%RECf*9VeMAZj2l)ThH$gu61Mh!#Cdx80Nz)pFW zxdXFAd6+;Bl6M>FjxWC`dxa)^66ZZtmi4^F+6x9V*?|ASkte1AAn{zcK#u3$HRyQ{ zpeAypP-sns)@Tf=z{(wv3Eh9Q4vK2{B#})Zfj&t#u`Z+~N0O6(r$p)KF1!k_)h?}5 zcReD`IIXH8kL4cMjJkdTpiV)6ly<-HYDgOL@!iPq+s$jq0Q;y?Xwrj=qUptJ+TzYB z4SeK&H>x4TGP9bP$53iB`)Ec!Kiu-@FQ{MyMA##R1}rKg5>9bao!&+%W5JWbg#sz#07M>>SHZ%ca-sDsMNNKn=Xk~Y&Vp*FQBn1 z`LquUX7*EOtUEQb$2-U306TZw*l<4dipR%}_5P6coOUm%Q`*vVAJlwjd#25VR;0W2 zYx8SBNxXE%0chcV>3OxbGL)Tt-BbWcJGwF(J_y{4kvPo}qGc;_CeZ>K6goocnUsBx zyBJh6XHJFm9f`YZ#&RwA3Ri$n#b&Zk0+Oo98EG8?d=K*t?IJU=CF~pF-DC2BA)rJjo{*aw6=l8=$Nyl-ZVQ|g z1K94FSctJwX}UlMqU$l0bAdEFW&(wqSJwm!Fhzu=B^XAjWdU@LD#-+QuvM`Yb*TZ zCdI?QmdiAvpQJHjI%qgCAsm;~~^@8&K%?|HKw4@5Vyc9wtQ zggG67oS!K`2=c;SJf|~nu+UultM#7*37_k36$1g1hvlBvp{JveIs|W zjm0E6K`MK@@Wu`Ru~NL=gK^Qe5|2R^D{ovMD$~EuE|_P!_m};GVzL7byJ%v`J(_iR z0ND7h3Kyu@?%nSjjO3}?*~u_a`Q!GFj#`RBdNMp1U7*1)WIsW6LlfBn&<=su%zdD} z83G#2OC=qCHMCJ<46s_hSI+;|9LIj&77Dao{*Br;ome|9^%YnR?FdcG5U)ULFV@-t z?|zYfXo6>!Rco}1e$B(nMnw&h&ELw4Kyx>6wN^rwVDWp6oVu$a&UW(;ch2EHw2Y>P z>6zkQtG^;y84(~C+R$p3NiEW{Y80>iCv@@6UfH!H;iczLR_Xfy5VlL8gB9TlRk)&E z-Nb;A9c4fp->^ejewBiFOl`mW7!s6ky^tpkNC z|H6bQulL|7mx>)-4YJ+Q$Ni%LdT=3AXF~XE0CJ~PtmHWtu1`A?vj zdhy2ckQAcIn1&U1yxN<-9kRrjwS|y3&3nt=s)zTwP&iG1<^n1Efi))el?&*}`Kl&Z zrH3(k(Xbi@bt-Ct=Ugx07bR9##)1;BNykv z#j;meM*t|@pZROyzJJ&{5~vUKve;rUEZOa{sE1!!4xq16J+d{pY;}VlHQQljWqj~$ zZ^5jHOMhsLmWnuE26clkbRS9rFK2&#GJ|mRmx>yQ?TNfH09l-H^1!O)Th^)tXaR)q z9dJvz4ip)f1N{$IVR|B5O@>7AIjF_oL zt-j9z%psCZnB^T$v7A2%h4BVoih%1Xdt84R6`xvgRhE|fBPdm9XPOx_#iA;?QZXT z@E3G$b0e(yCq}cK!3!rA@xcy?g&I&)vU6?-c*+k6 z3pecfFxK}~j1?3P*9dryauu@+Ks}jhs`iE0*>=LnC?y&OTe=AAe|_Rd7-rG6AYU|) zL*BOoHJ!65c=C!cP_8z(a7Txq>G@m`T6)(ju1Gu)!W&|Wn4hmNhg1Gi2>m$}4oTTz zXh^CdHKl9>7*SV62@nQO&Qb~>N#qx1YO zhtkHHesjLIHrV;6ja)D#SE_#@J)8`LTRsQsg~o+m?29#`mZKd+@sr7)*kHpK3#ru4 zLSv6qkFrz4AV0>3n5ePbZoJpSc$DY5f`}Wy74*DTT@3@wOp0OKA?-QJyQma64CWg? ztp$ui)3z>4aCg_5o-DwUJ*^)OIgja@91lofA951(`vLNaK@T~i(KCfL{ldKBw$3bc zIOJg7c<)ZYuetx6#oj<{6{-%b7hfSk`A4PEC4}1OwcR?yA5Q71Dr@NxosK5 zoiER+uM)Bbo}9l201aVlujY5mI^*+KVe%s;%PRnv)rIgOaFB8kjp+gA1EU4y04;l8 z1_BUP$*kTHe2Z6{I%tm`?&vCL?voE8CcJSUBerK3H8QhFG_V7~0X+T=p%$X9kCA-n&-O?oPp#uaU>$>e)D)6Wh8;~;_5Fb>?IlTH}hr0ToN(d2w*sq z0yU@+_QsjC92ELm?l4qU7X`b6Kk>@bgwW|w*0?0-vv#C4EVb;2Ai!Cx48GF>{3pW* zx0hOy*)(JO{wc~6`zejP4bT?4f=A(acEdZ>$54pcI2yl~MojMcg4!?u-b!k{nBMJ~ z9p6(-1UUwaOnN`{6+(PRWzT8DL_B1ydypjTsjgP65J77Lt`O`MPYg{! zYesilb-$vq3Kxa6Di|%H2AC`4D=*u@EZQ@oVMnDjltux!ETgRs+o$VtK>G%y0%?JV z#&UyX1^+mDu@&N-2$>Owa$ih==;Aeh9s)!~-A7oyjnSo15T)Rl-Fu<2oAc+v6+C+f zPNFCzpaIAjblCC`rOegOK>q!FL-of=dZVLPS?*m~80w zQ^Ef~#*%6Q3_pqUmIgQamk5|OJEuBRfKsU=Xi==iaq_Yk(Bxjx%5K*{rrGK0Uav6)3! zsN1dd_>dS|){Z{&l-!dWk|Z3d?~ygE-5U)6SAvtN94xi7xAmd8WY6MB6@a5`C{G7a zR^iaV^gPE?X~h!)5U6Ntk10XMsdYzk6p&KV3KlL1S>6}zfWj}AgLAu$PihFj$UqMc zhkf0#hwEtg?@`u@cNi2mm1?Cr4z{$+g;oR}NtB44ELH>bzLLQ zYod$)zl@o?JjlBg z5}h-fkIDkWl2eTBAwWoVxGe^MBOI-IZ2&pRosZDJ!Qzpe{#_ZMV-#&+F$ zVs}AARro{LBZN4nRlOxVH|mY10H5p)AqNX9@5lZo@KXxXl|X>&+2YEvfRyg6q4E&^ zFefh0^PNc5cb;$Bra3bDEo)v>`QymdRdo$GFOQU>_U}O5*6OSQ@ZM^TW^q@qPaOt0 z($60rMvjh0RMrZ#Eo*WK9nPR>MK4lM9-y>Ie|b(?d6gGIORnbF8@< zz145fwiQjqSB1*sZu~`2WMqn!gb*CNe``6UWxHm z46AFy^w!YNLf_SZ6I1kf77hKIrOSXW68i080J~1D^cCx(nVA7>_>LG|1yKA+_S`XW zGWXM+A!7EBx(=(6%ONl0>_W;z&ygD3+Hyrxa)INU&md}6G zl~YmK8*OwAPJm-gz4RPdxk~HCuCiL`=)}F^P*+pPmWM${_}Bo3yHZmcO~{J9`LYz? zGgiCxVCdiT>L7jFCTS!5ilK3>&wU6e-;6#91}2J<>|eWK$O{8?eC#ySIX@UNGbh|r zn-$q8yb)@H#YJ60-Q!StzPwqvAWG_K_#2aerF4AHc)tc9d=p)|e*(?5+(DuOK=_W# zy4-VzRo%5iBN7PutXUry&hW!WAFdap86ONBz|zQvFMn)gfRFIYPYEZxdZ-A?X2ee7 zueqZTLig_t0!eyRTLW(xi|-*uNNe~gZs8`{49K;7h8by_<5+Wx*<9J7O=6cAwZ8!- z=3?4W2+W7S=?_B6v4+g+M4?^EzDBUTJg%Jv47wmu0R~Mr6|?(vVdnx^o{Z9(JDr|A zxwytz4or(}e6o0&g`aQ2DZ%2*usLw*4P^to@q|-c=tG=GNq=ITuH|H&%tl}j^9O-x+QPUw9I;LX!3tk6vjqKmb)TBX!#iH6SjRoW3R!uG?W^sG7ySW~}TY1{xT zm@MfzrkS1nr;!UV*zBZ5?ykZDcdI@sa6<;wQ8mt8^BF%n2N*!cB0cU2x#zWh!t7$Z zkq^$o5SNgHNeXHoN?LUW`&yZz<>d1!RPf^;ea6qZ0@B^ovm9bxR(N6+-ozo+(Gs5I znwbS4r`-jYejU?;IZiv8dzS54a=^$=9o=CB@Qmf+87WogA8W=a9Gr`pgUG0xZLYlBGgw_}SmdltyzsAj47 ziC3QPyWrrpwXEm2RKS)N{0L`x`uOxE0!$H3RbS*#_1)*^gbla0$3nnn zY_0J)F33{BmzNI6d^^?(WyCIea`-gNb?klvl$&AUX)8EF=sGvb*#eR9w46C01zfz` zghsq^f7)w|co$(w_qmokmAhQnfT$z2r0ulW$%H@n?w?S(sMI7Xq0R2i*sRJNpR}QO zJMB8)J_|fNQo{A{6YesV6&C^bS=zxA3s>Jgi#F7M=3NfrVK26L6W{Kn81p9852HMT-ttmyu=-966QV7GeJ-X z73etK;CX``wYzKv67l{r;djim33lp{&@Rc-K?i#I87t-_>p&|is_;qWzwoKIanGG= zE4CX^GSwGpId@iegVzWjSRJtwMbXM=erd(M>e%zB_MXoop!-y63l`0uhKn*g>|>Gg zW6gw~b*o;gCkWe|?azBA00#Pkp@DZ=xagd`=ab&&;O6#~r3-LHnN6=EF5$#o-Y>@n z=$w|iM5b%deTXB^k}##INjk$>5$?YxwMiTOBkR+Wpuj=aC~NR7p~pW=qz&jkn@{T} zS9W6z69U=Kb^tMXgTLXDUFE34p{7ehO8I(V!JP~ZgMq0h$1(0<@y^G%qgbt{Lamp~ zz1TS#6d@pL%D{>?+3puJ%;@YX>2VAJw583Lt{-A$80o}!TmVF8_FO;IAeb&R>VNVb zQ}Wtjj+3dr&1yG=;C;6BN#Goi&>Xv`JIf%IZue3hq$Rnl)SgL&jjOQU2oILRHjUK~ ztL(dXPv#kxlY7W7HJT|uF1FFMfDFpIl@G@}F1DxZ?ooZ*)?F3V>~D?)j`oK4Yd!*~ z`j)!ESy6 z;=^t)88OXI;o;3EARHczuSVTBGPZAVAEdvi&&b*3-gJ-RjFwv6Je3GA;V=5?-nk7p z`9q8Ra~MFmrZ>#UFj_wSVG%ooZzQnfV$KFZ~7G*Z~*|`pfw1w_?F%8dl zHN@EmTZiL3UJ9%YFNN3IxF~Dxz4=I3nsME(l`6*lekvd6{;Qe5a}~{cd(J_i+u$s0 zH-}y~7lyKcH9{WYjA21EYKHuUH-IX3v3m2V5jU~M9TBb3!`r=JWuVlc|Bv6YzcAvQ z&`o_xEGytUlsFewOWe%|9Cs0qgaYg|h9BBu4MM3whNqK&P28N6To27E>#@D?Ae1E3 z&J7?9?w4`7UHp8t40nd_TSDUQjS;6s!t*N5ev$@w56#Y9Q5`UFWF#rU9yT#{?5>6w zEIu258tIpUNiA0P*dYqDRG4!dmNUSg_w1wU2R7h5Fg5A1bj(Ef?_Iks*p_jaY2uvV zlvzcOtU6%%RkAzrt#$M;=g|*Vx>11TMuy3ElA%6^UDK zfmout7iI;?TK>B;ZX8Knp&v^@lJtJEPADd6&BLI-TEBub?Kg#j)NUYo&NoH=cc@E)EbQ6~2vKL|s=ZQz|zdEtw z6#hjgV_-h8RGg;=n0x&laF!%J42a#X0aPQ6NUCo-$4BL9`ZA2U+|rp+1rKD!f{cvf zQ)cF8d;r}WcyV8Uw-`Wam2%hl4GWJ&K2Mxe@&gV9_R>^CZsN$PMou4$%U1Qpxy0mFO5ogKD6 z4(MrQp(N>=NNX{C9$@Ah6MFz@YiFZvABXdxX-+|T8)jRBJY2OsrBRMSbA7?$iwb{g zkn8Gc`Jg#otYb#NW46j1}W zihuj?;dCON;|0grE~<90V0b?azk~NFj5y!2D$dnQq^2~&*(~K@7fN{)$FSjPOk99{ z*J76{H&~Z6h*>)Tr4EGMLQC-SJ9O_Q3J*7dE`m8#h{v1kbOLZ=@h>Oa zM`+PHl*lkKGgCGn&-soKx^}`wRz7^z9`-dUH;D#1_)-8v9yxmb{3fya;+x6E1*(T==Y;$H2908=3 zwpnI79*Ax2DZTddb7pD25glKsxdCdpu1Z zAaW}>{Ti-~XWVhJ!nO#Hzu!~V6BGJ$4N%bFfvD;0&c&2{q3LO_(|2=0)}-Gx2TYgFU81D zoui^zwwcuZ5P+IBN$W%P8IEWiCgSJax{q*678ek58|R^f-viv`wRuN?F1M0&8a6UP z;YkdbjwI7d@dSeWSM;uH*gNcdy`PMJn=WBdfSAGEZZD-3`~ro4Ck9+aiFYG`qe&W+ zR4{;O{vnr{ClK24YrfqoA0A3Ns+;hMy27L1)Na4mUKFJ*Wm^{8W_RrHaTAbVGx@AV zI%>LP(ku|}3+x)6il7seAvy-GRC7~-9$mhcPdW(#{1QnA0hah&!{6)Q-^8lxwo7t>gr~eDqYzFa3EYp~rYxk<2_ybDBMi}5oaUA;KTtP%& z#SZY^rGNEV#$hLDEQf`~?Dr}%`Slu7*rZqR&e0o%p@Q@Lw#^fug!?pMTUN!X$$>Xg zW&>-W9#N5xvYmZ1kV$u6PgR>P@ro0`mcxC`k!t|O$49=MggG|&88ZQ!F0Ajw?@;oH zaNsG;=OBrF%6I$-(pJf`aDct_z{a^<&FF>CHcGI=_a!6yQ-h|5G%gkTipERY`NN$+ zf>*nE#8z}vTjlVE(PC}l3V#VAETWCL%!k##ya{A?@bhj80B!m1#=jgjLSuf^AOaDZ7z zK7j|?TvQ1gAd>zArzC-&@R~KyZ|WZSMOztyd-|EA?+Q5dIGV>16f>8qS~evn;OZIL zBfb~Wh!};68b2S7g#JH_y$M*%>-z`Hv2-ly(6N;o=Y){NuZ^~`cPvRlDmC^tm5}zC zL*zIlBsp3JNhKB9muZkn(xx(6M=H}kTBe%y`+mOT_xr!U>;GQYd;KrhrCFbOmixJ% z<^Fs=H>RDX@GGo1v()JddBW`1m@oW_ZcJymD{I1LShC8aCiEm9cBe899B!&-f=`5v zzL2gOEq7)rUcHYrPebRTn<>Zk)N(UfiwbV}uC zGKB@}+usNWXPmJQ~SJ0VDEGBP)nQ#TTJ&+;3`7 z4}VtSFOejSc4mE&hpH%RaQ&>8BjXNXqM?r9j@oebQ z3p{e?0FUFPAFmp#lNm;jT?BlK6MyEuG)h-_{ipSC6ZEZ=c0sT~PDxddV3HzV?SUh8 zPp?@2KJL54BYVWUNoOS-92#4$onHqCf~sX1PdQx0h7-os2*?P#yTuMSZ~IdmtR!P0 zqn+6{a)3nhnCpA0rRpIUA(Q|@7~{{iVU88$vv40j=9-RxP378Su?Ro#QUZ_?BVYDQ zD>O`9`4RWBM{5$jeNEh$e#5wEE0hc|LdkRWSmGSI;~v#RqMbrIw=TqI9Y;l4=lc1( zjONB49Dw>T@0~1%^1!>w@f2?JIDLCKw0N(~k+#Nr)S$Ygd6nU#w%_@P!P91`?sm8I@??8?)v@?+i|&);UL8T|p~w};p7gjQ z3NpG+1p%7Tl>3o{`$a?&JI%eVVf515l)3Ga>Mwtt9LCAK_4tYHADDKk9gY~>QKk1R z2qy7fWl1r(0X_4n$ODvrZqO7~_*j4IHCUn5J|`e>9POO^sMXblr=%wG3Jy(a=GRVD z*jFOm?(QqyegQ+AH)aXsP*a0DrkIV!m^T@1);xM7-_4pOiND4Rnf- z9E^(G_b)~1$cduK3{qAuU11*f42jF1U6)82zpDhD$0Fe7sD+d`3@(8yekbPrCX8`= zfEiZhO4a08B4XR#vTxwKm*lSXm2tks6a@1a{pBl%>xVJ*b{-7nG2Hi5Dw_~)MOykc zRYaX#|1*DC!stoA9wE~xAi^3inLbIuORWu)0*)a#$4!=|yrf0FD5o$ejRnC?n#W`# z@!6^}I;2aFPam~$4*u6_MI7>dyA7YSH@T$*W-R;$?b6yp__y>crn8~QcFV#9f@GEB zU1Y?cVN>x&lDTlk-7(~A^0P0AhRor@Lo4Uv+Evs~)Lk6j9K2U)HLmh}E=Rt>UT%7T z8E!5O^Rf`UX{aY=!PhvaxB?rJ)Ng>bL(fs z>Bg<4!fD1N86>uRF7!$O3vTen-B4tiX|9;p3i z9aS$*`q~uo(&^H(K>YCeZ~Wq(aGx03KwhhBNY9UDkl7}S90Q(i=jvYeU0HzU)eO&8P7j+6TLr02anZ)r%w^9W}?_2p%6dB(7-~#st9;3??k!EK$ut=vL#h= zsfkYMbW}}Z3nl;0MA|5KZ$2wrO)d@sg;>-O`hR30Ge~n_zq`XCWdNq3>QW}|x$q;) zguN)sQmz(ZF7LI=@;*8=D7Hv3eQ8Uo??7&ZY%DF592Kfu2t(%>1}A_(k3mVuk9Ai} z9Puje9v4BCfd59kKjlZCkxB*9etb2O#wIl~cFKPMK~MZJf+Yk2b%^)8vuH7dMuG-$ zV{Nj25*$bKrQf2~FzgPM%?=xmgM@_V4Y}kF1Cq&r9mXQS5x072dGEEPOtF8yT!4lq zm+m3vks3F|H@WbJ?$P66qiypPQq!P*LvyrLM5SoRewa&8I6I+B71o*goG^xmqOsbrs`|?sAgH(a=CN7~`N;pZQ4>h8l`it%|%7$H> z&pNI83^>%C#>K$W=0dbdZUaE{K3}->ja)e<4ZH3WEpKF&s4ExgLP-G=1}R|TE!~Um zpS@0pG(8R^yNIyfNVK$6aP7U6KzvvJnMY(J=+I!HA+Y7s}=Gp*cq7|FZ465Y)wR^kj# zHqer6U;#BAoyCi*wxle%1l$%dhMBk;bv_mb5Cw|*%zUEww8^57W{`PAN`E8MLl=0; zozDxZ1u38;&G_W5_2YHwA9Qm3b<69Fwy zzA)q~)Z7ThT)D@97C1Swnl3G~|LMe)d$!~!xwIDH>yCiw8bQhy(!J138GB!hQNrfK zCfbFhs8KS{lI&#if7y@6O7hBiQ8)C?>b8L>9Q2JQ5VB2CcMHzm^rikrijTDtTS#-2 zR{cUtgPt1ZYO<(&jDo2^7z509FydNg2O|M5`;-Y`^bFzfg);;d;%)V^iR6+Xo`#Py zuJ4kwciWe#bkkqE4ywg9x_?H_Oa`?FqDd%V%k zv%wrA7SEG^cr1J-dRd3fK1O;Fq5r`FA`(L}zf+QNluvc!yW-UXGtQ5m#25w=b|`}x z!80cZM9d*=mCJsD1xp*KI|F(QlvkYkF99MAe4+h2I(m;ImwXA6`v*^G*TFlh$OnQ% zQo@1>;tnj;a~YLM8au)G8$Y)BYo{dB#q=pK9C&sOVHDkuICR2#nLFej&m8hOkSz0e zf?*LqT;(RRTL_9=NGwMk6(=k^Ni8cv2AopVr!V&a+t*z`j?~0QhN^%)K{MqJg^|g= zg|b{38tAYWY%8>nCLdVrit*!<3>QGOx|3pze1Z@NQP(bMH!87e$2yIE5jZ;pfq2Xb2-KTK* zaB4!&P2E&kzWSyCy1P=m^+YrU#z(fAEQSgfL_oqEPcqjq;^Fjy$SxH#<-%$>I-wSTFetr2-q(&hD%7$DU#28Uom?{Dbuw`~U4!l#u1m)Od2aD<#yO|4WV}WV?3r@C#MznH$WO-aQs`W z#^~Euu)ibS2?LYj-%@o24AMk>iB$a3pv(b7=qc|6unF+GKt6<)@)eWzP}D6=Rp>N9 z2`6@U83MKa=AphDHqE&NBV96_c|q%gzr0-pw2+Ut2Je<@_7KzLBRqkeG{kiBe@jyH zO3Dryj$;uA+;G9rP-To*uJ-jx+&MtOk_pIV&hy^~2uv(;%ki$1(Jl-7l;yl#zLtlH zNfAcM7=!eW0|eX?``2%2EKj!4jzF``Xe$kr6^!yOxzFY+VI{-BfJHI#N^`Ef$4%w6 zESLA|B)M=NU#>sMgkC*%gz1^^jUeGA^7% z0D-&9(1P4Iqym>TlA{XmA=82CR{)U)NLVHB4%u%~?k{ru;8{SBv1n7}qDrMwWz6p} z0ALqI{Uz2UeZiQeygf{^(SS%`nExf8mhxRE4Qt|yF{(C+fsmT80ni;y`&w$>DYTMN z<~om=PM9z)^uLHqyZ%FD;#mD}BGdm#`)J*?A3Uc1Xt&dII~SH(AI^FF)85&a@4WnT z@gwKlOBXNl_HXde-_ZT#;P0z82S0Rq^=gm8rS2Kd3kGcF9=W$#`=a&b`yEIa5&(j+`?^(H$zy7qDCHr$h`68XR7hJ>re_Y+?$<^GD*6wjl61!~rid!9@ zLbfCf(kJqSXQj6$RVt;?I=*;}F>k-IQ{!m6o!K!-XIJBr4auVyr#U9wi@z{8+$h?PO9{Rsju29>EoLPBS-W0ddIXbHFEY|{Tq>2uRh7K zu}l_39J@I1_|TBE)r&tBu6`H$d+XdX z4!v9BMQ|7fr<-MoYN1@;$Dx;oCAqS96M0uSI%j_2$sl|&zzifd%^H`LixoQl9P=z7 zw#@P+Bx(V~%dA(A1wzSc#a&aiueLVMoH+Jv|Bf{-yA(|sNwa*M%sl_Bm8def{V;NiF-I1bdY0Ea}>(Hv4V3^{#4SJaIzI<}qbYn{3@Sk6=NE%qI6YbI%7} zypPjNx2jp5E3_DxWqR_p)cgL##)jG3={+Z=WHL;S*dC5ipZkCruCXze_*L2ai|8!< zCMxh_gsOV1S(7WrJ_Q)v+jVaL9=d*WnmCO5TU%zW^QMJRmQg_7-9^S7T zUeaII;jL-7d_RvB>++|g=$g@B`QwX2j{E1#6!8}u@n_YwwSGFMoDpE~>*4Pk41?E= z=^m{}FW1ZQ$%>mc^glz=`KMS(P%Ij)8qeBzuCVFNoJ87DtCclw1q~O)+U7f+KUr+Q zQP6Vm#pqTn;Ri%Hek=v4A&^^B_J`=Qu4tXgUTiczx-*Uh)G>?^%`x>>%}#p?}mBM=ZdB{vfoV{V|sF^$9R-|C#yovJ z+Uu*BkR&@z_m%#x(99@wAf8p)E_abS=T7bFmt315m5Ar=qpDl|v8(dbiC5Cj@}Qp#zbom4xbgL%=t2wLP*#Z+!n57 z0&_E)`A2o8lJnuyt6eVcuF?H1ZRXt5M2h>InQvFm7>ONN{wnWV?@~YJt~1$Z{@QKU z8&x&iuh+TRt#MOP&e@}J7xNt5$JZ~>S*P75ds}tx>ph!Y&rkLSPMq3K-zcdP$)}+L zISn!9VKblyy3?DyqnFAf{;u3W6_E%;UdL>{(-Fn z-9_5I{hznZ8OidQznJXvML+s{))-Q!pEngd>A5{#8RdUtZ;vvIQc?fKBg#j+T6Mnu zs|PHnivx*%M$U#&D>fz^n!cvcC3S0SUibuM`^p{F3#&J8R3lze){Z8J8a2y~-kXrT zY~(keGjq zC$JPe7aT6|4ZZk#6|?8?S*gYQNj&pMvkK_B#9{>^opEFHp?w4;V3yABH4=|`&TMJL zS=sKh7CDi+_J4XXEjk9ieA^;EzVB!=o$o!RSigT)HQVRjlmq7J-fKP`d%k$L-|GqO zYIn5~30}8DL`Us>=ffF#kCb;#-Ci9#s5|jM=0MVeZ#73AOm5FUaJ$q`wofUQ%2VjQ z$k7?2yx)is5F{&4u1vFwTKPK4rRtaVt8qrnQMWe^M5~;971SFvW2D6W?gQh&yBG7S z>MmEc_s6yIM8Vmu&)29kKF&YahnKXSo+qg?|J3U)5&|y%c z^xX4;*Xq+8Jqki4A1isQ#^(|$FOJq6RCc_@zAyRsbd#DRz5C@v$MWQ*cUz~g@^vW+ zRXO-6$gL|zW!m`Vfu!j@y)O;yAL#2vHoN{ZFs#G(Ogthv>e&2~Rur^){DQ^5)&=^> z=JmW1@Fdm#Uj%LsW;HWROYeailD${r5#?(e1 zkDb-R9@|MHqPzDV1epao_GRR5Rj*o<5>n55V_n3ndtp_+)MWXyhhCahi}Q-BE*B1Y zS+n*K>~Gc^O+M}4XiBV$J#kT1RXf?seuZCP$rY7m(*sW)q!NQ_M>~6hRigjx8VcyQ zCJj)VskbH-G6tpd*ME^t;&X3KB3EwP&M(}(H;&~&CF8+=ZN@AnOqFlKCVgrB-z&TJ}->>VJKtx>LEsu*0(B zY)53HMj5Rvp^Wd)^L%WZWHR-&<@fODwM~@%uu*eyoNSZsmLD%Fe}6nG73lv8Pqu{KhSz_M&&~;oKgQ=P{eO?o|3z;@?LVSQO_m>9+V#fQ&CjgHY`hn;?Y_GA3&$w3ZJ?ei&5<7#F5JRgaYJX|5B0BMZX zRcwh_yr^|Fq0z62(qjNo3TNrQD|TXQcX!6KEXEAM`@E#lPY|4FrsWyB0OzwIGpr{; z)Hs@8H}F@_o^E<#>o-VRFkMyaExk#thnPCcOhHcqlEfzb9Wee!Qf6qXCKqQYA%SaqOPu(}RQEc7fE3j5OBRfOv8-pA}wxe`kR5ZI;slHW|G!QeI zutS>f(mk-U-!k(B{i(xC>BGIWv7Lqj?}T&wf`Kcp%Jr54QX8WLb)w%$+RN~a7|8l0 zg=mH6s+Lai20>_xQhiOgEU6WBGMX%~4uTd%QdLZRlqkNQQ(25qf9flN*DSr`X?9<=#EePmirvGaH>n2`^j?Ep2N3 zi@ntP)+BtCt9Eywl+GIG(9#OR5*nwpP(MYp3mAP5X6=?9bRV0zQjp6&XXrS#**gl7 z6Atn8r^ldqkpdBrxX}b72wbps^d#h6>p`=dC7wPhQq@G34Suzk-YvV6L9LIB5IwA9 z7Hy_}inF2C-x(ejkNwjVgkr++lvJ=-(IDHyKO-9&-YNKsL79#=d=QpP4+}mi3GNI> zN|Rz!C~hBRPKjqz=ue?mQg6MFdcaA#rz%2}6#F1Qa$p}C8VMN;QVhg8h5l?k!;c>I zAl3~%H~wWM-%=2Lijl}ZOO6+tgD%|)9T#+~=`z&a2hRiWH(i<}+kp-}F1EIC6kAJO z#n$n%mgIAkl`Ts9ds^-ctaoKR)r4743(#s!e0z()TG~zOx%68KenmU+%@_>6{~s{7 z;!#3JHc?}TCuD>4ZT@S*S^Q_hb@KoBg!{kAY)sVu;Sf!meF7^ul+wW{uk_NEvAw@; zwMyQW_>`ah^nlgYx!Re3?`?OQpLwlOe@F7R{>B|z+qUa3-DVXqdG=M)mnXK zvfvv~awBOAazSV8YIlr)oJOJa81x0|C~X#irxdxhf|^%3UwM#KgK z^t9*C`Z%pALMCnu*MAcuN7)n`RYy{JK_?=Xr2Ic=*o7N?&$|JL9%Y%@17l0sTR0g_ z-PWs)rtXh3Kxlj{6^#D)LCfH6;nkM>ZDW1c>GvDhJ3&Et?S;!PEei%`Del>-#rt`{ zRD?z!1X#*dDy#tf;X>+O1fG*Z0}!{59OFU;qlL8wF%u10SQ*KhF{^kbr4&h!SoX^fp^&AQ=uv{a3?V@^hv>+MFRN5Ye$d?A4J*Z& z8|zmi`M6^5=r;60UGsJj`TJWav%(3--bMY5NJkv&i9kh9%lHX0BWCS8kQB%@JF zfueAu_9Le0b-Z*FAiXX<5AGpp@Gj3!#J1!ni`c*s(Zw71teMu_U#WZIJDJr)&j?@CBY2?G(dV&;t;@cpa#VH-#Q zz@7WxW(FUsegA+NqR)DXG~%wu1t8vzj(V-YxK0df1vuZ*8*=c1)rP>jxJWWH_t`e2 zS)_a_1{335?q9v^tS{lydPD#`%!$d7xds0&O72Da*O7!gS#9FR^WM^g(X9M>0n>{%2-u5hAcVEV zsV~K(-~~8tMv~v;J9Y@Cb{-#J0y_6PJB``EK!5C%C*@K9oH9+6kehba zvnaq0gYMXXO;1Y z9qoJ4lVQ*&4hX8iYB(lsQ-;NCl=9&sME$Z#fNA`BCE#C%tJ@B`5u(4H1*84}TYdy=qaDa2* zg!O^IbnQDZrB=*>L{T&p`TdO%-6z${s?1m=L7YSuVat+FF#RZ3_*z(?2Z1UO;20+w31rUbv7SURYpx0k=>`g zauB%z1pL>ON6e6u>bW2#?tg6zbf;scBjh2{w}*|vVjP?*HbH!;NluC{^dBaPD`%;{ zR2gP2RLkCnSx2yr%^>HS?N&BSM(Nxd&~z#8CcxGTcC;bo#psR*^Y>`5fd>QB_B`Vt z<;7%!eUE8HgN$cy{Ok(c{Q9h)$r3HDl<^`%3>Z?aA>m`BU0zY0eRvOqC(0xHaxIV$vFHh6<2@eKaUf?{ljzqmO-fo-RF{FE5fhr$E@T_TdBh>E zA-ra-M7BB9bTlHG`6;h6A`m{+kzxcTj+GJ$h`+2|Z`YF(@1AHWSz=QQSIa0JrnqmrykS0iF~dER9On@CBxo==SQn72^T5(&Fq(-`l^B(szxKny zd`gW*%3zQBHb`xFrg=Ug{fsQnUzWzIwK3&#POh^&k916wwVTYChKb#Vht*@*ZYk83 z*TdfKU1g#n9+Ljqu5r2tS%wyuA>rRi-k+BHVbZnqNwHRXj{QbLHv5vkKLztV-lvt_ z5zcD7{%3InQmBgyYLN@JHjVS$4v7j=W`wB$YShJzw*yA~Mzw z?1D+}{^tY&Q6pz9fg$vC`ziyo*H{Y| zeOTRkWoOaOKYa=TT#~vxgxw9jZ2`K%UFX26mSvUfPu*tc&t?b8EL-YzSC+izv+J6k z)!AI>7{(;d{4mcNPRk^-<``0(>Q~H1*j}9APExW1hW8;cSEfyF8~SgCxe#ni_4RA9 zXx=qs02*Ig$Op71f5(m$u$J(|Rt#oNbM8fpBVTyl$F`3a;V@Ld zs%xzGNA=Df;G}^7r@s|isYIR1MlL>s z-0e!_`c0qI`qku^%%O23C^R>BKmSWe z(p~)`O;}paXX~9A?waD%F-CI@_-N>VvoB$H@5S9k2s{sb6x&=!GR0Q^6)TiGgf=R@ zKS|aw++T8k^)ofh=r&b&*9&n4}!47odd;CRZBneu$vSLh?=U+f^RLT8TtAGuc zX_sWwpusYRZv6zgvK)@~dVzn>EjWdZT8Yl(P6S!|n^H%~tfp2mXzcL$rK2R7Z-)Ds zKj?uef|PiOil_3K$ugb^pCXX3% zzF|0ZT#US{2i`3tGmTmu%a=$pZ}e3*fKc0V%UTur+E{b5Es8PlJ1wg=ut!JV#%W+_ zX7xqyMkT|06=Cifk4@dc_|+b3-3m7mc2@u`ooLBAETZQ#`;LIMD^l2qXu)f3|MPJ4k(aSdM|Gra_E}8-+un?e2ta5b>Vgr!`~WGiYr)S8>IYt%Z8#psRze=D$lh^>wqo@?jrAy1Hv|J0oDd?&0eusfl8q6`#L z?P)<-bSv+0a?9zDS<_>JB9YZ`|v`#b#VLmEf<4w_<@j{F)vAEd~6`Mnp`F`s<$GI;Sxt-;bk z>Ebpn`lr{Xx7r$|=QOyW7<&fOQ|j*`7rx!6iku1^!q8n#X}$(YFnS20&1si?@J{P#kDE7 zBk(cu{a(tsy&IJ59sZwdkyBB#Dl-X4r=`DhPyNQF>fd%8%*Wo=AjkDN^6>_UByJX+ zIGdj6erN;#t#a?n=Xo%gKRnpk#XL7x4K2z#Iud`oHW>|vYJ#Bsm7#ifg*ZuTtrrt% zu*20(t+*}C*wW>;8Cxfh6E-XB1p`+jpLmxayhgtt;4C~sP8^ATFitd8^;L z50hFE?N@BqQ8O;lzIzTyt=m6+pNRXA+SY$o@|9E@n{^hmd$+*N(C8z!S zacn1-b+Ze3o~zpCnja_XwZ`(sdM@bLORG*M=ObRJ_BdsV@BJ-*#n4V%=2LKaV^; z^eqg?yQ=2!&{A=xOMFXQu^6a4?jk#o;#?N) zWwe^7ebJ8cVcH@@_E zjLma%vyksQQk(JDTQA601{XTuV#TGK*H1!h&V7Mq%FSb58X&8mX_@$v=4OA$5FDu& zf?=H5Z6rRpW-z^)Z}WgD`dBH#Cb)Ug(6iY{qFHb^5|>!b9`3==fzWQ5Q3x%MXzsv% zlvdQ6h24xvc>wMbvL5V(MBK4j1l^f=UrQ8mXg_4j#_4Zt{GIBf(#Itg_eYnE)H>Ou z+F(2F-rfMNk4yKtUJq|Sy7QOodA`!?2FLk6LxMR^48FE17SOl3ML~*@t(SSjo8KnT zwd1_rsHO6*S4nUP`NylAgT}@JO)cP!RV|Nwh4zST-vcHT4^>$;PWDnRK4S^7aVxPF`7mQW>Qb%0ZEK)VWSQ!kA zE)oiAjpkip;%?79bj1pGtes_G7`A86RO1L$?_Z_r$p1cq0!2a`Vqo>O%o@LPd zsqT?6C+cHs+->NP~)Ky&nwGG8f0~D6+e3NMP{9;Hal`0ldj~2Kf7G z>9s)I=Y5J;1R1#XpU>%tlK7{pH~>CIZ2KBXhcW{5Br^cH_srOZr%A=Z_+8!Q5V~`} z5`^ROzuKI^7kPWb2I3WsA#bO8hGQGDu*@BJRyXgrw-3UrUJcz2vPPk`n%QkWQ{`%e z*1fI-OP$f~>(IsNNbr?T)7Mrf8c||}Q86|O*Bd|LO6KThFYMagzkCA*&U+VY4RVa8 zc5Y>W+L)fOV*wnv|mbhUe?Y4?yhwd79jMPcpD!Xoiencmkc$851F7Q~L>PUzU7KFIlU9(CxVyp&rI z$e|sIP$M~A?0fr3U7?>nXMA9q5iXVx9Q4|ly+z2YoB3?^8g(cy1n|~Ch{Df45@&id zW(ICE*ZL3Zqcq92PIwH}Yho}kXBD3L2{%msm$h*R3Blq^Rp#QrPlix_yhhpohG$;! z>hCc+@NeC9@3v4w?-hOlpRT|52uhhG1z_2Top7YjmZhg&^G=FgYo8%0=lD{__5_rXzRN`Jn6mv zLMg4Z#{WRe>t0@FVM}rH*G_@C%OU&W2mcavTbI^AbgfEZ%dXj`DDy2}3zj&k#W)YR z!N<0*G|*tH7&cT)QZ^?fHFXHWji&B4dSOo|9;GJP_r1Wb)3jXYyx9^q!-{+3`p-gH zl2?k2-nW#X+clYY`)bYjXOf`nHz>PGii%Fsm|qHKQE--u?mYV47%QYZCF>8!gvN2d zi=a}a?^Qe*EJ$1bJ_`Oc-M-kXtDhQ?>=tg?s7aU_phL3{T_%V}+O5q$aVd!loz>DQ z7?@V}koa;^XqWu}RJZzrvj?S{d%L8?97wHs4G&7U^x9@nA&8VcxR>usF1`BQ?Xs6P z;^Q3OK%(A^k<1jyc3xw=bT5@eoP2eyYA-Ie9*a_ONS)mhjNH=h70HGmk>04H{&NKi zO>vsE>&OJ||IJhT^6=&$H|2Sl(1#rKw+U)Bx#n%WiT%SXGaIj|Z?>1T?3V;?sQ9zb zhl`aWDW?PEnYX1%gQAHk{VW?mbB)a0{V>@2ftNto(G55O6+G@!X>X@Ep`?C*y8Df! zJN%*6Suc9mS=zwAAReB^XaH2R;!n-FFtw07G9%pMJgVq+fq5?+<)4-%wTEX{0lCh( zS?DN~WyCI=k%uENcPJ$vqndiRl{-l~vOWL)xW6;=%G;Q&RBhSN&S)LisgFZ;!z8_Y zeBc)gh$dHfoTiC5)2OLE1#8J$vF{MXx^=zZ+rTTvC%fXbd}#Zw62TVn<8NF90oLcH zf0xkgo8v2ka3r3(#4HBO>>Ob%ZWF)8#A{)c*RID*E4^|eA0Y)%rX6nX|5^7H7bl)I zV?*@6wufq!U$ZG!?+@=9{f$g&FC9Hm%r%6v_Vm;2%l9YFuiTI7y*SW_Be|95p&5|V z>kkNnHXmgj)NS(o4MiXv>ZW?)2H#Uw7lPSrW2Vi(Y#yvNCaY(&!wgbA9>0WDh25W+ zAUg=QjlMuy8JJtYZ9&jP>D6!?ak7zCPv(#==n-X&-6%PE!DMhCmC z))9@-$5!-XGHX>83$EUuI9Lwty{S&7#z?(v^}P4MX@;}S^!{Pi)y z0Vm}hSIlsKtyjp#Rhr;xJ94=?y)#B|D#$v26^`vW1*eu_aV|Z}c*WTqmF~604Tf^_ zo_ibq~7@~`hu;JAXfoBdtmE6Y7 z7E6y)9oxRf^4jXK9b{?a>y0Ks+F&1Zdsjl+W$|}HA=990q!wyzD)~?ZPd&*&9$i78 zhXVpys*a9@vF{(3#4nwtD(Y_k-rFOojxMAo4sX78V_}bEdBvYwZSm5V@w@o{`?I<0 zsCH59ZXiI%^)#+VS<8r22rirpqGMNQ__lsJ8oIaC$W=B{6PJc7o81Xj$w#2A?fJ(H zazcD4yvU?vzE((X=b5{Yx0j6zt=z7u01aAa-yU60RacddlJoY)r7DpXMPd(HKj%mec!NA$w2z*Rh@R-}$*x zDpnqQjnaxg@4ZLWzTc|M0gWnsLpW| z4mk*0^sUAyiOC;rdSsIXda{izj0c6I`Ks8F9=c~k*F<}7wqoa)Zk<{tb_mJplDdG4 zulpd_Nga{dSff31F8)B#XYQlW-Ckv-VM*SX>WgLbQj!CG`aEm=RVv@&Nm{>%6ab&! zsQ0=cQ;C1#XklaD47UywMRzNfQio)w>(q?*r3D$U+s)o`Y*Y(R^jm`YD)RTh<*@ml zcuP`3Y*)TMR$pb^(TUihXWBhYW$tL-w1u4x3fK3~=S3J5n>HJO>W^l|EK3%uj+scfB2oulCof80EVBH68w>G0nz7Mi91Bu4(os$L$enyREy9n;;+8d}L zx;ez=nd3y7H0ZY+8%m3kGVwpl^ed|x|8ndv>hAS2%V=<$(doA)W9x<9P7e3M$qoIX zoiONtxqXNp)9O;!Rw{+c0$Omd9N^dnq4LPMy>O!mJ?5U+v8gCEl3Lq^orCpg?{iP- zFTyN?04s?rgf(r0XT7H;oZL{~K*P4uhZTVp$Si*VvHY${Tt7sk8!TTiw)OtK@&aM` zOt8;iN$iwS7{VkV2{=Tnlx4OZqg_YzWaRGX1q8G-dG^pvex@@I%#8O1bO-?1 zDT#Y1eHPY6g%$14gJ|gIN017;0TTykR=SIy{R+{m zU{#sYSY$@qB-wVdG{={Kd6;_h*8pg6tx4QrlA&&S39%ZR%$ML>>Q&mBCkbm625$|C z;~rLcyxeTY)XUKMbiPEY>^gPazD}yFa!7m(jLML)#_M9u#;(g--7py0jAD{;$u|KB z({%KAyf0cAafno%CB8=XL%~+T&1UrmYDKE)6D3jiwXL1Y%BTrX7>+CHt)Hga1Zi0n zGTePRexSyvm};#@Fo1qc$i=DVBt;Q>RLy_&Yv6w2eMLmtm9+5?9KuXY;Sn z?>mgLK-ifd9y?Bk*=l#+y+eV(!oYrEU{hTPL+^LwR`5S_F;M32+HVs_M{1WRh7fBP zTpCRcgQXaJ8(SwN=4Xs4XA9p}DTf&Jo*P^y%o^QVVc{#=Y(ZRlKQ4_hSU#p|LezxV zm|fvf8@pCVe3zKJg%M|8NQ7H^cNO?JjJmZn%nGE|iGEiN!ZnuHGOtM>x{cENa?-mJ zY!&!Z9x)4-vnJpeEuyT>+)EF1uTCf0Wa$QydIqVw-IBUwfa=!oB~U;rinI|4q|jpw zj4g59KSNlAjmElK{TAeRZ>7!C$5QUrTZ!Ya&hPnOM3xo=i;gR&;DMk(3%ZGWj?Y&_poI!CvjM z&ik}*9`nAe$r`ADU=RI8(0W%lwIn@ZhL;m&t!dUi;AVzTrGqRqAl}TtiO`mwN2+Lu z!f#>w!Ds9}I|s^#i*&6DQ?vsmi-BCJWfTqCA}L5@IaZgV;4AL1!BoaGoCkv}mpC$> zc*nZ#!OV#HI3vxx)_(?1@|!qmkYCK|;HWL3zlHR6rU+@2-f{iO34~JEJD^Hz24wf0}$O( zW{(SR-IvwoLw-_GbWDLxuM26J@v17U(b>~UB1z0lV_gz^+VM8dz&m+5`--c=?D*|r zgTos7yJK6OaB5|7wR2jX(_2#?r7|;43)df_CUsNWVsPr**fjsEFx{Z8N< zD6h&+{B$yd>_OH-U)eKnruJpL#+RP-mF)@*cmJJ)MQJ-;98RlvdOrzBrfAlt7{q0% zJ^J12vvSm4Tn|i&Nu||#@62FhCnlEooaN&_?|v22=ruEE13*I%T>qDZx)K|^qmI85ceNQNwKcR8{!gk5%v7i?O?vu zyI}6<>9Q@%QRZ{E%00MwCOn*O;N*d9IQLE?u{P$^*NuhbUkAEIc7+t7=Sf7zi%3krc!~p&vl+0RnZPT#6 zEzxUut|A>7U`)aO{hw09_dJ`Btmm%z@5u`C!)Uk~(;H&j0dA$bQXLf6JiRP^%wJbF zf^(IfTt04q1I8}=gw~ejTVOnH6q_#B5@-7ORQ!XOK(6OIz&k+gT`;26*-9vrkEz(G zfvnujs0Nughj;+~B6zfTJdJ#pfr}aNNTtBMKN<_*z!^vgY znfSFC4VIl?sM7b~jdocS$-b2uf)yNw*#&+q#65TtdJge~q~8+Yw&O#psPNe62B^JP zW;|q`tTb_)NYYFV<&5C$@~|{~R`rMsFHv#F54xzXoP&$|FFb}K1Gu7Paz>~!$p{wH z4jq84eKK)^z{;ZZU#f`ADK^}aVFudfv`=1D+^ga{*v+F2z$u_wP>e&XNXjt5z=0IV|j>})d~RBKR-oTzx>NV0cJ`P@u=m<}%P zf8Gh>D!8)p=eLdV!7yd6975NihD;>X!ABy=9wP`+AG?|0%6X+#7=3V>apB;)_1Pqn zRLw9Z-N@CMPHpu+=}u`;%Ab+xs2@aqN)%-MOT>?GJmo#7K3q4SaVPl{Zi zKubPs5Q_tweihk30sy1{tEgY(4M%RKP8op!B{>oWq#1$F3qrELWMyY71F~ZB$Ium_ znbPsyG<7x_LXp#y`EuU2RL;nqCl|bM*96q0(t)wH(mqNk8pr-K>+s3q>GwziIbSm^ zo9wY{2n6*Vv&Rku^khvrdH09X0S+nX@DTZ+97pH362&C8%_vc}M_yB01b!x%xG`-O zQ`L~-sm>McfDFo1(pJ(g%SpZ9?urR5Ie8u7EEETM1^f(WOCgC@RPGqtyg6#&qV@8x z(6B=!$I+3jl~``!SXwb2zhZYSW_NHnb@-|)V;SCN{NS?7c9G_l35e{I1L9RkWTn9y z@y!xLfC}>dRo)U2MXS^d=of69NByDdP z`;VkHB`C3-Y<9R>nwIsz@2p^aKjv?44&AL-#yFIQ(imFu9>a|(G!@dI^9OrfRjGtB z35byUSY7@FX7pLiZoMOIykp*e^1YuMx^M};#3C+Z1fY?FFS)fvEk!gR4T~cChtW)s z>~YqAJJq*9X9pD3Siw6^JC$2WDFBVb;$k& z4`QicaYHxa0lIHBIa<{D0GJ#xRFv1b7Vt}WAd3!?m3^l|>$J4)q$KuQZ$j3q;cI#H zl^7>Mk7zsDQflUr_{OKbxECbq1>vYV`Fbk^LLLvicKXjNN$BZt+)liIrV_e_asP$c zEb(~8l#R6aoc4u~k}2)wlT2(!&jfjgZ@>g)C~!y-fl`lf`QQ2cyKKfo^lAD*p?C(~ zs4`u`r;;XjHyP>+D`@KDKqMb4JLktJs{Y2S3tTBC=S_X~*D9JTOBSgN%*NIn#%m#o zRjh;DQ)wV664@}CFTh@|Fdy7|f6eA+!Pv`Hzbiq3+D$-!o(vS%0J+2GsSdjskhNQe`pPbb)0&Uy(Wg*dL;*4K<%)TXEXDIWIhP50x!OURy*8G5k%942 zUP{I3*!zh7NM>u;$c1efbVK1FmRN}HP*nV1zUBbcwCbMfDy$^|gykuO!75eKKFb$u z9|Stko70DF&^u|Cw*jN%)9wz#N+RITqr)DeK9&z@E5>9v6KAg8^WOJin91w=f)R`sn7_wnIOgw3C2`CrPUrb6xu3rI%v1-I>odW%9q0`p z`yHq5kw3Zf#$=6#&x_S6Lf}A+SLLTX)eB^70O|g({E6@KO-Tln_Xcw3teZbZS z=4Vu1@(3*@n3$(G)EcIc^+2KvU=%;#$`W3bjLxHtlRp5Y_~_A({(B>Vu`qOQ>5LIt z;qB$u<&ql4a!C!1YEqEN9?EuCymRHMBV!w>p(cFh1+s3XWen1P4iX9QK@0@-QNwY< z8o$ZCNOvD}KQ={fst4qYFV-8>0*Z>z{E`0-4+|KJ7zQ&1e~|km5i^(+-jMQ< zUlRg3%Kqm&)rx6zYRxT*S z{Jv$>Iw6R0?g;>osKf5uAu%bNWb-SD`Gy3_Ys?Lc0dJ^ex`;Lzt1C4YT$jQhCN+y0 z)|HlS{VJC@N*E*pDBf)Y+zWW(-eCQv6V;Rw{baw%2)RZIb(-An8UP{B-EJuq=%FhJ zHDMMirXyD(A$~g()kiM1X8_>Xz4qzba$XhLLjl_mkINdF-N}S}4#ru&*vuKM-b-)F*ZOy9b7!>Ym!4Ud*zoSe8L)XL=Wk?AiArcB@HHBamJc^Bqw zT)gy|=i&$BKTY1_cz3~q#W$N<&W^T5{rQnctYS*OG*_N8$~-$h)J`;4RQwapGieBz zwtaHIjUDAL=NuVuQCfCoMDy8}&6Q`Pd-=ljExY&Y{c^6wH*!C%Wj61h%j(jlv*)GE z?;B12S<7oEe75@af%nRNAA_UA*)(^J%*=1-Yv zmgw`aFd$pOx_$G+;GyXkQ;qH4^|X1Pdf)TqOi;}pgIZQ@=rgL;FV)YueN@q_kuc=7 zRyZlEHmDB#aE6W>T8T~AuhRk#6*bnVU$=`qbK}gwqdx=+jpJ)R*e-3jZSHXX`-F+s zMX5vo4|DGs*L1f1jgDnxP!Sas1tE@I5s@x6mH|{sP*4N}R1~B}1*9h`Dx*?FL{NmN zh;#!YASFaZ2tCp}Q7NGZNJ2>c-4*7X`<#33^W4w><$YmdLb9{=YJ2as*ZQuDxn8et z(}X2Y^Xq~WeLlI~{mbF8v*+i4ot>@poZQnkdZI7vblOd=Yk?g`20=bC5>}1LSLBEN z4}MhaQR>Kcx`=KNC5n!s5||z%(!6cG+%3CD0zNw`iyp3$k80XzNwd6Id2LQpv7sS- zD7z`xa=V0SZ{B!ETF6jaI_CG)YH@1>T6EQ>pRx{~SNvSoAEnv{W>C0n>MpaQmz(H% zzdDu1zinu$cxT8u6pG^qRcK8$yr-jHpP;I{sJrIl@{v)At2|1T;lF-=f}5eWvb?-k z-E)L^{QR(gids@usJ%nNhmwc+iXq3ghZjZ8znM;$`09J~_oM8lS$(w6*}T8bMPhF{ zpdu%JI(g4pMte_B9BH33kgPNfl58^Xt$Luh_gA@ArLB`{*YS>2|C<*6Id4y(Tss(- zQU5vjBUg3M?3~$9-$O1DKXm5K3q;X9#YWrrxW?t3zA2gIbXse?;vG{b%Yi=P+xp&c zyu?fT>nRP~&#pr~c_)vA4sMf-Z5`}f7js}Z`)2a`^ze!4NC$_(KTYIizj^mkGi}aQ z=@>jVC%*D%Cfu_ncjH-i#!x=EK*a>^;3d?@B!c_I?vhs{a|P<%)|G?nZ3)HA;kBo; z{wR@V%&c@JX~auCh=^p)F7S=UlXP0XQZ)0HdnWKdE=y4`xsbleH||gZ@=zjWndU)j zs{i$ipL4#2S4hZ9mJl3B=Z|?s=f2_1S!l_L-iE*8WpDB5z|NzD7kP9_Ag+?E9k;;y z9Yt;ub&XJwUS5j-M!Z5>_Lk)PL{q-@;R!3f-)|m1G}l!ZxF$lkZB-%NDElSuY`rgS&^Q)4xjW4)>WDBow^b_ShsZ zbHSaEf8P0c=uZQ+CiJdrB75S;k`U4ntqE;@wBaG4bCU{nnL0kiP};VMnp=ByX=i8Q zz>hEK*YhMQyS;Yl2bmCrxU9#`Ke(TuVU(QqJ`EZ}P z?s7%?LsNzH%=mS_q3xR`Cz#1sFcwp$G2;rn&$)%OUXo{j9=%&0ePPyqK0*7d(VF;z zXERqS%;YoIt)XA3S|Y8ZF(KO}k&nE`f0q~$yyS)%*4)DFe(e3aKIhxR4$bu)%8jyz z&ZCerizmS?gRjbxCVqzc?7F$x?d}I9@8P__H}`4{guh#JX#u%7vk-z~C;las+k8vQ zth_VsH5a+3bl4`fzP~HxtXyDf6Y7ehl41HKi8E#Ma&?@gBdRzi8}D z#|xSHA6g3(KM);?&2nqk95hP~r9QZn=y!1SK(XC1VGQGF!Gab+Xe4>GGnD`QUhTNY z^0vscp4S}|>^mnf&s+c8?bbZVzKUo4e0cxU3wh^9nnK4VmG(x(3LUb}~tDlAr) z*DOOJbK0=R_(ONH>G_A){nC1qx5?cz*E3%+f8vbRb8Ftl-iw7qxI_;}_hfVlCyN6+eh24{tXAfpO>OFovp{Dn{z9TzRTAH)f^Z26ETh@vm5zJjU z#0;nZsyIMTE5>VasE4&jMBQZ~Bb1=Xi99h((GPL#Kh8TOY+rfTkw)CR_Kz`kc z`PcRd!G|^0rCE|e_&129WEd&Ov#CCKy)TOA))M9-bU~UyG7VfK)GIY6rNS_QYr8F1 zdW0X(6@h(nq(?+jp=)3AF+D4MkgbB~GTg~2{hhPy6QmHb1XaK2QT~ATnQaq9z)$jf zL8`dp-YOX#8gxfG?BmM2INEXMMEA_y#)ET3(L(`;O44&~kKHhORoO&4Ib=;Su# zvem}DsX2H5BWr?nrAw33SN0(aJ-frv(Fe!q=<>O~{lgtgC zy*a_1HF!$;M3QJ_&M7qYKK9%knzwzvJme9J8z1R=$(MShNviVK1p8j%);22_VVQ~x zVvhXyM`?N6>R@?BpY8r^sIPYBYpZmG-<#y(`}v|kZFwDo6qTc$jiKj1c4A~L{T@2) z`Risjg&mV9$rJ4VQwQa~|MiCh^z7bE!8MtodrSDY=cc;E}1v{Ox_aP;0RHiA&(|B8!gF)91VeJjamIvkq z=L(IYP0mFvYqz(O3=(}zS^7Sa6Qwyp4?V<3zu+8wA&S}5^cZ$0(!lu{f#gf$PZNh%|mCcy&-Vwfvej|TabM?SA^fj-av z{^wHmmB$w(#+|1QhvNi-I$lD)_ds*O=&YH!AQ;8EQ(CO(5@gzT_ESV-ndPaN0avyE z<*tyQOukBZ>JC}J-Z1-*JuBv4*eJ_)@&0?yD(PfwWaM=G+9mJ*BRUH5o1NJotfl|j zw!Z8?6?b}r5jAV?-jzM~?>_v)-PWCp5Z&BTH*Dzl-P4t&M_+Zo!gED5U!lYJ++yOZGg|H zple?WcIMB;KA9>?^d$FR;ZN=E#d1^|9tw7b&&6(qvIqD`oM0z?F7`qV=H`BM?F+$9 z?YY>#I?PRFbnPDQ$%DgtxChWDd2q4y&$qR^aiz8Mz2=29?~lS;v0jCVp85S(5@BFZ z?QWOSTCHC5rZu1kWJs}jkG%s76loeTd`xjB6Cx!y4zx<`Z>l?uCJgL`Vg zJ!x2jnFIc)%*A@vV?ORc*9LP>77p#{enuEd670kd?Fm#u*Omx&%KsP7{%h9%V(0%o z>&{CxFz@6km^XXNF%DXoE&r;#J#vzSWpPh%@;ThdX*}`)!O<3M|0t>}V0Qf+#=m zamOiS0>9SoR()kiFJDxgI#n5xC`v=d@MIy9g1>zNSBsgm$311t#R}pGL*as*=;1wq zFh>jAQ;@0R&>k*`TAO=v8l<}iU7Ii1`M(wJKhyL-^#2rZVYm0k##^!ZVf|zH&WsD4@MyLBzD&u+qQYWYZs&>y3n^VaiwK zA0GApn0nxe+|r#-_kOrSIl0A_*OVT%P3K5*xi&vQ|3ZseCH<#|dSc^Og3l_H`PGh09 z6Ts_y7dX8U0gjJdHp+tt)%fH#I*y?@zL3TwjH|+@6B`Np{iX*T9?gf3?*q`KF8HUK zh4N@5G$A|M?1=yhWQ}eoXyG%%;FI&kXg3D+I>rbs(QXRwdz=A0Ao_y=VX`JZlXjPv zafXmc;w!s}tTX5%q~3XCDIgl<`xEl#Q68Ug=@cN*8E}3&vvHZ70IrllFZU-r9l`iT z0LV}%wziaN#7xs=ji-%ws3BTr$fj(k@PoECsW!#Ev zM2+jG1GExj6Jwxjz|t!gxb^`!Ru10=fi%v7sO8x-cq;WtzauZr}Y~eNJJ8@6O z@%;Iu(oR8b2Uch)Z3`bmIP7VYUir*6suU^sg)54qlG(=b zCIx#j(@v2XLH-_0ikz>o&{D`bvawXVkmJxSvh42~aQ4!`kMrdx0A8uhr?pf(WzI?d zadrhSgBQHlS{9~X3J4?gaBCZY!zu+OTa}1zKdyj$LeA&2k0;5pt-R#fRt|ugBxa;} zsQ1itV28*ubg~^&P=L#fZXSW|pn$`bUu?yu{wb2gFSEAHhyv&&)_>TV`M+&VW&eNM z+W!nXDf!>fN&SJZBK_nkv)!EGN&4Dj^Ly6E+~YSrPnyhlax5k_`_B!3ntr^uc4dsF z{qAqyo=N`6SJT+c*Gh;}O{TGhq4;F{05MRrDP-g&zmJ}*PQMVXApF^Ax-V{7p(?Ii zIQxb;-EB-6c5(KW9(R*>h?YRuuiMu3jJeGXVvTb zt|>$D>6@lCT#m5~j`4lG1w(4u(l|69A$rv7+7^q;DcF|tbN!gMwXLa(=0fTtuX^TDznyeEPEI)T-e)kCP>qQi*K^=y3|@#kjhsOHUG*RE zv4#vG+=YgHV`-v~9<;+MLOYM?3ei{#w(QUd6)x^Lrz`?*0}w%Ak1AFZT#Fc#(naU*8d`@i--&(=e`Y?Z(*_j05Lo{|!?#+gLhd-4oonN9_iq}UJR}_SdT!=GkF@Q>)ZHi1k>0xF$JxT3 z>IIB6{ntWT)ZmByqEteOcV}evEQa)x)LWw;A^N30@@t{ft~EIM!ggWxD)tBJX@lpp zj+V1o!gqubf113mBd_3=Wzd;lXrMXi2959(c+pde)IY(=A+yhE({+N3LD~#m(G)X6b*yeQQ0`4vlX6|`zIaAwluj=I+SI5#`_!C)i3`zpch4+^x=5f!_ zv`ytV?0Ieh)+2Z|6=%q^;)MhC$V}I9Kv_isQ?O-JVu`~(5JPpCng?i&gn>+CriPVvrG5^Cs=e(wK^=f--x zQMwRBiA;|cmDUO}cCdL*eG5jR7V)f!#f|I6CEDzT%0c2M zh5ayi|K-b{SgqTu(1%Mcc?IWqUy}&XsmCYOTB3n4vd4R2GZT1nGESZli<7%G#dPj` zM=+MKVAX&~X`jxF$c&{$DU{yI2<$fQ%#&Yd^^Oqa9c+galkJF|-wI?u^4(`m$v4ko zoz5X=9)NC?kJqFT^%uJpV6DUY0T?0479p3GqtwWOqWCUDvQyRfF{ z#!`E-cY@e#HgON!Q-iriF;qfmr+00-Nf*+wGCn{*v(tejJyWu3`PX^Kn~Bnlb?1QmPQiuv zwijsjyVTS*@woB&D6_4~!cQkyJ`Qy!$Q?YD(uRtIHuDCW%p`u!S;EzZ-s0E9@w{{e z4IyPk(N&R#r%e+XY{uG!Ien=GGiZ9SJa#V>EynE_uL5)2rNUny?bPNo{^QPV$SHLx zw^t-b7<~=(yK30R!}^p$hx>--WC9U5f^{H;Dhek$xKUj#%E)m;>Jt;)Lqj+^D1KKi(^}o55w3cgHX*h zqMWI}Ud#(K+Q=L`^3sHV(sQC~#3>HT0<4FzuuYyK?RQ{|M-j959r5jTffe)x&iS7}7l^X7xB!OdGCZ;epd{X3H8?`b=yB;9zs#>tkm=uc<1Gs%f zwO@wx2IotOkX81faR>At4O(-62>E{Xhcz|}HJArjXCsFjW7*{jNMM`SM^aaIg)VI(1d*D2+kV1fSnGG zEqV{8T+h^c%9U5hcPhbw*YPkf%7orv??N}Uig!B%FdXLwH>i$L=fDd#qpi<((yUo+)1<|0yaL3Tx2`>^1+fgW#H{nVCF%7{@%EK^$QLa)Atc<#k|nl}WS z8N1o?k+_#ObaK9U=$tdgP-5z77IO_QcXJrp+D1ILK746CB>t-In>UBM@#k&lq1h1T zOi>mvKq2{pxEMQvaNvb>K~s*G&6%J`f4U)bC}|AF8LbsN-oZFYz*&>G%Y{0C(@F#B zJBzRpdd2!s3lw!DTAY{Safu6g1#C~8^D-z7kT4#BQq3oZSamUp(Z;L)LX-47bz$M$ zC?BvI#GXFTrVqw1lHCny3d$eG;L=@BgA2*Zl!Q{q4sc*T5|;DSPW1f?%vH%Ju^5zPlM{2&4HKN z?Q}#L9=9e*<~KpnU%o7OI<$~h{%qR$R^2RSS(#saD2t7%W5^aZYm##Hp;+zeebH!I`B0%f zz%Ec$l>Lp%iJNB{>EpIAcyeVRm|!28q1d0^B-XImR+YLqA&k^^&-5nAOMbAhTwnm! z^W6y$8akgfK(V?({iB1>Q*Y{80Mw3MU+Bl(>`=+Q#$G}}YBCA0O zaP~kJ+^(M%rcpuC_RmhQ5Vkc3|4f83hDff5B#h^yP6X}b)T^I`I)@X1f#)BwJaY2U zY`cfJAlLc$0Dbk54<&)?fWW;WG^h&6eMyC!6=SyCC&+#Ews1EB)d_YYLrbX6ns+Fm z^M&86E@-01uPiWyCl_w$fF^b)JDDFtlhnIxZV!f!G|}`?LRM{xKQ0cjn9AM%22k9L z{idG5j5+L=Dj?+kY8=#V$rX-6)tM{r1{x|kt71QZE-FyB8k0M8?Omj%iPd^j=L(^R zVv@iXu%-5B*R#c5QYqLEAkM5Qy2{O%!QCM~&{J==V^3l;#vyDIR8F$Zy6pjCs)#iJ z)vI^jEigwr?OYEEWu7PwCXE-Ifod}o4Y^1hZ>S-O3l@E;iUaNIBHho<9cQ(EZVvMS z;*thv(41KAkb$_&bhbzf6tF6O1hTKS3@T`8>3$=WUes&Cz>U;j993s;!omwEo1Yh! ztN|7_l#0}VxWQb=QoeDVwi*h&KTUjw(h>-2EoWI#KesDD?d7T{6)057CX){sO_S{= z%%Zm+rftU37%z8)R`+RRYPsLk47=yK#-P}_3s}JTG;Sv)187|*dEhXp%fx#~jCUYO zD8OtZY=@w*q|qE!XpLOmL1&PydaC=c+0Fnytv5iRIilr|jlz$`o;CmQ+Q|bt7|1~> z!`VT?7|=&LB?}-38u$WOVkSt*kSt=bBh3j0ZR|M*fMU77zU_tKTE`Ta?0<9M5;kQf6u!#|gEd zf$|LnZ(qPCNvX&uSU;bT7!S%C!?q9eVuMylt$Et3&U=3#h?IN*-}2>`SLt_RfrY=r zZJJX=k;FlZI74UeZ74E%Ga-cMtSTn7_v$SFv1;bRA42}BNRL2E=)$G&+-DyU+M1;e z)%?qXNPpwT6Bin<1IWc)O@Hxtva}3323r((no1Zk7UmrfEx#HvcZpyHYV#&O1qIq) z*Xy@_1T!e-H3xv0v+kqopt!SizY&ZVs^<^=UL*OJf9C;Y(PeJvxAz?xpH_`(58y8O ztBqiM=5|Lv#SO-4XHk!XQk$2yLhr}@NLPcJ?~S%7d}Hqt$@$gO+HbJT zTQ^tlYQ|s{w%(;Ib8Z?it%c$Co0(S%3T|Di6D$R2zU`y?a>zrVFLVS-_R<_a1CU53 z=ROn$-%)K;MY$(Ue#*>bZN{>dq6y)uuHH$|xaw`ig4v#6k6gO3snyu z^f81g+i%hN;H@;JU%^WBsjiCJIy&Jn4({hmO$j#voZpyULIf@-s|tGMbDBZe#NJv%s%F|F|7r!))~_q_Z8oNi%d9&|yF@SSS=1{c(L18`bIh3Zv@#mL8$u7xZ z0!nrjh;+~to^i-Mpzdq`Q52drQcgLHi_nRzpBN0^B=S9vLc?f%YeEIzYZ@)!u`9xn zx9}z^!M_Jg>=fn|C`tzDC+s(fUUs&u)+5BSR3MEK9n#}4;#O8XJ^|2pjTtdqsS(U7 zdPvag?9)cn0I`MGUI8Yz%)tA{ zY>XYnwV_HsQhQJQUZ@GP(i#f{J&|PmntjppCagRg03nN6pY$DjtGk@f0<4MdF-O2Z z9N*vLzY0d{DGJcn=DpmdeFQD#YhM2hb_KIqdN;~8V{xC~Nb%gFI6k4GwEM@EQk_M1 zdY>5KVD&MpZdt(MX7JTikOP z{9T-}FW6bTQ{f*%jqkJ4I*Oj|3VIt}?ITquZjAaxztqrl>!--$z+|p4H^i{uI4x5P zN}O)ieFKPy?k%p5GN?rn_am#@#hW27dKQ#4>3qOIE#TyPhsb7(jCvmhmPu6=v18xY?*~oQ zi1Y6NVd2iX`b0Q%D0p=LM#-P8Za;9rNiIKHIS0COo=-7aCH4X?(x7X`QJxOq_inLU zDo4{Ex-v_kuy%W$6xhSFYfNx^#E}}H{z!f?Pmoa%RTbLh5EP+3Z}ElOnvgWNu8C0n z^`m2`sIBJ>8)>Cu>~2Mac&Nu)DLKmA!`|Tano4N1$sxd>j|>vE zE{p6YMn$z=?`Q$e_ffQH)nKNn1oY<|)d^=r_q-|Kgxuk_)|4-S1a@cHkWa96eaJ@w zp!c-xW*-Y^!oJ}C49a7Or;5tqV9|yOTn-L&bV##=Fp!XYhSNHk8Vy;wn;r;RcS6W* zYjO%NYXgc|^j+BI=N|k*fV3Y;2s(mxaNuwJy^d z!C+aL?Y4$mE>vE=Bw#9Jix~Czv|HCw_kpXAacHrBL#Vb0+y{yBH~2Q8-!Vzu{wqOG zB#q<%^q@`?Je*v5zqzCIMXQNxZ8-pcAs>0h2D1O76SdX~SvMZwNJ|Qin@S%BrR&y8 z1*bRp`N(db+ppbah80@642Qn~boJY}LclkT`=BZ>)UeFYDO0R|-w|Ui!Hd+cyVWez z2(~oo$DmN5Y8%D&YSdcSJiPwijc$>EZ zRgh}I11Z>#M44q9T7p!+db_}C&nLMWfJqDv8f2UmZ&n-%a8Q_*jh+Hji!RK;Nn^D6 z1v{&0Y+-Ytkh%oC@sCpSTLSOVraYIr_5$iR8SG`V`R(1tCHHymI| zO@kyN_q_+S(2w&JfTwZh3o_uvjiaYSk<_Modw{a=Lzh3bZ-+K5Iw%y;K{CEN0GrJ>iCn!pAwp}>4_1g=~csd>{ zpCpSbhZ#4a=fUSuZ4ZOdT7DSygc0#pBT~;42id8QXYy1_duHZG)1qDDzJg>=h=!}@ z*by;tjyfQd-eED2{li!lXw#}oRqle_e3M8C@Kj_8-4MjEbbpBxo$?Us-NeeXS|^;{ ze~3IA4t5_}10XG3y&H#^846E}$r_+|8LoIZxP&?%N+zrA#w7>+CTt7TT|#x*($8`K z$yG{G;TZ@8aUHrBm_>PWqE&+hpZw;66zdcG_MUJgIB!9bXP7QyK%IM)^bkkd`L6-j z1!41M`=5W{@EW_zZ57FAxukvML9RrK-jrN2{!mc9Lx8Aa^WVfUIx5|7@04pCiq+Tqs>irTKXgs??*Bq_N>`X`r2%sI4vXjTDk3k2P{WKY zRGl3rE$|;V7was+<5f$f+rGlz1|k&2?>QaXh{wO_KvVF?$+LEiSNbve#zqr3yC;RG zIUZ9_j6D3%k%u?D<-0Y+MvZFkF3+{&SkYCEmJmv;l*Vx5=2#*>1C9MO-D!t>QaZ2? z;^|CMOa!+zyByhcQS|A@mzv+AP&o=}t}ds=)AYN#3*tDje0TE~WYs(YYXij6i+MOB z5P|=xygLxT($1MZ2X7KIb1kD#?h1!5E63ml+b19Ig5WE=BP1|1=jws3=HEK0ZELte zdmYgp5naX7oz&`tQtB^Wcf!KtwhL(aBqcR>*bv0Z7y~{nro9JF`_vE>2&PRONjwSM zA}XQ|Q0cbS*&__iztGC(WjYnWv-~MjGWm>%jacvt1uU`Z3sMGQ+}6MFbZLNexDa%C zCzKJIeD{Vz)jY%qE@7~K*TUew2Km7l)pqP(FMzeXBWt5N^xoXGRZ6^+ZE=t$k~NL9 z6N}dhHAVzy1;U<$1ZY%*^YT4tQ8j^$oX+9Q^6XPM*Hz0z9i!xq%|vo)hv@mhl^5jM z@yTMPW=#J6t5>1W(aiSVgoJze>d-ZKw5qW{V{4~$b%KnT&`hy(X0BvO1T3YEs^ zy;6c(hwETBpm<^{RN3IGm3me2IR#jJFiW1e<{+|!=XS1HVQ#^D%PQmfZ|pq<$9X1E z@i61_tU_=&suFnHyMy7o^(Bd7)6nscEF)KIm2?sgz_!X- z^sB_lLrBv0%HE2u&T3Em6+~J1ajD+=1v&4vY19QOT%iThudf}!>?l9T)C8Y*3%8%z z*^YrWUKEYt2pp=pz@4gYt6Dk@}9tz zSWeqBMe%LfO|mqEFeK8b^}<%QO>N10IVO*L{#2&_WKgUBrh5Mj>ff9{ttr4=GCPc> z+`)~%I{Xd_oP%e7>44$p;0bW7N7d~IRf)4hD7!|}Y($|62T9cuctm3(aPG`R9GpY{ zj5KCH0ZDAWc^KfERMBy9ok~5`_hfeb0tyF%ieP`Hk^swNTdA9#BlQ}KK|Uh~7kbz^ zg$7!{)k+NmJnu)*9Yt2_-M2=WZ^7xcg%*Kx`ira#0Tt&>Rc){xINY_7N|Q@+9=HJR zDOvBJ1dN7rZ~$x!PO@AysB&lKfWrv3Ol{CM9M~tg;IW10c9eDh3hbnw$VJX@P|kl* z88aM3=Y}Hx8O}cEuTD}kJgF3)E6fzA1GGK<7|@1nR01JNLUyH{0uGXKjI_D1@FbksD|LX6ZpXtLEL8%IQrp7ry=sbjuE0I0W)rmg3XTG*QT5DaG^%eEinZkhSp$c z&&>XiU<;M|WDm+(@raJ?WJHemDUV)T7Ad`37)e<+m@+|#h=*IAcb;YXhWeUsk4p>6 z-6ObjHi2cik&@)maDwVp;e1t8t)#NGS;(rG zc~L?z)D>nAWEl-2O^A#pAuGUcDs+UVNQP z`Ha)jVDB#X+%PXe}x46ou}Q{(n+;b8tyz<2omO6Y=TP?X$DnG)dZ?pKNJkSH>S@NX4k46m+wv(0tgH}%2nB<-I;_WI{K*q>^4u#^P_R1cJuugSvc#Iny_8VB);t?`4_a5-(QH{a;-{4Sx zy+YPjEMqDG5ZW|GlIRMfX_Bqg2jS#*i=+zrXV4HvMr|Rr=D?X(v=Q}-Vba#ayj+^6 zh94YuQ(8KjCS4Z|@lD>fGu<0N3x8w}EQ26HohO9dBFBCtz-egaDn=meADw)93t+Ph z_O8d{wS&^ix&Wh#%u*Hzlk7@6sg~TM7*Zc`1VTa*q6bOM7?f0LB%PM75Rz5g=aejW z+H+Qt)ta!$mXSi(9nvvmID$!1kOsWX5X}D4lZykrW&4 zhogZ+%qf@VeGa%wqy?5k!1{0gS|VP( zx{a#buK&Y5a%{eEY2N;H_ElD z^^xJNtk!!))E`0*W7omr0OVzJKU=yC-#DreB*So0=cVyyM4Ilq;!9(oOHv+s`Xx(_ zfv~?qC?dKp$qwA4LfIaj<0G!CsdKpPOttD~V=_?p_Z>%v`cJR}(AX0lhjXsZyq^Kd4MjsyfMqmf|4}^Y0RBe}$UsQs!uiGdQ9%O$ zB43*wggCA%DF%X9{R;62EOAr#!*G@(%;d_$CabA>i|IRBf@<+faQ^)I*kO^|7L-xQ zqVumvEdMH`ZpMvmoyJyg#uQ+{Oyn#gz$J7{7h!YY@~F4T$NMSS$r4NGPl_F4$hIL> zIaPYYTucr-IBW~t-w#%9c%>4_At$x05V9^cnW9dj3&LzT6n2=ZU{dh{81ydzk9TKx z8~210+S0Xg8eWvxn|E|dxAl5FF2}tVH6vpa5;+Bxx>jdKunpIGZaxD>;=3UxFjiR~ zr~_+Cg(>atbBHkGr%61uYWBGEG1PNtIq=mqM+<_Swo{S2Jg$n``aOrvf{zFmSi=RE zXkB>tMUkCHaMGpy=+TTV8xQ^vxRs&b)tq9rhEx0pd3Sm$R=ET8!UG0DAFh#j&G;KF zShIj~UI_3q?!g?tz{^*A8rc+uAD_}?m=qhN;76w?4vPvp3T@Vx!bS5A_v>56Gzaj= znT;?c-oonv7tGq$2%2_0U~HKIgcDYnK{&)D>XrkLzTde_ohvzjpd*~tgH70!+O7>i zB&JXU!jBzTO_%qOb<$Fh+uh<(M#B~8li?WQ?S}jgo@Zw0D}<(g_V$the=Eg~l)n?|A=dVILo)EvCJXwGLBo%JfaDb^5^_w)9X)4odtkwD%X;xj z`oLf)=V&0VQO$6xzF9IRKV6}Zo+t~rMs(L7?5OHdA@K+MMfHM7tA#1Kd5mNO000id zFV?{xr#eyuXLx^w&G%ssQEZkY_TH(+X^C*PA}u_JBj-j)(}?j8z_R zC6NPG`nS2Q3lb;<;zYiV`}f20@?ir4Xxf6*0iMbrgfbU-(4P5=f#p?N)wId$aE9H2-%2HK?!QX7 zh(tHr6SpTvtMc>;DI%1+*MWhpl<3(rT`6#v$vGHTe-s_s^&@u`@bR-(QZWd|sbTM9 zoE&L(Za1rS!L+~$4(`T`Dbl$SOn>ThPUY-zQURg1diJ=`OTM#WHl;vogN|GMtaDj{ zsuWXeK<}o%6d2+-^9%$S!V=@k!~k@cYt91z-C6#6i1|{V1DxsjYGle@?9XOR-Qes~ z?QaFL50 zJg=X;1y!QdAwI3(hD-Fz4K&Lz{o(^Dm9Q_`A5!CJan9g&^+mWaxGL=})s_a0tm7!d zkn*yLx54Xb?uyz8R`~1i1fYrsqqTJQqU2Ez`bzJBxCOt^gP=gc&u+oBA$4mBBs$s^plGCgY42#bw!oG$FlMK;p}K)C3@G1P%{NMIHUR#VAh84N=2tI3V)8t$yn>4( zyG?TMt092#xWZ|*37W+5CN#mcOZx*vPkJhvKHMxb&=eFz28h0I7M|RhjMk_|7B<0? z?g#(pgRNR6VdR9r`6}#9wmxeq(rj`-%VR#VgZJk3nU7#K7iO-UAkGfRw-0lr>J!L+ zdTks5olKd4#a;@3bs8e<={H1@RJKHoc4m^0VaKB|;EivNpydA2ez0#LaQk+#tO__} zz<*OBcLE|hk(o&TE*>p_8JEG1OQ(@fs^JQQ}@LHynN}S_Uo<;Tdlc%eAtZhmM+8MAlP6tTsjwpV7ld<6|z6 z-QX7^9!mpGo?~+hRYk3M`F|M87Bg0aWG?a?ec&Yg7DASxL<47$)KVC=t@Jt3 z8#9H78OrpAOf!b4^ZB7M@k@K6`69v6NqfWuOWW@jKM{%@#p1zB%-e`LEwlK9kC`ND z!B^t1;x!9)YlU7hB?A*x>>;nMhwo%mjsmgL4jA!(U~&+8kx*1+s(7Y36qqR=p)Qh( zkHm|)ilF?gqfjtahEA$CH62hNUd7{bGSgW-cNi2q0kIVXNXy;zh2)(?p4Ffq?>Nu{OF zi)^Ce#VoerFUp4Ip3m~Q%0QkcFKXwCW$m5nKr#~bRQw_T#JysEpm;@#KgKz}_@P|q z#itS1MLDMJ&ge~pIh#VhA5hX-viQg3sZ_B(OertE3aedwDv~}S7CH9SGx6Yzh4XN? zZtXaFXz`2rrx!o7#cA;~99fv{6oMG=3*n~`nhIJvr3Y~$MTn`z2eO%gnV>XRL8CxG zcX)xdB4|r2LP{Y32=9wNf~Mt7=s=<+OvX=r@oCU!kzW7d`HV@SKQT^BgGxMu0^eh- zu@YL(i=-`SG%LtxG+eVtLs~k+W*#{XKTxx3k+zgMp*)D>t?A-;j5_@Y(8fBy#lN{g zZeZ5D$m#QGTS)TkWG0Ez4!y(bAlDAwra!Y)5_6K4uv4g^>z<*|2I>JgrXKFqCK)WFmu%+-R93vididd_!u~Vm}D8&gZjmv zHP{pfcs;`t@?cAT5X=Ty_8;=&8y6sW{M!aGeN@apw(@e<;#9OSi%M1oa{%Y?1JZEe zGsCCq`ESH*0Sui24tk5wuA5II6BfmE@w4~|KNkQQm%HMZzhAWf-U6{QAXMz40g}J} zV@_|fAjk0M0Hh#+sbC{Q)v6nw_m+z@*8(R7_&JaS4NS$1rj(P@9(WnV#sgQ!dsfM` zak9YK4K5or0B7LbZGx@gV11_&)TJqC_Eu97X53w#e;tenSrNX`Ub}?GDW2pv;aYB zk`@in>5Rcg#L1cuPG9)4x}i>a1#}59uNOg_v>TzV1HK{DBVuQOj_K8|HYr$rO#FgV zN7gRUiZ)9Z+bhD@R^$pJ$aXApn+%u7lR^q#Gx9}MDC}>w}whiI| z0DeZUfD`T7EM80sTClziA5MqB(F?xC7=$$pLB@9i3;6$fg;pe|Pa^T5>oKH6+EV%s zuume2{0Zid#+@$s*CQ(033&I<6K@e-8|kA-+@a)@vPPr^KRj7NtvvRB0F)Sqg`??!Llf zPq!j%{ukSR+lm025gD*u1V03~{V*d)BqMfF7KBN_n^^Q6S zMufnvFFZDj=|?-Fj=}#KS#QNMf-niZn9ZcT{fLmodV$~-#oR;|XNLbz`*^NV0CYGdBt8<$01tgvU;u#2g6~&~sT4( z@p3wTFsV`JFe2|$6kow5)QRvAp90zq5g@>cfWV+cs#x^!1)z0;iDoyD(*FI9+=-0g zDnS7-^a!-K@^`@~-siUVo%Jt)umRAI+yaE7_5w85G7S9m8m6BJA z#}F27oDK31nnOMqFduSdVJO8#?}izJsJLF3@GxqN4;>rRS!rLrC%VK?g@Cz=fQN2P z|B#gRMm$ZpmxeE`{O&Y%`G=urd!NCa#ur?^hy}zSSb*xz|g3bwCP+C8=gfL>E zn8P27O&s0ACE6`5Mq^g-rYO3xV1%o&DI5^ z@vx zZ#@NEr~3b>`7--=&DT}M|E~G^AK^OP`ZuoAE061E+c#2LCHIFdeZP0_ioDD)R@gp%AyxUdQ+l9#Lp#O6`Ns`x)fq`%iqpD_mgH8K-A~t>IVN2kXCnbf?DpOx zpp$=!UsL14qYSP>!%%VzZ=Za zS|OJxrNQ}YswUD}FRVsBYRdu)43n;OXjCiKpsXo==1PD2WRS1~ zsR<)8Q@)2g^@yab>;qAH8)a9LLQcXpB@92c?p3I~ zBPt}5yVLg?*HO`YQC|I?rG7+y;{}d7MLh|ZlWvCYRPTP&9T)+8Hf0^3T(Y{ir`{?BI`S8Rm9$(359^Zs8`McF$U06_@H>Lpg5C)fMAS z74;i7N86k@q{=#V%s4ym%HKNiqg2ACCMt$HBY?c)L!=vt$}Fl!d6>bhXkC?| zZgjsJ`Q(={VSIk6Fj!4yQ0?rB_I`ZiRb37-`h2{KWps2|^9uP#Eh||EL!LZY=ONct zwIb{VM?EQ;xuI;Vd+RFSBKD?>LKE9bi{T@Z{`paV9Qr;%$Bl|61Q*ex!YsP<&F?MT zu}D%~^{iib`Ht^_`Jui@zcRV~p0-z?d)UB6z2&3jE%%Rf{@hr(GnjaPsqetwy_5M? zlMnmUe#gF4KdUCAvpfhjoo8-$yDES z7MedQh|x;#*Qp=HGMB7kG4xKo*4c32>FeH37hS6$^}(F?mM@wl$cfkPcykiFC;ZLU zUw8fHF!|7pYJwXJTIGkZDW4tF4qkfDs(ZaZn8$duQk8`3#}6H$n=qW3?j)n{^1pxO za=Gtzt*4-RpJKz>?M>FHUEZ_8P~nD8-0j{~tA9@p2~Cy4X--%jGoGy9*G%`ZC_{g_ zOb|W&4YPH#XBdI(YI`yD?CUR?f3ZZr9ygkAMnki>ferHm`J}p#INh ze$?P&de@9qapdlR%R|SOwM}#i>H4FBuFOweBk zzWTzEnv>s^P(JFgwBKg5>+J1WTc`XzJ=1YB-~Qgdq$DoXGdIsFd3mKOecya{=Q$>phI=lyl;1u=MDASS zK^~ux8PSP@()rFEyZlBv2pQ*wZT%F06VVSTSoquuRFct8dZd4W^RkNFlXn5L=79E( zfy!p#O>EomT7CT`y~|@O$-6EZ5-lfP5z$lpgz|2_UHB1N+O*aZUhUwfgua_emt~_9 z|1aj=JF2Oz`5(4(6_IJ_g0g@0>&u9&-?qX_5Jf*E|ZX)v(MhMXJ*fyJ@c7~ z;GAD>RBsAc--Z$4mg8*N?&)<4^cTzC>vg;3QiWd|+9Ia%kFMcJ0RC6onJGHGMla)f zWvLT+5sn&iG?jtdX<>K$9l54DQ2BOLFzGq7I;f&iKTtE+?!5HPKXw?mH1~d*8a_c} z$VTlhF_rZ!?_4Hk=vdliTWf`hqg2*y^xqX@*PN5~FeDUg<4FMQRnnMoxJ zqZQ|MuuDS!rL@x78pXSIdRGc#$?r#=?pIh{pf+ds?dCJ_w9aC|cB$X@l}Ubp+- z=&t05oTkp%74)rMnc>g6!fWuAxj8yna-|3&A(COP(YH}6%#$-_5I6C*3|CoE` z!HMBAOIwK+REnZ2*cKh3ygPQsvu^D}eqvFb;`e>Cch*0Vz37_SKX015tjZwqmmBz- zwtWitOo`|j+rOUlCBT^Vm3VR0pN{O+lZ0?FB zGdT}-pe)}E^8Qj2U8tIIiNu;J^HpV8YQHYw_{8oLD=&S~^iy+{AL-TKdcWB;Pw9TA zPhKB79P~nx#~3$D3$lpN`@Tn@S7esdFvWRi+PWb>qv;MaimuXiqOtV-K#8wMOENv| zNUgcj^HksL!X@Kt+^^v-6E;=oLiM93s3M&8*2E%9F(t=~0fQy?KTKJZMNzrddQPOSkL76a3O)8RsT>D6t-SL(M0^2&cn zxG&1+E$;O7Q!37|F=JVp5wpB$OasAVeZ|0=L2eRx!h78GGv~iVGQ>|70RirFZ?I$0f;34c*57Lg z!>{ezGO6BW`<7xysFBv{7h*%<@TuUPbrugX`I+{gZm zo=^MsHr`f)?j-px%HVf8E}IRXFBAQ^5DxF!_$cBaBS)fmvVeT$i3k6NRIS_q^jCuPKm{Ryh3&(@yZ!;oOn?Gx*^AOWU67j3n$a zG~ITFdBv!1H;drYq!zU83`IIT+~Q+imFASF$UCQ_UR)7(6pQm)JIT8nq@6%UWKG=>JNw2DBeQrw6$$lX_V1VkoR|yP4(oJ$Hp^Es%QNQg$cEo~pHHd613Je= zXRC4nqhl4c)09PI4hjlw1!bMu1STnn*pBnVz;6*_Bw8@nObI|x^uLYOj^$#;)&ax^ zJenp2UjxcYZZ6SPp%~ktlSOpJ<`7-ogl0;~b0nI@7%6Bq-0=pEQ~S>MK)*z{$985B z$7<$C<-}s>t{>%wYz$lpAR@WY{$^i^kC-HAgiBt))1g;Jp;Kqet$HwS>Fl;+$(4ev zs1jZCvGJx>YsR2~L{usbkMM!Z`l@cwk5A%?OYqr|ZIbihsrWbAgfj4fv!GeHr^81n z-Kfe_GC8M%9BfZBgJ=7)Tl!gB0r@7VzL zzDO$TDA!$lKDrZE9I1o#k`R^Z$N$Kd^~Yy!&Lxgnx0I#RhDF1Cg^sXEoZl=oH3)Pw z86)Wcfj;BCdi+WKrAAs@M9zqJo+&a@np89m^?@nt2Vz;kV4a0#>3C1ma^4w6xN97Y z{5}wuAsQAdcL2FyDubCBDZ*BhD$iI?fiGhxjjrC#FcP1yeT~m1B~f}QnR9^Af-;D$ z2O--ag(wnRp{x*@jLG&$XB%+g0ZLEjNIEphd0nzNOJ4`TTYMxw$SZ*!%-JB^1ei3N z-2(tb#u_?WZCGS#uYZrDy+Z7c;J{8CT|OiM4p zwqlc3EAL&j=)l~6NSn#OrOj{Ie@ol{4%sF3z(1-{uP-2^k&3CENvwKS!Aeihw63^d z9!fDUT4&zwZazsnZt5EIYR-8^b$hX!>h|NOPMKCLJNoOgCr7s$9Q(pb;ss&|dKliz z2NwF;W!3zV5wo`bQUvMWP59ofqq66;Ye>!B;;D40>;s9F9qmC{)(@g`mI$+Nmy2-yNoX9<@Vb#u&r#&TlxD6A{+Q_4Y&BJt(OkSC;fryu(S!prwDH{KE ze{mc=;v}acSC$;bzv=(-?n*|E4}H08=Cps zY^?`%1Nsk2mB3w>$GMbkoVG_#+_E8zggwGKhE?N_P&J^=4t`V27f9=fiywfa?Ea}< zNV&fgTe8$`I_oK z)~g6yP7S`(L8<06=K<-vyH@3>(XbUC7F-YO6rdx*L91wdTXI$J5!-}MDWQ; zaI5z3#Mq#vX=#2|Qr&4Lm<#J|n`xE9tRg5mjGwc6EMjFbODDw;?R)e=jt-QB4tMGY z;>TK7K!wr%>C@0qp|}t-PN!}UGhm!5n$l_1m>z-#ba7dECrl<8D;6r^qSdlwVY^2KGM`8!D@ z%__rjXa2=RtvUDdd6taFOow+36eHzWITQouCNnpHbX}NtQtKucmoM~?O0!-GLmm49 zwRL!m#lb+hG}VESbA$D`Ibbj56|HH0%ZSXy*!y_PkPq(};R$$SUx?0F@wqsbsBWeZ z%Wg0PnGz?qLTSdaafr$E)5J!QRdOq83ss6N>HuxS}MdCI_mPt>6od!&U{Iw`>&d(GejUUm@ zeX`XZ6t$%0mIXkPYiySzWE$n(#+V$%7RQN4AmOg?hX87{1PFa0c(y9^Tr*k;)uwVk z)D!eLQw9$SjFCL2F1=TB(~-Cam8>*MErmx*^`m-+zLJR``#~A%G2s-H$_Zv}X@=2q zV-G?+Rp|pUWV`jK?vn$Bkv0=1q-@TABsFQM3RhIgg zWvk%-1rNti+1Cf8eomU?_K7daL-#r-f`C&lPzaFeG3i~s1Pb>JXX?HnY3BO*CaHMX z97zluC4CkbdRJ#MsimP9s27#)21isMqx2F%%f+;5DvH}ZSuGG5cq#NlG_*A`?gdCC z6{1N)O6z^B*Cmv8IYHjpA#WNRiwV1g#h;0ait0#G0$y*t7~)p<9kpL=&88gHmKCb;DCN&PIfnN~DV9S=Afbz0ZOZ`3@s)7C&m zL0gs5a;VMH7M?loBwxb#B@gP?)t%w(rXbM@=XrrQSBh zN7Kd!$Bh+AJm>bnsf@8!;!7eev#dU64HMC1MMjswgW4q!vwqZ|vSV0Cy_c&f53!nl0@ej6p8d1sd^g#zT%jE( zNEL)Yc3Ua`uRuM=bAzo(lZRNe_IS#V5I0}y`bkhtbM%{w#YS!9{tQ4&N!7m#IXE9< z@$Qf%s8g~9upcg*9fJ5rS`G)In=O!=OQEsux4|G`ahAkMwcw(xrShb&(7AMEH>|1k zo1$3sET%=MCm=wajeczkSV_JL7ophj8p&J8YKs+agZSu8m&TyjMZhrc0;Cuva`vEw zEO$cgMterd;q452XJ3-~Mo2_`-s@Zf^}z+^8@r+2U#5LhrOp20D{aOy&^emMX&Y?3 zrB!EgEGYGsx4@!Pt7P^-dkX#&==w18dM)F4q9wBpN@kX&Rn#-A46N39)i5Fw@aei3 zL#&J|+sX=nK2{#5!l6-#zaps4hIa=**fyR0o5d)aDlmtmtSYW$kpXDoLpjyQ=UmOi zZ3?hP&xPg!_|EtIXUV9o)7*auDxGHXML_y1X;YsdXExWZ3*z(VMu{_{q%%Ynw2bc_ zYaP&9RyjX@0W`FT-16rJ*wE*PnM*+t_sqP6ffXGOmfMa_?A>ZhsMX#+l%oypg+&KL z?=HmlgFR9~L7V{i;(N00tk|V*Y8vWI_m7zmqWWn?i0LW0fQD%e&lAr1eJ>h*%Go(lj~(r#78Sr45< zeqK<6B0wj`Uy)Fz3!-O^V=Rk`mgEsKnO4`4=OSUz(T>C$P#SYQe*hv<+mnLrTW}s) z7JR@k@QEfs74M;)6nBN(dT8fsP>vcz{JmzKgMLZN@Ki4Cj*ZLMHuadNEaTA> zXspD)XmwtpS!Kn+P~3$abqdn5Vg&breOL3%*zv;@m$Y(=FJert+LU@P@?Gb5%uh*l zXN+4de5Lhj=M-{wFyv=c7L<+qU1KMxAI4cDurf{KKd=9MSjJVbd8Zi^ZJVyM&>gBQ zxkBB+BxxK4Az0t$%pm znbVf!q1y(_*w%6=g5J*QW7z{XM9BO~JpQ!|+r6eay2zBZ0e-UVdFcvev^syIuf$?o z%Ue~@@5qRwNOWJGk=GF!17+I0b08agz)BC0QvJss1PGxWGk?~?tql@) zqp|mEMJ}U-r9!A?l$O2w8=Qc9jGMuUYt%anCkQu<=^EP&XXDzo+E6IUd*o+$#spRW zTU9he!Q)JG%zRL%+-6trUqH_V)Li6q#jWo@l2pJ1)8DB=={NCcce9U$QEF~ihf#hq zw1MSyd!;$7XV1C=pi2) zZIHu*0P@)zADaoqC4LsuY}?$y$IG!uNBK|sd-yJegM;r}lk@|&Uud!wPDiH#Oh!_v znQwchJDdO{7((A+haJO{IytIfX%vzm{sSPZkep*|!6 zK(^|IwNT2^yF3|k)|ekL7B5Cg+8w@$konkTtwwfQ?J9^06)ys?urD+3Y`)*K(GD9| z^*Dc)51>~iF;b9@t`t0#2(Ty`riGB2Ugwnz`tFclxp5ItP|<8VoV=4bwm*PL)=Hf} z4tAo_<|4?wzRo52U583)W!B-qdzXH1fjXKV4W$mC1N?1rVLPG2)Bs)jjPu15WY;X0 zdOrlB?fnG+ZgN27M#cufw>UW|K$%Y522m|5_GoxhPALS5RC+OOh9i0(#8$Z;%mlEG zqH>Wam=C3fFFapM+|}+y&>R8Rdm2SjoQS_w}(JJVfS)K=b{1mjTo(YZF3(K&J;9OQdu2 zAXqAESv||Z9J|*09`uTEfO$4)gU4KP&uqv>+J_y5Gh*F?p*^{eiR8EyXX>5r@!MLI zSP%&mSy}u>N|5EzNd-l!RTFwFee-dwj7UI%b?&8tY9A!ySMI;^Cp0H`e+tMK69JnR>))hi(+c2#PY1$xb%{vH?l&*tZ1w5OfAG-#><2(iv_>lK4x5gEWSX$AweS$2; z*O$xC_PlBh(}?<`EtiuC33|fkItb@;+V?|9J12Ktw<2iIXZnz+VL+kNA>qu&_99fC z_PCK802ARG{0+7$xryFj1^HelDZxmIOXWCjnD**SsBS+GpwiXv=1Rt3oMe4abZ@Oy zJ8%Xnxv(Sk5w7jPc_{D7#E-q`xWF}|Cgg*c|!6LMiT_ z&!dagC0yQ5(Vr%^j2I#?Zr5yNHdvkFpn82sDDb>rJFZn!vZYBKV(DM>yF+lCwW^dJ z#9%o!w>rY+?S7Az#gLUv5aNBNdZNQIAUG5?11QO&-){MuA{4x+1O>U6xCRlVE0qV7D~Xl^XB3pO}ihf1y$%b(I$9pBQJ^7 zU7|rpFpO=HjsO588Fz{X2f!qP2U}ibwC=Rk>i(B50KPgTzvGqjDvR^2*_Tsb&*;)g9vqWo$tNUTN-7&j?=k&FgDnsv7 zH-BoTK!xCoGi-H_A)a`et)82E;-?NYH+n=QG9FK`+JHq`gF3lzU8eU91`Z@l^48D{ zB&?@x>u+Mt=XZ}nV6;SzEQ+jCEk6nQU(P*Ak)ThK+RGu$(Zjl_57vv->X{IKMtws) z0VHis@E4-mxM(D18&rxGm#FNAMD(z&kSV3UVk!r`4a{ekQCy-_Uqi_GXpvh9eiLO% zUiV@c?Y=p%$n39M0@eui1{ILLCN8< zAkiDU+a#GF;MBM#5hf#e*s~0;$tdIp4%AwW~Hd?K)zo5K&p@$g04D?W%M^*x3f$4kQK$+8atLP2^)PSuA6u&-D zFi8Xa=n}`ZJg+z~G4?1tE_;XTl9(^IOYiI>c=${^ zuN8A#u-qAEBBG&%?n|9^>Q~3DP*nI0JPl7Hqp9tN7dRJSw#_Xtl+N#!0Z<;)TCe?Z zQHm*{{evjx3sFYybPSu?Z#*L#E2fc>OJkn_1(DI+gcRqqZBA!qG-nvVh>e<_)e zn$et@J3B5;Up&71rkJETbk2#-z3Qqg#(x~g7MGm++zbeI-0UA*qNPRR8Su90h3+HW#Ipbdv#vkUlIz8l7o^0T zEIJPMw?v+sKRVZ>=F!9G>|FHmxtA2DIdpN8F5p-cP#zj$i@T=+hk(O7l!JbV&RVby z6<|-zoH?%36y4foHuX2KIB%DXDTCa!GIH^J;Mzk`mG-|JMNgB%!2jfU5) zxzbIrf%E2r1L8#bQ*$tU9XqB#SCrq#i^8YR1jqY-FR%@6M(%>Adfa9`(3Z{HlgUmy z5UQhT&In%-QhG5NBR?w)^}{=Vs@gFoI&1ay!H*s&eVP{1i8+LA?-+_X2CT#E8q)&> zm|xMp{fSo~vu`L+_0!?i9-W_6!iMZ8*;*Fg-h<;?-=p68F}rQW>G|>vO|mlGvtBw) zvXSph{g*V!7B3fR8-TfQI@0d~Y0>hAG+6yz=Z z?R*8eU-Hvh9lqHH2lO>{Lwgh);FyL^WnKVlk;(2%1Lw+O$isw9IzO<^5i;P-WEEZ! zEhF$XV)fjQeg)t~%o#E3m2C^MtSZNdjqI(uAw`XKM(YdU3FV6aSS;q0d0jw#ba0R| zI~eM6gt%&+e^>KbT^AUbzn#DhGB#Mc)g05tn2ofO^E&#@gGviGR@ta%F6kvq92U^5*V_q|zF zpn2`X_|4E_&8rRXAepxF(PA?p|Wp?(Cv#79PjLE12^ z4(EErUm9TF*q7t6qXGCDuNGpB+K!AU)M3V*Nt_RHmiAYvXWN}^Q+Zt`5>*};$Q@Q1 zt}NPOn^D&smlZkR{b{_pxKjxCmr`jFUqs3bvR_%}0FPgkl7RT5YB-@?&&+``cV;5v z=8R;uN9?6_e`4IE@qK?1FrQL0qH!??fu;N?pIO1q2G#Fw(Q)4mcW1TB!?_RZfJx6D zVOEu$U6oz|vD`g^@`Q-XCDCfSKKe+E>>YllpjElo_Kkw=e<7K0=aW#YXn909WlvMs zQ4`~%T?wmacy3Fxxq0#G44gqZOK%9?l}G+AdhoOv+a6SSA?WW3(p>M9m(De;-|^GL zff#YSnTwF_;6Q1;h~Kjr3QU`w={LkS?$RRc5xCS8-Ae?aQj5n;ffe}NYad{73=OXT z3~bxBA8cMratvA)+bOgQESmMRTq8ha9z+)J~wml%o;ud@i!@D-$ByE6{PrHE?&{q6sCYa;WLd?S$ z5CBql8k{8-?so7`Bg%2~@!7A*xUDV5-4{5wZgUw5Ui>N_K+6Br7Yrw1mZKr zrjyOF^=t!c{XQ!BF(W+4$OLDl)*RjXq9fxH?DG3}>gK1wu0cO=x_0l(MXQ!8KL{E_ ze2awGzs>EN>)E)acM3&ohxnu|Ud5N6?rz3L&d)M@aPUQ^MsxX@r{Z=zMKs0)5sT2T z#9CEib88Qld|A>>KCpw3uw_>NtLF;z+;{wZNj-k-!RWqkYC@N+S$nhQ`#fCaYl>@n zL}29s_WiQg$rGgIWIft<9CY2-eO$tVQ)?pMcuoqs{ybPGw{U{=8w470%O*&jU4;zE zV{v=RW0uaJ!YqxP52XA8V$d;Kp6(uKeSg^I+^1qAWtWa06#%K(yXi1sXf8LcAfU%d z+cO+7C@#n81~_B7&#S)%`@bT*vLc(*X>g(m4}{Uv@6fiGGjqCE$k^JA(_7rwx#yX< z=zLa6%vb{)vT{7am0>w@85u)%)JLC4wB3K@F69OGpjw4HRT&fkq4m~L8&DTl^&VT8 zHW3Xg6%MAABw>rch&G=y1d81Kw1(V(9}8Lct}=Uqw3(<=>RN}ltnbLn3qjgXjs-G` z6AFlqd*@~G9>cz*=!kLdiOkEL{@XqC`S*QtMtZTOZ2TSbTw3B@42D}GNk5~ zM*$RS09m7qlD5P$`+&K}E{ER2yY>~ofz6Wm+Qb0>&p0=B3XT(QtF8hv{M9E5^7_>3h=;j`!Hj)*raC2h|#6Dd4Fgv{oyL4;&)cnRSyRGlQlfr`)e+LLSa0-_cKi zKWFV)S%5$D4GU?(8Q-ncKXfStlkTls+Umy_o}+zhPTAAFr&+cUTj_Hm=`hx)t>C%` za%EO@7EuoD9t8bb6OTEQxCI!kY&7%ktjKJ9WaT6Xk-=pCIH7!7GuCfMlJRMf!g391 z8_M=(S+(^83B4c=kv+lmQV4k{(Y+;j6hNO?*<`2k!wNzP$ek?_PrM>cFy|9sWOfF~zvwf1eT7(M0|!s6Q@t&#B}V zoY<+OmZjhp#zSt=qdV_mD=)!eRkB6)c0pFCI2b(v55H#(j+xf4hf&;Kwug!DD)(9T(Un^Y5Adldy9;IJn?vMPcF73m>qv)9nxdyeLtHu=(@)@Y({MX~V0o?hnBW4xu-5ZqCH@f+$$)irNK3 z%K+SotkxCxQpV=&Bk^Y1v~qGagmOexoG-9$BGNXi02x&QB5q_^7 z7OydLBPQ};N%sw9UW6cwm$65IAEj;E!5@E8)ViUWNUJT2(}xX#lU8ifF%X&OYR`b! zbbLENHx1OOyn;aoRL@Go#QgOLTsQjTQxF8yG&=1E-2LKS7PJQWKaW{N`3L4X1LGFL z`PoGw`bEuW2$t)?#P~U94bEtKwwn^PmTx7S253G75Z6+?rhETs*rDj_;nkb4etEm` zTj<2js!~heB*K_pw+}99!a`nab4d-GGB?xjbW=jr*S$Ei6*Yl=)@T6ZIC>Gl>32Bf z2_Tb%_|1}Gyti{=A%;tTcph+4bmE-MA+RHus%ijRpGdd!TTvC^u4sBDWy9nkhH&Ts z+kog1xSL2`?P|H?%pf<%61g`#Eim_(zO~N^#vCV(ppsp4LpSt-uQc>0u>+d99K=$E z?NsUUPf%e(!OFvHp_78<8hx3`!F`*{Fdtj=g@I&I=s5$c*`I}^+2$;!Ei4`C*)mfd zjd$_#)pk8P--wo2VmUwz&3RjSLVwGqeV|fBxmL_-co458XO`dl`b*?P-4j5cc$-${oYjT4e%b!fBW1B(NlUS(xFHCf;bvP6*TGHrkc6+ zjTcCO09rfF*~ligzr(Y(1{FoqLn@XEn1w5I0p8F!4_m|4JSc8Rsu>S2u9<8Ihq=K? zS}3DePmdzEqw-bLnxvfZCz*USE^s4i)RqqvIttFwffdop=P)HHnB>xR^!#dqPxi#QC1fMY2N225c(Z_dM`qdML#2}&{sHF zTpx@?rx9tvB@d2Z*9#HdG$Py!IHjK@$Ys6+y*DU(;=AJ`k>6nfQ^RYq4IxL3@8|*B z=Bo(7p;B@|bq;BuDkRdT{TTp#n%jjCWEkPJ3Qe_e=!^up4JK7Sq@Fg(LhG1R+nsX= zQVc2K6KIArJnE+S>4ga-`Y7ex1R`rHRDdS};640YD=|bHTj*ygkWP$%odpfT9<6`a z%?74sFSUvr0~bgT4Ixlx^AQA8KeYNg&u9=00+SDf*~*rp24qph=A01r2~`1KBr?2lEF`H`HOOH3ZcURo8sAYs1kEC z>_HdhH4MgWq5o+Mq*@9Z>%r1cw1b2Yf(dlf=sN_VMYE(DYGL@c{Wy)Hs|XhGB76|+ zRGiD_enKz3?H+YP2|{-A5eyx1gL@YGhMkgf?i(zRGeD<<@);EVG3JGMXpB+)g<$~H z2FHKw`Q+$kl%N(rx%QU%JVI3n0*}FvF>Nr2s(l0)k=HS_0gSx_Xz6te9pfN(3w*W^ z8W%Hl?_8G@104Xi`$4Jkp{8gUBJvwJlG1A%s5vjt8H3}Tf2e&Gq0nrNU|^Lg$Kmlg z;&f<*vWJc~-ywGL5Qx?v!l9jj<2@j=g4n1G!SIM^^Ij;K|M^TQM@~h}eR=Y;#I_6Z%9P=(YaoH%beW z*#{;S%wXgKr_CsUT|+Q2M4Yj z=&02KKkP&YKmZ66-MpxBLf*Pyr106bXb4U0fvA>1`{oALhEEcL!%WAF$9M8`A>xf( zR=AOYog%uS^NFQe_7%2^eSy+BLdL=~d^}7((7=$-$j(q_&yR_{1 z0IBkG?T98vby$MHjtZ`t#mDs`vLAge@yU60f_-YVP%5q6SaFVjtdsmW37i1#b{4F#gGx{zoVIjc*Ez4ChEdxpoQ`zZJSBhSqXazq3RFEuyt3=Bw& zxS_H`;0M{70bkJ#(dmVd5cn($QO$Fw^dk7GFj3}m3$5peya8RMu%MryAPtZo&ZU76 z5a0w82;pR)ssM;&0)f*$Xh>$^2@nuiRpptD5FWw+vHRhSX0oA=50jb4f}$&*?dh2i z0SrvL5&ShUGKgAzs}Uu)pq7u%%)z*eDuS~>2|AAsX>Rt?{sg;3qyEHq!KgTL?2)%PrL0RTY&KodrGW;A;Hy>ZfIu z2XM4q2$GeAY6aDw;ystkQ3k>aMSr|@oN_TASf>A`5fo&G<0wx^s&zt)bKG5IyW1Bpwvg27v=z>q2V!@ zg_)2;XM*rI%3V4C&@X2}_Y+h`5pJMf+*A#!s99!s!L&8)W3ISx_Xb ztNapp{?qnsFJDluQD79dHUhE?#33Gl>T5u<5PdC_%e-DsbYytW{>%r`uy#v=QS~_3 zoYjj&(|Mh!I8ovNq6L_ej-dkWXCb__OGpMhE#Ov&Fas5Ye&*TQ$bJL}%@>c#8VT}9r)rCxW?q1rEe zwxA+LWuU)KBKiwIL4yNvD)c7B~WZ zMHF73V%co;LFD4v&}P2CI4rQ?Vd6IN8Rw@EOc)y%rXv}QSkQmR4e^F|kP`XaGWK0?=ruzoXDu3|JkLAP9bisBNnCuTsR5CafT!gAmfD6j=1 zAukBg_yW&Y!7TJ6Ca}a6m~UQ?KkF9q^I&Ad!msl;VP&I;cpqAT;Pdk^#Axv(v_k16@!w{t+xuJj&2e=%Y(WRHhSw{)7e5CrG11B%I$ZV5Yr$yBNj+?+QYWiaILrIWYWv>M(iH;7E8=drWm;_lpPu4&|JnY{-Fw%FEdnAbj*X3JzG;YGI1W3yKh|3tHZBfZKwOsJ=qA zrNKgXWI3@EN~+1JUhR`1*e!F2D)gsPa#nRtLTbS8;z=H%`y>5SWp*I2I@RQ8x16(5Q!>d((*Ra5`TF_p<=Q+#*UxAu+=pA2RCF~O~GSCf% zr@|6{`6DN@Q|(so+7f;B;HT_gULCl#so3(!lUL6l%7;3C+V#h-KYo2vz+L~cz9#68 zUs`8QzE0gb`};3juKj-W;?u^aanGy21t9^Vc3F=JDcodP2!E2*)Z;tV9~|I#?4?z# zQX1iIomlt4sG>e~$=V)^e9~-1VTA=R z&z*k($+l_TO5(j98RO=sAN^!}?lvP?f0_EW^J+kWI+gQsZ(!cl^6ggZh4%{%ZM@7^ zR(Q@emY7P>&BgP{~`RN zyGU#OC|7hc>=d#$xXr9o!_4ciT5X9Y?X=(298n`q4A4 zkzqE}!j%WY!(;bWT~a#GOQ|xv?a2yRG8xc%TyykAM3nh|u`j{+CqZ6FWv=pXtS+CwJAN2j@MqhQ?>K37Ib>nlcnfx~79JZA* zx-=e3_rz@*>v|haOvFF)A_Hx|qxu4eGzLf6Q6b%ej%XMAvsn~Im zFn9FWo45HmoXqB~`OU&=F6I759>e2cO(?;+_^58F+N>F?b^42n&YvxKhqA?;i1L*? zGCf*ruiouwtaYD0`zEQ%n;9m*XFN{it8`L)-S#9>FFJ}X3c%NkDTgVkHbat2Q^c}0 z)#D6ao2Ndr zuE%HQMLqAg`o`~Fp?8U5xEZBO=2E6@JiNveXN7ll9@A~h2m?Bgg<6firc>CRGCqii zGAnwzGw90)-ftO%kB2)6)mJI$=fi3ebO*nks6C-CG0m{mJ+fu$owUhYZs$3F!pAd> z_-6BOcI6wwoz4{fHX2f;vR}i=aI;*D^QXSq3X`{!Gg6Njowy zJqAXsD!GFjzoi%-+<1ZOv_jT==gqUWHJk{RN;=zo%Hf{0)xpD;tNzyO@?YHMHSW44 zMW3fLH~mu`zFn8B(ub@{44pPml&!Zs=|Z@KWf;t=bHnhDB{BRk9cPwkb!q=6_DAxA z*-lGc-2@dP1xI?xUj1l_9oD{UIj_(^K9%aGbNkTvYR9vj*yXZuqKjci>5ESjTFx!q z9Obi)-EOlip(iZ-Ey+GC{^$i+=@~oQCytKm3x&z6)(Ia(Ei121*~E7%Ti}qiHLvln z34xoxihh)BEb_%W?yznW3gaRj9HST;_i@YurKCA3tGE6dcIDeZGWCG)#8TxmNgf|R zdf{b16d#xCMc&+IDovkq5w?Yyw2*s$mC`toy?ahO*`!5-{Yz05&t7xmjtvSE(rLV- z5|QfecZG8f%QGSbU8!$uXQOo<3!X@hD}5F5{n>?npB)>;8tGB-O?=gzjmW;`D@KcQ z+fqy4{dN0_DPc(?eapBP;V6)g$-Vb%39AdRsqphj&XKJ_6p zooB^)*@6iyxjJ(AtGixxhaK+uMZ4>L>tuq=HmkJwdV0!cpwABak7sL~mKbgEY8t;J zznUufes#{u?$((}Deo4&nPM41FrjI6rP+F6QIJ0Yxv@5dS&kwHy!oEW8&g@a(SOhV zuqoP0%@^7%?d3tfCw_CTR;O>45=$SGDVY?1U1p6?y<4c-%YIU2yX-QmBdt5t`6u*F zibHV1($~P=44cHaHLN}nA8SR}JLE5r&m{VU?@jhNe!A4|zF}|0qpy~iCDzh<)b!K7dW?FfkVmGc(FmBe3bX< z)Uuy}%TJTL+O9K3_eRXm9=XJ|{$#M-dCs-{lK;MT`ovb*k6q<5+6 z@8?a0<6a4aa|c%hPi=UpJ!9k8keGb>9ai;ayaHwakxP^zjNczzWpRV=(Gl6^$ zXOgJ~p^CXidi2PwiEfuzO>g%*v-MTf07r()J0YLFinD@aA5b5lkyvQ4Uo0|rd{m-R zD80KSe%frw%=BIFw=P2)Wds_8jZ$mdi2IKcKJ+Zp@d|ucRo3%Se#-q)=6hw^Ue^M3 z*K6f%_nx(S7vLigpOmEI&q}pY_7iSy1}Pu;i{%})nRxZ*q0(|MMUI88+>3;OmKDju z6w_}8tY0&mzMS80R+xSIW&wjMH;OHY>J|+vW+Wao+cI^{ajmn&f*>bV)poFu|Aw-0 zdO*ry$7s})Q7Yr!sl@m*9Y>^7MsKdv;JWT>vlji*7ROE8S06oOJ0|7#hgg*@<=4{B zXDU)U-b+rHkuKR~*H-Nqjr^*0gi+eIj@^NEX|WDmT0zu`VJ3yN96Q|I3rrU&bWn5; z@?93p{*r&1_rPrRr>ZFpwU*G`LCw!!{8mNx_R8zHuN!*dcn>6^@!!p?%Mc<*FAS+9 z+rRHK7XEn_SdRg0pZ{12)xN#5lgY$kOzRX!Vn_XBc}bF7Rq2e;39IWop7e{lE4aO4 zjb<(Tbv$)orA8gqtIP;Ro*_Qn{t&%sw3^}|X;?K?dH7NHInBq~2=i+;Ad=vTpW|W(s|hT@f&dQybFz zru&VLQzvgr=Sk~T^O4(w7v5?`MhXsaXD%!B^gYZ;n@@0GE?d6ceQ$B-jzX8e9^6r> z2(9PT$3AKGHfGrcjjMNDS7GZeFZmWF$s1MA*^&Ovs%|F3LhdbT2kXja%aY@5;UAQ7 zo**KGl4GzsBIaVzTE%Ks3V>N$`42-A_iyBpBK!X~G*{Xh9zSkt;C#jNf5aX^Q0$SF z{|2;3=st7ablq|msU-E*oz%>)1B;^We_QiyKIaX0scxw6xqYO<&0~}PcW)%<2q&hl zY}8*fIG@TmB{!rJ{}orDjIDbp+SWX*61W>%=f*#k@)fsV1zT4s+7>;evZ*I0zxkO* zVerb4EYY@WiIXYsAA6Jp%iMFP^j#B9?&$H->c&^p&Gnd+&^-&p{?8^$gWa2J^@$QH z@i81^d~{rj`6VKHwsDB9g!1NUL5{OULlVk zIYkh}Ru_M}$+QX$PZh=rgR7Q~Rv|Zt8kEL4QLOkIGO3|QNktT;^goIwVo8A>EFmMd1jnYqPdG$4iCBnN+#f0w zZ3~`#7V?ZZR3X}?GW$&ND{j^d|J0X%>ddf;b}Vto2LDu*e@ar1^Vx!}^WvZS`kypM zhaJB6p9$fqZ!GZehdE1hPwczaGa*^(y92v2u%t)4($NC{v|os88u7=}JTA=bV> za0;i?`X^)R&+Q$A3B5oJxD?l;-)T4PKohG1Z)AB zcmFj{!qZ2fZ$kNzb8rFDE0k!8$<2@Z83dR>n2j|q7OdY^Y6sIoml{Yk8$HVrjyR&< zt4(MSgcvj$NP^d%JYa^;=672Np>kdcXMpmml9dtvOt%BKrc!WBwoHG5R-o-VOdYd6uF2=YOP* z1XVpt7XOPnw4-anj;vl*BeQK9!3azy$O5e+WSRI zS94Y?`XZ65H`?90opQUmm!Q0K#YVeSC%Y!fi6y^3zP0Sm%3gM(;fmFJ-ydmye~?H2 zdTa5Djia098^v1t?cj6Jihk>}tnwQ4g4$b6USzf#!@p_K(w=at~F^iY3-rI5@mEAKgqLn3UynnBmI_c>CK6$AY?%mUl7GY8}L7N6ZAc)8}3_V|*Ul(GAy>inGp)&vfGn zSxrab7p}cuA6v98)BXas(@uOgi*91cd)q|m!)B!v2(tFTW24WA&u398a)lq^xi#=V zk!#ji9o&!P?-&mc;sMrA?ih3mE`}!=113@pfamPXB#xBNyr# z=x0VuwBoJ1AwJjm&v48IV)l7JHwpj@97G2Il`2QPnz83M^blPi0EW-@|HIgOfHj$Q z?Z2<%DDSAq*b8EuVU$rsEEJ_>6os*1R0ITsjFm1TB0ZUr5p0NxfYPEOMru?DNR5hu zN>!SG5S31V2qA>@b3e@Yedj&jb*^*%GuH(M$j&Znuf3nW*Zo_7H}#>gp!U3B%SOe) z-L_;KiJ;a~YK_>4h=KVH6yaRdtPpSVK3MB4KNyioOBcj*faYo7&&~=aI6(LVeS)O~ zj*@*ZcbI&T39t`850D~%Mw6*=5-GCw;cc1zw{mdV@6s1_lzpJ{J&?^{~3j7n*RSy zA-ZM<3elkHa42`antSuVcVrc2r>8q*oZNl+LsOeIPPy)cRqggu7kTA5^k%i zp8we5Xwn-}D+*8qaz=k1d8@0{Y$^@D>f635@RD*#Yr`paMdM;|!M*BuQHP)SNnRh) zEBEM|K*C|u&yJppMpUBA4WcD?Ie8x9X;+2s0SRGOYZ1hj^)A&llsd}P z8mS55-2)rF5(k?tnp)=&F^5BqP*ElC^8%B4Q$eL4Vh%fQDG|7oI5c;D1TB7GV00St znBJ|_sH0q|*|Y2_g0pix_nSZ;@-`v~>Y_91T8Qe2PmQp<7ooS-ZmlslY#5J*H0*UC1yA#mD~LLut5-(Z$pZ)oVkM@KjlX=E2d!B&;pAhKCL)_D(wF>90Nh@DxX z&$t|DQ*1l)k3!vUyK)u5E!cA^K7zLNvF`{@kFU3-&4w`R%_^j(&+?dOixYOWlQLW@ z74IvYi>e9Bej-Y1iy?Fir{B&H3uk%RvOQ&Hu2*`p?+_~JO+D41^-M{qAkY8>K|Kfu zIQ~ZgcnVE65psn51@n<#(l7baVdTHs>lQ%BP#N{6RxPa1&FM3;$*q|;>5q77I`Qj& za{_3fw(dFTPk-t&LJ+@m=9E8DyT8&_-a)*d)AD)e5t`?hrHL_p5j+i*6K5$Aj;C-F z?j{7)H4)#W>D4ptY&jefYVN4_sL7-XjSW%c&cv{86d;iM&D+#6i1^MdUy#CZSj6)B z3*{+9YPd?9cjpqWavp5-MtG|%bikRAREHErf+VqNW~=utlE;;xo^sfaBqRumUAO15 z89NZ>YRS0+o$QD#5e$jKKaPO;AdM|UoJdl|Fc)p6<{w0?+eFchX*Uo_X5PjDxqcI= zh!_b6k~N33tG>506q?_uC#S1Gk-lu=>u*vV;unM9uSeuao+O3?zu$xVq)Caw)z#Ljb2+|UVMB4p5_ z7Q!x;Q!p$f@EhYM8Y{48ph3UrwIyGrNj`tA{1p+socuv^vQB!_7ocSx)~d|ITc=u3 z6A|a}wBROkqkkQkKpa|A|I|2y$JprOUJ@q5O(tQ!`I``KYI&&N*Yco z%!;Ri)9`lgfFkU}SfD5e!JAXe$BBeY_VeZfUgVQ4@utb4pq8LAOg{U$P+C# z^9$VoDaGo}B%m2oW>$U`*(HcQ%4VRcFZ`{DVQrB90mRkwUTx%&2wxkjP(xGSii$9< zTDfl#tfafV9yqFk(Dr;Zb)NDUjBBFoSn(TC&`{Wyq7fL1?5(4MwzT!7%xhHi{_aCc zWcsM6n>~fGcR8loXj$r7sAp1Qm=F$B7^q^B=}vqFZKyYP$1`%aAIbO(uGKn^cWPQg zEPpnDRfMqo8inx`dG5FO7v~dd)XQ_6(Oi-!32}3y?Jo{MhoG_zK|2nX7BMKUcBlo2 zhJqvI28c#eWX=>kM|W}l~q1hx`vAG=@h?zwics7NxQlci3G*OrKUSLw+2+^}#%JNOKDWO?bgFsy7_!VoPHZ^`9i87F&qWB_ zT)iK{?WD@!0u)wM%7YYU4pp=*F%df6f;-P>?wiOV>Di3j)4T(R$!Yza`L<4Ex8K_L z_{ksq#K=F`Oj-KmEW40)z=LaoAC3RuozBzpTX%|?&1fhI%`Bv?iJTW)28U9@so$b5 zVBX;m#^kfY^G?6k8Xa%A`_TXW*!nGGuiu0o+R$r{x(U}n7(8)gU+ zcv5Q&vkW48`J$Y=4TYE`DS?ZHr#a6U%H$E3 z$Ts9m;pfZMAp}~o_@~;4dpgSk_9d%?#doaU5C1WB*(L~2!u2@s=Ob11*+`&6n)X%@ z_otkojR>FJ(jK@Nm3ub^2er90YIlP5N!?eZX$EDG7(F7R+eETl!GEu`uC_>>2tKYb4^xLzn zwmOzo;Kn%!9Psh`4DiuQ|Fw=pSrn~yWKGshH$AKfZoNLhg-f>xIpe!rlE!{LO2WER z5~T%Ib%jYNlH`^=Z(M|s-s}U}t81eSx^t&Blf25`woU}P&eU%ALsOVa{0bWl1AtAA~%D*U?UDP;8Vt5r1uPQ)kEkA8zMY`x{>aaw7e z@Pw=;BC{`KQyb*aK8FTG7jr}oN-c3fF;jJQBW*s~+NNrTVR$$Xi4ljK3@uT+2&WxCHt5v*OGHu{GFpmGr6Q5$tNkv3 z25uMFBh;kH!n~&ZO)n#@q<%()vskvtk0x|s9U}fg2`*GT3Q^d*$wm}^B8=2ZJbHVY zT<=)_AodQ^wy-;oll4pT)m{kH9F+8^PO*yD@3(iGDu2_ApLL*?yw5{!7S}CevGW<$ za|O(rDN-|p%m$ARWg*mm^U?Y7kQRSP?=(UPDc{Hp+p=fW#ebtKOYTKmDWnd{%7kXb ztiQ^Cyb9XT0ovK`A&fCfS_6%&BLzFIfx)6cT_E{n7rw(lmsy=$SxNKS6%+idr19j{ zb*sIps$MT*=1tCEQM%+9V&N&ZLQr|u$-JLnqj!+y2<(ePPGJ6G0Cv1LoK;1L&bYG= z**2Lpu-x}Pp*P*!P`6M^%3i%Sg?6i?^{PT7ff!4s@4W{8RP^;G0!rnSS<>&JF%i51 z(dgogWFPdWyO3E~+uWM4Lm38iSZ#qV9JJ*i|C(4klFQ2?c2y;D0}QQT_7bOa0d!HF*~o+cf`TEW6}p<-G)QAu(AyrrC~M)_r>zzNRIMu zU4-^Im>GMtqxEW!W_JkM{P4h;+C}mVL|@aYdg%H2Eg?`w>%cyAL3VC3_o1m^4|& zwb%@alFrV7-jv=g>}&2&ulp{_pS@&!lPMMvi%8H$Qv2nN=MlE1(B?YYH+-&`zlyXuQvMBCsdwrt>nz(^YRfmbB=7XrGt zl-A8$46x|}>PiG-w&XexLFPs0mRyF_n5H^j31KyN2(*{s*@MRV;D-eEqFNVhzk>YT zH^Q6JTemHO<{?=+Dn4hePGjxY7_;{Hmgb5lqu_!u9jrSB5QuY|vD>UOx#kVKI}5!M&bMwTO{N2wEyjjm8>iuvMfv=VSL zd-8o#Nm@~8SSt2xMNXtFP)<4`buUyn;y6|fIWKhrHWiv;lK5}p$T23GLB-g_6r1(@ zj1c$}K(sJz`9sH!LZVjkDu#@x>zr$G)Jzj)LwlivIw7Ub`D#ySl*_VLv}9OuH!TqL z=1v<=4^aFa-=RuUwIBM_bt_CQQtTrOM)HFKUyL(i?KId{iNb$Fk$MNmx z$oBiUf)v}`27mRP3JrCAFcr`g4&Wc(NVBT#&$H-BMa%0h~@8S z?m>3#of?`wOd)^C=(X4G1uZa96ecG_E2v(B=}F6F+r<(DMMe3B`4ltBVt=z zs6&CzIW-XDyq3k-bu2?aAPLK1fY+6LykGQnqw>nGslX5rZOmnA@L89VOvl%)7 zd&xe}sV$Ut;Q{9_vR@-3OZOAc64@gEhZ8~J2J)P(mgrd-S)-Z2ZFmhif$XO2a4uGE zS2y|j4I!vd%)<+hzy=LI`F(2%Gfl+U=W=PWP%&>HJJhN~x!p~6U~D>;f8UDaHNotD z4Q_eo5if=J&PHO%4od)tR_Oh#_!^i26O~${BTv&*scv}{vb1iRhY78z)%jYhE)>c} z&7Vhdo18lNBGlu_xX()?5L%L+Wg*J4zBu%-+&-XF_cr<$Bb1!Aqa==b+`AitB?&YF$wC~j3Mi8N=_n* z{Q7Lsq$Nnku18s_dKGqe;z33Bg+&l`oYO9?8|h^Ub@!h*HWk9rPwodaMnqO#6NZaA zPb<>8FPA)p=NoD%GDq-ZJ^eF{@OvL-ULm+1=ci103)woezq1As--p35;?H+X$a-YS zK`J>=f%=}woCCEtM}IKWa=iYt$c$&Rb-ex?OGHjzSxaUg9`lw#SDRcV6^xT_7~Lbe49v<2%r(iw1_*!8+&$1#YAk zip~#F(;M&!=PH)h9~!r|R211`7*FvQMLNDg!OyDS`JGX;b~%!%M%q%hR2|1%}b#?aD^Zm+a1n0Jt7Fq zqPEs%bcx?jkE?!kSzumfoVWR+z+A`2r5Ta?ZNg8MnAbO)&1OKT8rF90wfNr3UG)AN zRL0V`8J$55*TJr}JH1;hcNJ)g#-ic`sPz;5udhTR2Tp_AP{mu?(!qlGUrMRg>Ky}F ztc8%lRo*zZV^rGQI+w)Z+Sf3QlDG7{33P2&Sm}<(3YaT*jh(r)JbLNddB)I{SvmSX zxg$H2AaW1k_uOa1I~QfqFOun5)X_f;RF9KY^OhCh`Ee?}}D7@#>b;A>6zXx4I85kVi3GvJL z`&7r5?qdVG(in>~opY$oM7Nybt{auU?~yMuGI54doW(YDoQ1maw^hILdCHg`Y{fS= zhlM}#a6=D24Zib!@3^(&woiMYp!%H_l2!>A9TL*xt==$QEInpB2TNd)S&p?jk!0V>wS9cTrUZJ|25yf;1D|d z=FQ|4xNZZkDTWoj{h06p59{9GZyl#)}!96+Ve6k-v6v01<_LK>=SCZtOtVFWk;g61nwl$2x1Kw7f*Yr|McZjFa zFjYD^MuOVAjE9Y`!B{!@5rbNU*E>dzU#ASs;>JeWiurC~+1*)@adJJAM^2Ffn4GQu zGvS_b>$cJ#7HmZG6I=9trHotKy%U?hhSGmDIhLTtCMg`};rU2=2yoeW!~VXtMCTsy zreeKvG%mv7Ql0pL3&eHKY^}Q}vX~FfUYqFyoRnxDfn>$nZgfPwkC~j=X0;<~XJlKE zE;NnxFHfz6221r0G{C9-`gQYG5j{|;!tz|vO9|Vn!TOm~YOuC8@V8`A)`^`ZquBf8 zX@r)BIKm9Raw?=gx!Dg&3ap^=)*5=bXwz|2({ybx3H&tKIRo(%1Acv!0kMS?uDg5< zHsHNAq8A`Kqdd2x#e>Wvx-+(Q$=I*P3YkE30Q)kQ;8Gu(aUQaUcmO z%ELf0`V_^wOh>uA{0dZJkwfH(SU`4X1z=A z6k!3a`d!|{+Vqi5KUXHc7u#}AvkT9fSs5a!^A`HR#mMoSg1W+WRpM`t63M~`p5+4d zhGz=|t9w|XPhMsaDOx2gGSPhY1Y4_zA}=rA1MzfS?A~LL1RiP5n>eCq*eG9_On={M zYxe}(!6z(hL+r_G_8i7z9c7gA*BP^hXZiu}pb#xxT=XjzXja3;r-VIO(GTHIIQRTB z@Tl$TB{v`Cd6d=EdR>BVytRnZ)$8GlspqL?W=dl9)Fmr#3n$?=Oe*{-pT3kxI~k@6w;6q zVK}-Tr~L8GF-zY{Ggv~Nk#Z3x{vDA!WZfDey=oZqH_;2gZuG6kIgpV->?b_Q8ht1R zCffH4K=>$*Dgp4mx8>4pj)92#`ULT``R>+goDVnCUY$c>Zh!4E$>z%pVb{4rOS?lwf$|YaUu)=jrG5bg5j=v*)Ed zigebz2|lzYoi1Z>%s^m-J^O zxanhiFW<#z`5QRw(ob!`VMkk%aDQ=DS`6_tTh(#>{N4zolk!qB;nbTtw4vBZE@5r# zZf2HO3u}F7xwT&OPAtZ>1vDV28p$f(~s^Cg2ArLXO@LH1>=?vn7hVm$nKgy7HHCgWzBW ziT2|h{P8`$0t6rNBO6=}wmrY03B;N;%?x)`4#}S}KrP7|HJxjyZlBhQYBsl|gq|C* zUkE662GX$aGncwMW=y8mP(XUI*K1!%4p0qc({Isnl=9)>$Rg|)n)m`IeA{qj>)uSP zZ|sS>BD~D$9-v{-Rex*hQn`F6hx>33QpbBuyoL#9qBEse|Fsz3f&zPt5t z$CLo&&8E>KkqitBsD<*~4iz8Wh@Y|lQ0d@25PJT;d1bG8q`HSzCOGAJb#t+PIkF9g z$sW{D`n)JnT7QDPW42h(G~MQK)4v7GBP4P;oz7$zD>*|%H8X6c$-V zVObBBL|)VP`1iFVQy1bq_@w-ze5ylj`r=~Ft)+&$NV>S(%rsBJBmAekWT;+BC1>i~ zAwnH1A)Obgd4wgFbW5GEAgBO}cqA+J38_Pw&i2c0K~{uoTiZuyhq62*xxCwC;aX~& z1Kh-6N?}Bx2cz+Fg(#)^ZNe3ink!ZKsBJEuCk*?=%K=K9uPD8QRcmHYNYt9MyLI6mb?WA8#Tp2sg0Z!NR;9R-5xzyc$5>97T{Gf)c zI?Bq#*9^n0Np$zLXvsoJT2`bNj?Gf2^JF5XL-XH%P4Fq~ zRG#1zw?=rN6RseawN%Fb9((Xom)YmQ$^Kkfr$Q_)?%SgP4@m8)_J)%sNpSjXBx$(( zN|xr~8I_F|S8154VO(ry*@FGNh=azPa5~qtws!^UXxDNSo3%FvB&2&dscM2N7@wi?yT@VKg_|B-#$5JYziNhj zEQaafh{cMlY5h&%==HgNd$H11-L`N>2R(y*(5MhViY7gM+;+aNRzN`R@v&$VNYwSg ziNISt%R9QfCThH2P5WDbMMBPrvtVu8Z9PE%gCxVeMOVc2&u@KPNVGQb$R!}MZ*k>N z!)3j%HUZzyg^p8t{YOoEuQowef-!aF3@}YT%q{kE??UIxe1fbAU-{TYjxv zd~Zw6cQtnz3(22i)*!D%sd@$lM}vE0O-SF<<9`A>y40=%#q=E>8NP$os2R^v{XNA= zK8R}y(_<+$M0S>v0|#y41a0|sbLDz2RXYMr4Rc>Nm(z)Rgre5VJhs8Ns(*bdbv3^- z+bK@&aK)p^xr)*1uCT>%itCLrTv23Do_nIDZ$`u5va;9tJ-o*-Q!QBlME0gX#1Pzm zweFcl48v>tE!fgs^mS?D(wg%{F3K-AM9j1D(T3g4FA59IY?~ef%s z#fIy%Sw=C(%iY|1ddOd5>)mgd^N_|zo6Mu&K5gmH45HUPVOT3R@Q~2Sh zVN2vHrw+fUHBabF3`gSF*T*_u)<(pahLye)Kuc(2*a{QYlYWG^+a zw z09m%`;o>P#T=qS!Gb0mD>USFRAmglV+Gk!01nNLXTfIH&dQ)_xi~%7-slRR4zE;V3*QD0h@HlQ0Ep-A1)0!z?+iD zRX4~~^Ms^l`;!fkV1?yGCp^BFlPgq;dnfvE1=u$p`H_4#QfA1w*-_-pk$lSp(@+JXe&Sa1iMR+!EXfRLr^oeFXRzPvcUK{4%O~SpY}EDT zH5G8E*XtUw&5B|9BVfUrGtZfOuRQhpB9kaq=;0@ehDokDmgi=ILVBm~LUSB4k36l! zmEiLx&b#J>Jzjkiam46;>PW*Wy|CrPAgRtsM*S-MH7jEe@gitIPq~#?%;OuM&yc>xje^t8X(IE4gBhDqDXzn$~uCz>?LGqE%F*~rSG&*#h z@z`VY^!Q8|w0n~h7fqc9t_{@|LY`=9OG1jMRaam>8GOg4%knJn(s2i*2Qy7 zxCCf#*52{$ zhu;R?ao}Y&PVimWDrt{FM(=LuMT)I> zGdCs!_f@gl#>mc-+u8RcBEGzp&bSpSnd63&BGVEAJY;v8LnVml_h_DpGXA36w4KIw z7b|=LMJ;Y#G9@z)&h+N+!hFOXM9RJ`zzc_{gRgmf zhv1`&iWS*@W=U6@x$NbftN?k^(%w^gbHzvLW>y+S>p%ea5E@SKzp!`cR_fw-WvnF- zNpjqt(<2)cl%-3zP&>Gr*f+{e2eC#S+db_qZj5zv_esfVoBTEptGSyxYd=v&Lut*$ zNx;K%R}dNqIe%rZOP7NF>$sxU92f(+65|0x5g)7q^Qo2(ApeIl8&7i|r6dF~lI!nk zOfnMUfUAE3N(Bg^_)XkeDOCStBYdGRBIpt%5gBv`?stUXyFyNx6rD3#-#E1SC<)XC z&ZPi7z{Uy~i?sxDfd3nTP*Agz>op3W7%A~CyI#h^q&t5L2n5XQ0EG=fj1b#;{eEhm z2{{v*@yYFLdaXPyeS{M5q>rx%&cGjQO_uWyDn(NQs0v+=s3La?(U`bqmq~bqSOtuZ zMU$T^=;AQ(=H2fEgq9r?MwEf$Nz}XOKX4nHC+RsG;NFKtPjGFmpN+@BT-U}E^Crmx z0di~g$G&rt$<5)PXcv2H**9)Pj>roBhnN8R5yBq_kPr?W9h}{PxUdn|%mhwgQan$d z{MZ25wr+)TKI|3@1QXi(@WZB8Ds;hMAVpC@f1u;Z04Rk2_z8JA2gArwld#n+Z8AW+ zu^Dy6QuhAuzq}?nIHZG%h*m4XuL@6;W=)+OdvDxRqNTja*8i7kANQh3hfU`L1Rz%? z5b$EsIkRG7_~jL~2z>nY9i9~c=TL+=t3MtrLDU$*q6oaxdNHvgal-aGI4SChI#?CifUgHYj=0ht;an8+xWgE18?)8A4IV%3j#oek0Pc*hc01O-Etek z+-oQ45I#!6h;e*7`3{1|C7PsZMO~UiNd03tZnue8#|_96`b0^;X(OC1S7U^h!RD6rpqCM3g-sWN;S~z0L?HK1GRVG5q8?>Kd$coHVUfgy|@MAUaDq zXL5?OIIgfVaR8UV^gMY3NdBZ*$}9psB%LIADYPar z7#UJEe5##@5WU4-7f1}UTz9gA4dID~m8@00#GD>c z%p=+$Vh}CGEi;@%3CA!XAy7(w^8fi0s*^I!w{g*b|D2$V;QpInf<(D=6Mk7)8%rXFEE26BRw81L zK!=$FsEzr2V?z26eZ>glY2g!k35Ub+Nqe9h4+KDX|YzmgheI1$3H)6ROk^SBJ@Bvu*R9I0RY+k6t~CR{-xJw z@#31&bx7@`ZKgp?NoiCC2d;){sz}8L2g!D$6ca@wYFj~^qDT3C{cnpv)ydBEduTuu z_AOGfXFJwk`@p%SB(E=ny99vNNR{)tIV^-TKG2=S%G6JKdqjg}v3qrdvZ+LW3MMTF zF=51KD(?~qm~H4dsP+hp`sWMbbA%X(|Hl`PWlQS?%$|G<#;Cg9VG+%wr*F`Pb{+WrpN2F-3@)wx`@FAtuVKPu@AgN`R zP)nK-H+wbF10kg|i>z##DX*;Fi;r42Q_#~HlLLt-WK?fJ zva`LC_lU>D%1CmsO-4ePIu`_k5#tWmHE~2+t%n65lVJBdu^T=-3tXWG!xG7)JLsH5 z)F{`G35Um=G*&vGh{LZJtU3mYp^_efqz9`htJt?nh~a z2N|n5lh7~kN!E?sq$lv7^g3`YSi;wXnA4#=dqY>G)VAJhc@TxB`=Z#$(@lNk7azA0xD=C52*HR%<9 zK^Wh=#8y0CT(zp`?$m@q*f0Lp$e5f02oRR@+mmrl{58OMK4CZDuQjx~J~G9H1#G}n z^ls9LDR*aXjsl8@EF|I=;cQtiW$e{d1sf@^j`e>+$iw->poJ~O!ha+{VarqUe=wnE zsQxgIwYE}Vj`+oLLB4~B+*K&knKa-0hAn?^f)ufZT1sXz(!p3(9k9k0b9I*4-rva8 z6WLb~e)U2gmpX|PGOm<1vxJ=D6Y4z_^N=fDaxZK3{rP1(CmmxOu7B{UXJLIVT%7>Z z!@T8mpBaD!4$2uzbg(t!le0yrIn|jv=~5Jxyn;{4C|)6a8!x{}IkxOD3xA|s+d{au zB#bPdUV+Fll(}FtvG6L@CNX|7NC^YGUO-@ps2$1gCTV1G`BC989)Kz_*_3}z2#A$Q z;~(>jAQls~NqD8!r0c;+Aj}t0x^S02V2u;e-JT-k+Buz6Q)G}*Ier2$pwgl@&7HIG z#zmb%!^tJ2jc^zW>0!L!{74KCb&``vom>ldPp;YW_XGo~@?r=qj#vlZI(u0N_Aken zSf%prQ&(dRnL}5=)Rq4t5Kwe+$Q6Q-raQU69S!I31H!;v*+H>Td_Hkt27} zoa_q{5*wgfHO7dM!m|_p?LDTgRHJRS*$ULry#J6^?fGwM)oAzsmR9{Ap^i#__%F5M zCy&!MjSE!1{W`JjR-VJJFZ-r!-};xU_T^(E!`qi@djB-z=YbnDCNd}19Gs(e&3ws? ztN+%yY_T`w?%m&GEdQGS@zvKKx4ydHedN#RU&BvFe-eBYeNvy_Dx_9WlKS;%{jM&d zl5P&a;B9gYyV=z6rw1=@Eb2Rd{`|o_@1*l1j=YQK4>kmrhDXke_1(+;knDR>nzOtq zY>~<@JddI^$LpVTgxzt<`8f7yWJbZ0&I-?oS933q6~CU>^7!j6m6lr5^grr1nd@DR zm4)3E{*iRPzj@*5nopbv)8Ys3UPx|iq37HkGEk7?>Zk&HD=MK4X>ukf~=&r5SCdUOuUv{q3x&OQGsnM;| z1gzw$Ex|#iy@R<=60K^r^h2+|BR^?8f3osyf-gri^X)CyuG14&W>@8RyxrnVeRMr# zbkpYE18R>Iw_9@eFql?1&OfE6ktM%LENgTnzxC9L5*aDlrVTnB(%mXOJ=FVKbR!R0 z+w8c}Gt}guV$n$Y<(ln`Et_fVX*my*S9pi+HLou?^rG(q=g@lo@qY)&T-Bpg1+$H1 zrg0@kKlhDjRC|8XJzkv|*K)XepB3rB{dbJb>x0Wz80bp#pDjN?UlTSKl?c|vW)+@t@AWFaEz=g!hn!G>G$(c*zDc4pN>?U1U_S#yn$}01C+5O{;o}?dU z@cyH{&)>+NOqk@Jru8_tBp>Foqbh0>M%oj(_XAB^^KQqw&Gs&R7v8fxwS}rn8EiQI zlZ#Z#*C_eW-Wxs2#gwu~749`7+1m5Z}49$TfT8de2vpRQz1~WhS=Ic60{id<%VjEvWgz z`{pQ*K2F2d7vDNgeD9R+pE4~)h3nrkyF_0)B%aY@?R$9fC(|h3v7oFAi9GwVEt^a4 z{9G-#-@i_8(XtPNm!cNT%3mpc!ztKoPtkaIqL9|@svh1P^0pvQ!8JWT`RRW=pwDmK zTEn_x^hV~^BCFDQ`|&Us5^R@NWxa@{>zs_!Vh7qM*ijI|$^Rh`)^YB^CB zFuYVX#WADh6QgO(KOen9F6cDjj0h+N6N(Ewe$MA8FNKUVM3%{&B?fh(lvCHkx9->6 zn#_>NOh4*h$+>e=CLMJ>L06B8$QN}9C)8B*pVH-m#IP-Xv(FUwEm61FnmV((_Uch> z=O-=AMvk8S7K?h;MAQA}``yX9kt51Jp3?2I<;}?TtV_x!^5oE)OI)s7XmrWIydudE zs@mv%H^PnP-}7k7MAXpn2>0&?o93mv8i`w zt@hgE%7+`1G8wz;q~C>Roqv(6Vc^0$p_)?J8aQ~(d3M#F#u?M2D>q9iPJ?HLoxi;J zmZzqFOTJrPpoX3w`0<@Mbz>dZ2}mW{gtwr+A&b4A^)M||XYsj#jC)%I7KpPQx?JZk+m!N6Ka6(s^oxYMrsb3*_ayfF%>$L{f$e5z|#%7ykHf@BSAYTiFT=lRiFSABwUXxg)E<)vR(6T_0T zPhJ+1i&R)r6*Ir=Od##e(sZ3Xqao*j`Q!$K0xm$jcs+PVOeM#SLAxq!Z-OI zTo<2Fz35E)hau7GuG5|VBL0x~!{2>FxU=J$wfvguKH1=uXUM1K#o$}dL(X0E>w*g9 zM`~zRXPiC?r(O_N<*58yBGX#Q(zFa(DUu%H7ZeZMB@T>qcCNEoAF%oK=Nm^dJZnl+ zd=WL^cjJWe0DX9BKPl4ajW|YJ)_d=QpuWtRN>Vu}1`KBr5rD|&&$h~S32SLMx-%ysqajg>3Z_qv}O94Cxee2+uhxpjy4{hKe?6?Udue<{@RmeU`;CB~@Bbc^FVW`tYx~|P zi^^NmCrW(2MdKF^<=>w&bTUZ_!2y*f^2GeDRJ(D$4;ICB1B7o}6uLrS*`p=-&6(3B z#0!zy8D%-XF=h{}5Y>{eigd-%x_%?_H*t|#Z#qKfUoCe!o}=YQ@szy#GMHE%AF8_W zDb;>k9oO;No({V^wKGkR*N3iTS@xWqSx{he@4Qc2k>_n4qp!b3Q)s26juz@q70ejN z^~P&fxRT;BegE)P`gopveolQ$=Iyk5gVcdq`3kxD3BqidpSF>5&(aJ;!Aa|wrFWcp zFF%zClNQ(gU%dwoXS(cm2&^kUWL2jWjJHggmST7ENzaAd`cLus zQD)Z_Hw2aFm5Od7tXJjgJ@(JcI{YKP_IkPgQJtK0ss6HlQ}rxv*!#SW%O$Q?_l}xh z3cH!85p=nXH!XFcUfC+Q#T?8Aaf8o!v)T#ivWedz-;@J^l_ z4UFfRbuL@G_;r+}P_VgDk*esM*H7B=52nzY)>9F3Tp(`QSoT*>!h-Lsdz+@tpH({^ z9TK>!UPbxcAs?v_P>{R-u_d(n*T4VaSI8#*_m)tFYJK9^S?@FduUwF|pr*(PF37Ga z|Gg*NKl}V|z|3v`?X{HK>~`|o+>l?Qg>O|fJ*D22Ph~92(07@eY8^JURXKa~+zxDv z53CJwuTI>=b=cJ0EtQ)o$iup|5w!3iS}S!hYHVs~xo>qKVe(68{q^^5jmthyB%eO18Rr4+NE%PnkY2dNQLiRoR1?5|G z;)XWTP}I1kG)1v()AoOUI1k@0S$@D(-ar4lMLl5L|BwIAGX$2hIrLYg5lh+rn(JdZ zV>w+{{`>z#Qoq)~HqLWDt+44&$l=ddwx)FBlWxWumil)Con`da4S8R1d7En$;P#+SW#2X1va^ro&u# zRDO_ivxnk$ZGc<xeagNXQATUKabH_H|)*H14i>O-0^21WY4)a%1gXv31FIp>
  • gs68>dOk=Sz6XfE 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�U#qK~}zq!Xz7275A8 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
    6X}zPl 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 h#Zrjl_M!kDEhVnPKgVps1QY3(jYWRCwu) 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 z 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 #include // for SubsysReco -//#include "SvtxEvaluator.h" + #include "trackbase/TpcDefs.h" #include "trackbase/ActsGeometry.h" @@ -134,24 +134,6 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) 411.53, 421.70, 431.90, 442.11, 452.32, 462.52, 472.73, 482.94, 493.14, 503.35, 513.56, 523.76, 533.97, 544.18, 554.39, 564.59, 574.76, 583.67, 594.59, 605.57, 616.54, 627.51, 638.48, 649.45, 660.42, 671.39, 682.36, 693.33, 704.30, 715.27, 726.24, 737.21, 748.18, 759.11}; const int nphi = 205; - //double phi_bins[nphi + 1] = {0., 0.0068, 0.038675, 0.07055, 0.102425, 0.1343, 0.166175, 0.19805, - // 0.229925, 0.2618, 0.293675, 0.32555, 0.357425, 0.3893, 0.421175, 0.45305, 0.484925, - // 0.5168, 0.5304, 0.562275, 0.59415, 0.626025, 0.6579, 0.689775, 0.72165, 0.753525, 0.7854, - // 0.817275, 0.84915, 0.881025, 0.9129, 0.944775, 0.97665, 1.008525, 1.0404, 1.054, 1.085875, - // 1.11775, 1.149625, 1.1815, 1.213375, 1.24525, 1.277125, 1.309, 1.340875, 1.37275, 1.404625, 1.4365, - // 1.468375, 1.50025, 1.532125, 1.564, 1.5776, 1.609475, 1.64135, 1.673225, 1.7051, 1.736975, 1.76885, - // 1.800725, 1.8326, 1.864475, 1.89635, 1.928225, 1.9601, 1.991975, 2.02385, 2.055725, 2.0876, 2.1012, - // 2.133075, 2.16495, 2.196825, 2.2287, 2.260575, 2.29245, 2.324325, 2.3562, 2.388075, 2.41995, 2.451825, - // 2.4837, 2.515575, 2.54745, 2.579325, 2.6112, 2.6248, 2.656675, 2.68855, 2.720425, 2.7523, 2.784175, 2.81605, - // 2.847925, 2.8798, 2.911675, 2.94355, 2.975425, 3.0073, 3.039175, 3.07105, 3.102925, 3.1348, 3.1484, 3.180275, - // 3.21215, 3.244025, 3.2759, 3.307775, 3.33965, 3.371525, 3.4034, 3.435275, 3.46715, 3.499025, 3.5309, 3.562775, - // 3.59465, 3.626525, 3.6584, 3.672, 3.703875, 3.73575, 3.767625, 3.7995, 3.831375, 3.86325, 3.895125, 3.927, 3.958875, - // 3.99075, 4.022625, 4.0545, 4.086375, 4.11825, 4.150125, 4.182, 4.1956, 4.227475, 4.25935, 4.291225, 4.3231, 4.354975, - // 4.38685, 4.418725, 4.4506, 4.482475, 4.51435, 4.546225, 4.5781, 4.609975, 4.64185, 4.673725, 4.7056, 4.7192, 4.751075, - // 4.78295, 4.814825, 4.8467, 4.878575, 4.91045, 4.942325, 4.9742, 5.006075, 5.03795, 5.069825, 5.1017, 5.133575, 5.16545, - // 5.197325, 5.2292, 5.2428, 5.274675, 5.30655, 5.338425, 5.3703, 5.402175, 5.43405, 5.465925, 5.4978, 5.529675, 5.56155, - // 5.593425, 5.6253, 5.657175, 5.68905, 5.720925, 5.7528, 5.7664, 5.798275, 5.83015, 5.862025, 5.8939, 5.925775, 5.95765, - // 5.989525, 6.0214, 6.053275, 6.08515, 6.117025, 6.1489, 6.180775, 6.21265, 6.244525, 6.2764, 2 * pi}; double phi_bins[nphi + 1] = { 0., 6.3083-2 * pi, 6.3401-2 * pi, 6.372-2 * pi, 6.4039-2 * pi, 6.4358-2 * pi, 6.4676-2 * pi, 6.4995-2 * pi, 6.5314-2 * pi, 0.2618, 0.2937, 0.3256, 0.3574, 0.3893, 0.4212, 0.453, 0.4849, 0.5168, 0.5487, 0.5805, 0.6124, 0.6443, 0.6762, 0.7081, 0.7399, 0.7718, 0.7854, 0.8173, 0.8491, 0.881, 0.9129, 0.9448, 0.9767, 1.0085, 1.0404, 1.0723, 1.1041, 1.136, 1.1679, @@ -183,19 +165,7 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) //R0 sector 9: -2.3456 < phi < -1.8432 //R0 sector 10: -2.86919 < phi < -2.36679 //R0 sector 11: -3.39279 < phi < -2.89039 - //R0 sector 0: 2.36679 < phi < 2.86919 - //R0 sector 1: 1.8432 < phi < 2.3456 - //R0 sector 2: 1.3196 < phi < 1.822 - //R0 sector 3: 0.795998 < phi < 1.2984 - //R0 sector 4: 0.272399 < phi < 0.774799 - //R0 sector 5: -0.2512 < phi < 0.2512 - //R0 sector 6: -0.774799 < phi < -0.272399 - //R0 sector 7: -1.2984 < phi < -0.795998 - //R0 sector 8: -1.822 < phi < -1.3196 - //R0 sector 9: -2.3456 < phi < -1.8432 - //R0 sector 10: -2.86919 < phi < -2.36679 - //R0 sector 11: -3.39279 < phi < -2.89039 - //const int nphi=2*pi/((2*pi-0.5*12)/12); + From 5703baf039a748ffc6b85f1105025a1cb29d6b68 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 27 Mar 2023 15:53:47 -0400 Subject: [PATCH 039/468] split `TRKR_HITSET` by subsystem --- offline/QA/modules/QAG4SimulationMicromegas.cc | 4 ++-- offline/packages/intt/InttClusterizer.cc | 6 +++--- .../packages/micromegas/MicromegasClusterizer.cc | 2 +- .../packages/micromegas/MicromegasRawDataDecoder.cc | 13 +++++++------ offline/packages/mvtx/MvtxClusterizer.cc | 6 +++--- offline/packages/mvtx/MvtxHitPruner.cc | 4 ++-- offline/packages/tpc/TpcClusterizer.cc | 6 +++--- offline/packages/tpc/TpcRawWriter.cc | 6 +++--- offline/packages/tpc/TpcSimpleClusterizer.cc | 4 ++-- .../tpccalib/TpcDirectLaserReconstruction.cc | 2 +- offline/packages/trackreco/PHTrackFitting.cc | 8 -------- offline/packages/trackreco/PHTrackFitting.h | 1 - offline/packages/trackreco/PHTrackSeeding.cc | 8 -------- simulation/g4simulation/g4eval/DSTEmulator.cc | 3 ++- simulation/g4simulation/g4intt/PHG4InttDigitizer.cc | 6 +++--- simulation/g4simulation/g4intt/PHG4InttHitReco.cc | 12 ++++++------ .../g4micromegas/PHG4MicromegasDigitizer.cc | 2 +- .../g4micromegas/PHG4MicromegasHitReco.cc | 13 +++++++------ simulation/g4simulation/g4mvtx/PHG4MvtxDigitizer.cc | 4 ++-- simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 10 +++++----- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc | 5 +++-- .../g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 8 ++++---- .../g4simulation/g4tpc/PHG4TpcPadBaselineShift.cc | 4 ++-- 23 files changed, 62 insertions(+), 75 deletions(-) diff --git a/offline/QA/modules/QAG4SimulationMicromegas.cc b/offline/QA/modules/QAG4SimulationMicromegas.cc index 320a4bd025..c5301858d9 100644 --- a/offline/QA/modules/QAG4SimulationMicromegas.cc +++ b/offline/QA/modules/QAG4SimulationMicromegas.cc @@ -272,10 +272,10 @@ int QAG4SimulationMicromegas::load_nodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } - m_hitsets = findNode::getClass(topNode, "TRKR_HITSET"); + m_hitsets = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); if (!m_hitsets) { - std::cout << PHWHERE << " ERROR: Can't find TrkrHitSetContainer." << std::endl; + std::cout << PHWHERE << " ERROR: Can't find TrkrHitSetContainer TRKR_HITSET_MICROMEGAS." << std::endl; } m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); diff --git a/offline/packages/intt/InttClusterizer.cc b/offline/packages/intt/InttClusterizer.cc index 7d08cc5fe7..491bdcaaf2 100644 --- a/offline/packages/intt/InttClusterizer.cc +++ b/offline/packages/intt/InttClusterizer.cc @@ -245,10 +245,10 @@ int InttClusterizer::process_event(PHCompositeNode* topNode) // get node containing the digitized hits if(!do_read_raw){ - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_INTT"); if (!m_hits) { - cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl; + cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_INTT" << endl; return Fun4AllReturnCodes::ABORTRUN; } }else{ @@ -256,7 +256,7 @@ int InttClusterizer::process_event(PHCompositeNode* topNode) m_rawhits = findNode::getClass(topNode, "TRKR_RAWHITSET"); if (!m_rawhits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } } diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index b8e9c3b822..c2c08b4d5c 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -144,7 +144,7 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) assert(geonode); // hitset container - auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); assert( trkrhitsetcontainer ); // cluster container diff --git a/offline/packages/micromegas/MicromegasRawDataDecoder.cc b/offline/packages/micromegas/MicromegasRawDataDecoder.cc index 8d6e2d821d..a4ec04cfce 100644 --- a/offline/packages/micromegas/MicromegasRawDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasRawDataDecoder.cc @@ -50,23 +50,24 @@ int MicromegasRawDataDecoder::InitRun(PHCompositeNode *topNode) } // create hitset container if needed - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); if (!hitsetcontainer) { - std::cout << "MicromegasRawDataDecoder::InitRun - creating TRKR_HITSET." << std::endl; + if (Verbosity()) + std::cout << "MicromegasRawDataDecoder::InitRun - creating TRKR_HITSET_MICROMEGAS." << std::endl; // find or create TRKR node PHNodeIterator dstiter(dstNode); - auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "MICROMEGAS")); if (!trkrnode) { - trkrnode = new PHCompositeNode("TRKR"); + trkrnode = new PHCompositeNode("MICROMEGAS"); dstNode->addNode(trkrnode); } // create container and add to the tree hitsetcontainer = new TrkrHitSetContainerv1; - auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_MICROMEGAS", "PHObject"); trkrnode->addNode(newNode); } @@ -80,7 +81,7 @@ int MicromegasRawDataDecoder::process_event(PHCompositeNode *topNode) // load relevant nodes // Get the TrkrHitSetContainer node - auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); assert(trkrhitsetcontainer); // PRDF node diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 2539aa8e11..e13ca47cae 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -212,10 +212,10 @@ int MvtxClusterizer::process_event(PHCompositeNode *topNode) { // get node containing the digitized hits if(!do_read_raw){ - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_MVTX"); if (!m_hits) { - cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl; + cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_MVTX" << endl; return Fun4AllReturnCodes::ABORTRUN; } }else{ @@ -223,7 +223,7 @@ int MvtxClusterizer::process_event(PHCompositeNode *topNode) m_rawhits = findNode::getClass(topNode, "TRKR_RAWHITSET"); if (!m_rawhits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } } diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index 8183ac24c4..2a6258fe39 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -82,10 +82,10 @@ int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) int MvtxHitPruner::process_event(PHCompositeNode *topNode) { // get node containing the digitized hits - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_MVTX"); if (!m_hits) { - cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl; + cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_MVTX" << endl; return Fun4AllReturnCodes::ABORTRUN; } diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 011f08e14f..11e5e7f973 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -783,10 +783,10 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) } if(!do_read_raw){ // get node containing the digitized hits - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!m_hits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } }else{ @@ -794,7 +794,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) m_rawhits = findNode::getClass(topNode, "TRKR_RAWHITSET"); if (!m_rawhits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } } diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index ce66a38c7f..8a3bd51546 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -148,10 +148,10 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) } // get node containing the digitized hits - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!m_hits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } @@ -159,7 +159,7 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) m_rawhits = findNode::getClass(topNode, "TRKR_RAWHITSET"); if (!m_rawhits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index bdaff199c7..9af08bd46e 100644 --- a/offline/packages/tpc/TpcSimpleClusterizer.cc +++ b/offline/packages/tpc/TpcSimpleClusterizer.cc @@ -438,10 +438,10 @@ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) } // get node containing the digitized hits - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!m_hits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } diff --git a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc index 74ad8ea05d..e89cfb1e28 100644 --- a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc +++ b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc @@ -236,7 +236,7 @@ int TpcDirectLaserReconstruction::load_nodes( PHCompositeNode* topNode ) assert(m_track_map); // get node containing the digitized hits - m_hit_map = findNode::getClass(topNode, "TRKR_HITSET"); + m_hit_map = findNode::getClass(topNode, "TRKR_HITSET_TPC"); assert(m_hit_map); return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/trackreco/PHTrackFitting.cc b/offline/packages/trackreco/PHTrackFitting.cc index 4c63959704..b92742f8a0 100644 --- a/offline/packages/trackreco/PHTrackFitting.cc +++ b/offline/packages/trackreco/PHTrackFitting.cc @@ -21,7 +21,6 @@ using namespace std; PHTrackFitting::PHTrackFitting(const std::string& name) : SubsysReco(name) , _cluster_map(nullptr) - , _hitsets(nullptr) , _vertex_map(nullptr) , _track_map(nullptr) , _track_map_name("SvtxTrackMap") @@ -64,13 +63,6 @@ int PHTrackFitting::GetNodes(PHCompositeNode* topNode) cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << endl; return Fun4AllReturnCodes::ABORTEVENT; } - _hitsets = findNode::getClass(topNode, "TRKR_HITSET"); - if(!_hitsets) - { - std::cout << PHWHERE << "No hitset container on node tree. Bailing." - << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } _vertex_map = findNode::getClass(topNode, "SvtxVertexMap"); if (!_vertex_map) diff --git a/offline/packages/trackreco/PHTrackFitting.h b/offline/packages/trackreco/PHTrackFitting.h index 434305c238..2819c4283a 100644 --- a/offline/packages/trackreco/PHTrackFitting.h +++ b/offline/packages/trackreco/PHTrackFitting.h @@ -53,7 +53,6 @@ class PHTrackFitting : public SubsysReco //SvtxClusterMap *_cluster_map; TrkrClusterContainer *_cluster_map; - TrkrHitSetContainer *_hitsets = nullptr; SvtxVertexMap *_vertex_map; SvtxTrackMap *_track_map; diff --git a/offline/packages/trackreco/PHTrackSeeding.cc b/offline/packages/trackreco/PHTrackSeeding.cc index 648547704d..89b79afdee 100644 --- a/offline/packages/trackreco/PHTrackSeeding.cc +++ b/offline/packages/trackreco/PHTrackSeeding.cc @@ -142,13 +142,5 @@ int PHTrackSeeding::GetNodes(PHCompositeNode* topNode) cerr << PHWHERE << " ERROR: Can't find " << _track_map_name << endl; return Fun4AllReturnCodes::ABORTEVENT; } - /* - _hitsets = findNode::getClass(topNode, "TRKR_HITSET"); - if (!_hitsets) - { - cerr << PHWHERE << " ERROR: Can't find TrkrHitSetContainer." << endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - */ return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4eval/DSTEmulator.cc b/simulation/g4simulation/g4eval/DSTEmulator.cc index 7e8a3b1ab2..d1101f3920 100644 --- a/simulation/g4simulation/g4eval/DSTEmulator.cc +++ b/simulation/g4simulation/g4eval/DSTEmulator.cc @@ -571,7 +571,8 @@ int DSTEmulator::load_nodes( PHCompositeNode* topNode ) m_container = findNode::getClass(topNode, "TrackEvaluationContainer"); // hitset container - m_hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + // TRKR_HITSET are now split for each subsystem + // m_hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); // g4hits m_g4hits_tpc = findNode::getClass(topNode, "G4HIT_TPC"); diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index 816c6ffa0b..5c3b5d4eb8 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -189,10 +189,10 @@ void PHG4InttDigitizer::DigitizeLadderCells(PHCompositeNode *topNode) } // Get the TrkrHitSetContainer node - TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_INTT"); if (!trkrhitsetcontainer) { - std::cout << "Could not locate TRKR_HITSET node, quit! " << std::endl; + std::cout << "Could not locate TRKR_HITSET_INTT node, quit! " << std::endl; exit(1); } @@ -283,7 +283,7 @@ void PHG4InttDigitizer::DigitizeLadderCells(PHCompositeNode *topNode) } } // end loop over hits in this hitset - // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC + // remove hits on dead channel in TRKR_HITSET_INTT and TRKR_HITTRUTHASSOC for (const auto &key : dead_hits) { if (Verbosity() > 2) diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index 79439dcece..0972a2558e 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -117,19 +117,19 @@ int PHG4InttHitReco::InitRun(PHCompositeNode *topNode) exit(1); } - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_INTT"); if (!hitsetcontainer) { PHNodeIterator dstiter(dstNode); - PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "INTT")); if (!DetNode) { - DetNode = new PHCompositeNode("TRKR"); + DetNode = new PHCompositeNode("INTT"); dstNode->addNode(DetNode); } hitsetcontainer = new TrkrHitSetContainerv1; - PHIODataNode *newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + PHIODataNode *newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_INTT", "PHObject"); DetNode->addNode(newNode); } @@ -224,10 +224,10 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) } // Get the TrkrHitSetContainer node - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_INTT"); if (!hitsetcontainer) { - std::cout << "Could not locate TRKR_HITSET node, quit! " << std::endl; + std::cout << "Could not locate TRKR_HITSET_INTT node, quit! " << std::endl; exit(1); } diff --git a/simulation/g4simulation/g4micromegas/PHG4MicromegasDigitizer.cc b/simulation/g4simulation/g4micromegas/PHG4MicromegasDigitizer.cc index 16477c0cf4..123f7a1198 100644 --- a/simulation/g4simulation/g4micromegas/PHG4MicromegasDigitizer.cc +++ b/simulation/g4simulation/g4micromegas/PHG4MicromegasDigitizer.cc @@ -91,7 +91,7 @@ int PHG4MicromegasDigitizer::process_event(PHCompositeNode *topNode) { // Get Nodes // Get the TrkrHitSetContainer node - auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); assert( trkrhitsetcontainer ); // Get the TrkrHitTruthAssoc node diff --git a/simulation/g4simulation/g4micromegas/PHG4MicromegasHitReco.cc b/simulation/g4simulation/g4micromegas/PHG4MicromegasHitReco.cc index e5bdd1ee2b..26b072f215 100644 --- a/simulation/g4simulation/g4micromegas/PHG4MicromegasHitReco.cc +++ b/simulation/g4simulation/g4micromegas/PHG4MicromegasHitReco.cc @@ -151,23 +151,24 @@ int PHG4MicromegasHitReco::InitRun(PHCompositeNode *topNode) } // create hitset container if needed - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); if (!hitsetcontainer) { - std::cout << "PHG4MicromegasHitReco::InitRun - creating TRKR_HITSET." << std::endl; + if (Verbosity()) + std::cout << "PHG4MicromegasHitReco::InitRun - creating TRKR_HITSET_MICROMEGAS." << std::endl; // find or create TRKR node PHNodeIterator dstiter(dstNode); - auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "MICROMEGAS")); if (!trkrnode) { - trkrnode = new PHCompositeNode("TRKR"); + trkrnode = new PHCompositeNode("MICROMEGAS"); dstNode->addNode(trkrnode); } // create container and add to the tree hitsetcontainer = new TrkrHitSetContainerv1; - auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_MICROMEGAS", "PHObject"); trkrnode->addNode(newNode); } @@ -212,7 +213,7 @@ int PHG4MicromegasHitReco::process_event(PHCompositeNode *topNode) assert(geonode); // Get the TrkrHitSetContainer node - auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MICROMEGAS"); assert(trkrhitsetcontainer); // Get the TrkrHitTruthAssoc node diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxDigitizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxDigitizer.cc index dba2d09e54..ad4d4a07e3 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxDigitizer.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxDigitizer.cc @@ -142,10 +142,10 @@ void PHG4MvtxDigitizer::DigitizeMvtxLadderCells(PHCompositeNode *topNode) // new containers //============= // Get the TrkrHitSetContainer node - TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MVTX"); if (!trkrhitsetcontainer) { - cout << "Could not locate TRKR_HITSET node, quit! " << endl; + cout << "Could not locate TRKR_HITSET_MVTX node, quit! " << endl; exit(1); } diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 8444315010..900c5529cd 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -113,19 +113,19 @@ int PHG4MvtxHitReco::InitRun(PHCompositeNode *topNode) SaveToNodeTree(runDetNode, paramNodeName); // create hitset container if needed - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_MVTX"); if (!hitsetcontainer) { PHNodeIterator dstiter(dstNode); - auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "MVTX")); if (!trkrnode) { - trkrnode = new PHCompositeNode("TRKR"); + trkrnode = new PHCompositeNode("MVTX"); dstNode->addNode(trkrnode); } hitsetcontainer = new TrkrHitSetContainerv1; - auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_MVTX", "PHObject"); trkrnode->addNode(newNode); } @@ -212,7 +212,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) assert(geoNode); // Get the TrkrHitSetContainer node - auto trkrHitSetContainer = findNode::getClass(topNode, "TRKR_HITSET"); + auto trkrHitSetContainer = findNode::getClass(topNode, "TRKR_HITSET_MVTX"); assert(trkrHitSetContainer); // Get the TrkrHitTruthAssoc node diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index aaa4a64ed1..007b182fc9 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -229,10 +229,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // Get the TrkrHitSetContainer node - TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + TrkrHitSetContainer *trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!trkrhitsetcontainer) { - std::cout << "Could not locate TRKR_HITSET node, quit! " << std::endl; + std::cout << "Could not locate TRKR_HITSET_TPC node, quit! " << std::endl; exit(1); } @@ -272,6 +272,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) phi_sorted_hits.push_back(std::vector()); } + // TODO: edit with new hit container // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId, layer); for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 1fefe1cef8..01a0cf1d85 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -130,19 +130,19 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) exit(1); } // new containers - hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!hitsetcontainer) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TPC")); if (!DetNode) { - DetNode = new PHCompositeNode("TRKR"); + DetNode = new PHCompositeNode("TPC"); dstNode->addNode(DetNode); } hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1"); - auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_TPC", "PHObject"); DetNode->addNode(newNode); } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadBaselineShift.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadBaselineShift.cc index d0f3c4461c..f8f793afd6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadBaselineShift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadBaselineShift.cc @@ -183,10 +183,10 @@ int PHG4TpcPadBaselineShift::process_event(PHCompositeNode *topNode) } // get node containing the digitized hits - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + m_hits = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!m_hits) { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } From 416249393da27c2542484e873b70b1b31f4ccffe Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 27 Mar 2023 16:27:39 -0400 Subject: [PATCH 040/468] Standard names for trackers --- offline/packages/trackbase/TrkrDefs.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/offline/packages/trackbase/TrkrDefs.h b/offline/packages/trackbase/TrkrDefs.h index bc072e5209..474a383cb0 100644 --- a/offline/packages/trackbase/TrkrDefs.h +++ b/offline/packages/trackbase/TrkrDefs.h @@ -9,6 +9,8 @@ #include #include +#include +#include /** * @brief Define a namespace for Trkr typedefs @@ -56,6 +58,15 @@ namespace TrkrDefs ttl = 4, }; + //! Standard names for trackers + static const std::map TrkrNames = + { + {mvtxId, "MVTX"}, + {inttId, "INTT"}, + {tpcId, "TPC"}, + {micromegasId, "MICROMEGAS"}, + {ttl, "TTL"} + }; /// Print the bits for each key type void printBits(const TrkrDefs::hitsetkey key, std::ostream& os = std::cout); From c7fab6557fb5311567f7eb9057f8bbc4a9faf2be Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 27 Mar 2023 22:54:27 -0400 Subject: [PATCH 041/468] split `TRKR_HITSET` by subsystem --- simulation/g4simulation/g4eval/SvtxHitEval.cc | 253 ++++++++++-------- simulation/g4simulation/g4eval/SvtxHitEval.h | 2 +- 2 files changed, 147 insertions(+), 108 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxHitEval.cc b/simulation/g4simulation/g4eval/SvtxHitEval.cc index 793bde92a8..bd9e56f589 100644 --- a/simulation/g4simulation/g4eval/SvtxHitEval.cc +++ b/simulation/g4simulation/g4eval/SvtxHitEval.cc @@ -28,7 +28,6 @@ using namespace std; SvtxHitEval::SvtxHitEval(PHCompositeNode* topNode) : _trutheval(topNode) - , _hitmap(nullptr) // , _g4cells_svtx(nullptr) // , _g4cells_tracker(nullptr) //, _g4cells_maps(nullptr) @@ -197,42 +196,54 @@ std::set SvtxHitEval::all_truth_hits(TrkrDefs::hitkey hit_key) // get all of the g4hits for this hit_key // have to start with all hitsets, unfortunately - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for(TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) + for (const auto& [trkrID, _hitmap] : _hitmaps) + { + TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) { TrkrDefs::hitsetkey hitset_key = iter->first; unsigned int trkrid = TrkrDefs::getTrkrId(hitset_key); - TrkrHitSet *hitset = iter->second; + TrkrHitSet* hitset = iter->second; // does this hitset contain our hitkey? - TrkrHit *hit = nullptr; + TrkrHit* hit = nullptr; hit = hitset->getHit(hit_key); - if(hit) - { - // get g4hits for this hit - - std::multimap< TrkrDefs::hitsetkey, std::pair > temp_map; - _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only - for(std::multimap< TrkrDefs::hitsetkey, std::pair >::iterator htiter = temp_map.begin(); - htiter != temp_map.end(); ++htiter) - { - // extract the g4 hit key here and add the g4hit to the set - PHG4HitDefs::keytype g4hitkey = htiter->second.second; - //cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; - PHG4Hit * g4hit = nullptr; - switch( trkrid ) - { - case TrkrDefs::tpcId: g4hit = _g4hits_tpc->findHit(g4hitkey); break; - case TrkrDefs::inttId: g4hit = _g4hits_intt->findHit(g4hitkey); break; - case TrkrDefs::mvtxId: g4hit = _g4hits_mvtx->findHit(g4hitkey); break; - case TrkrDefs::micromegasId: g4hit = _g4hits_mms->findHit(g4hitkey); break; - default: break; - } - // fill output set - if( g4hit ) truth_hits.insert(g4hit); - } - } + if (hit) + { + // get g4hits for this hit + + std::multimap > temp_map; + _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only + for (std::multimap >::iterator htiter = temp_map.begin(); + htiter != temp_map.end(); ++htiter) + { + // extract the g4 hit key here and add the g4hit to the set + PHG4HitDefs::keytype g4hitkey = htiter->second.second; + // cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; + PHG4Hit* g4hit = nullptr; + switch (trkrid) + { + case TrkrDefs::tpcId: + g4hit = _g4hits_tpc->findHit(g4hitkey); + break; + case TrkrDefs::inttId: + g4hit = _g4hits_intt->findHit(g4hitkey); + break; + case TrkrDefs::mvtxId: + g4hit = _g4hits_mvtx->findHit(g4hitkey); + break; + case TrkrDefs::micromegasId: + g4hit = _g4hits_mms->findHit(g4hitkey); + break; + default: + break; + } + // fill output set + if (g4hit) truth_hits.insert(g4hit); + } + } } + } if (_do_cache) _cache_all_truth_hits.insert(make_pair(hit_key, truth_hits)); @@ -269,42 +280,59 @@ std::set SvtxHitEval::all_truth_hits(TrkrDefs::hitkey hit_key, const T } } + std::set truth_hits; - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(trkrid); - for(TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) + if (_hitmaps.find(trkrid) != _hitmaps.end()) { - TrkrDefs::hitsetkey hitset_key = iter->first; - TrkrHitSet *hitset = iter->second; + TrkrHitSetContainer* _hitmap = _hitmaps[trkrid]; + assert(_hitmap); - // does this hitset contain our hitkey? - TrkrHit *hit = nullptr; - hit = hitset->getHit(hit_key); - if(hit) + TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(trkrid); + + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) + { + TrkrDefs::hitsetkey hitset_key = iter->first; + TrkrHitSet* hitset = iter->second; + + // does this hitset contain our hitkey? + TrkrHit* hit = nullptr; + hit = hitset->getHit(hit_key); + if (hit) { // get g4hits for this hit - std::multimap< TrkrDefs::hitsetkey, std::pair > temp_map; - _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only - for(std::multimap< TrkrDefs::hitsetkey, std::pair >::iterator htiter = temp_map.begin(); - htiter != temp_map.end(); ++htiter) + std::multimap > temp_map; + _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only + for (std::multimap >::iterator htiter = temp_map.begin(); + htiter != temp_map.end(); ++htiter) + { + // extract the g4 hit key here and add the g4hit to the set + PHG4HitDefs::keytype g4hitkey = htiter->second.second; + // cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; + PHG4Hit* g4hit = nullptr; + switch (trkrid) { - // extract the g4 hit key here and add the g4hit to the set - PHG4HitDefs::keytype g4hitkey = htiter->second.second; - //cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; - PHG4Hit * g4hit = nullptr; - switch( trkrid ) - { - case TrkrDefs::tpcId: g4hit = _g4hits_tpc->findHit(g4hitkey); break; - case TrkrDefs::inttId: g4hit = _g4hits_intt->findHit(g4hitkey); break; - case TrkrDefs::mvtxId: g4hit = _g4hits_mvtx->findHit(g4hitkey); break; - case TrkrDefs::micromegasId: g4hit = _g4hits_mms->findHit(g4hitkey); break; - default: break; - } - // fill output set - if( g4hit ) truth_hits.insert(g4hit); + case TrkrDefs::tpcId: + g4hit = _g4hits_tpc->findHit(g4hitkey); + break; + case TrkrDefs::inttId: + g4hit = _g4hits_intt->findHit(g4hitkey); + break; + case TrkrDefs::mvtxId: + g4hit = _g4hits_mvtx->findHit(g4hitkey); + break; + case TrkrDefs::micromegasId: + g4hit = _g4hits_mms->findHit(g4hitkey); + break; + default: + break; } + // fill output set + if (g4hit) truth_hits.insert(g4hit); + } } + } } if (_do_cache) _cache_all_truth_hits.insert(make_pair(hit_key, truth_hits)); @@ -666,33 +694,36 @@ std::set SvtxHitEval::all_hits_from(PHG4Particle* g4particle) std::set hits; - // loop over all the hits - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) - { - TrkrHitSet::ConstRange range = iter->second->getHits(); - for(TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) + for (const auto& [trkrID, _hitmap] : _hitmaps) + { + // loop over all the hits + TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; + iter != all_hitsets.second; + ++iter) + { + TrkrHitSet::ConstRange range = iter->second->getHits(); + for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) { - TrkrDefs::hitkey hit_key = hitr->first; - - // loop over all truth hits connected to this hit - std::set g4hits = all_truth_hits(hit_key); - for (std::set::iterator jter = g4hits.begin(); - jter != g4hits.end(); - ++jter) - { - PHG4Hit* candidate = *jter; - PHG4Particle *particle = _truthinfo->GetParticle(candidate->get_trkid()); - if (g4particle->get_track_id() == particle->get_track_id()) - { - hits.insert(hit_key); - } - } - } + TrkrDefs::hitkey hit_key = hitr->first; + + // loop over all truth hits connected to this hit + std::set g4hits = all_truth_hits(hit_key, trkrID); + for (std::set::iterator jter = g4hits.begin(); + jter != g4hits.end(); + ++jter) + { + PHG4Hit* candidate = *jter; + PHG4Particle* particle = _truthinfo->GetParticle(candidate->get_trkid()); + if (g4particle->get_track_id() == particle->get_track_id()) + { + hits.insert(hit_key); + } + } + } + } } - + if (_do_cache) _cache_all_hits_from_particle.insert(make_pair(g4particle, hits)); return hits; @@ -733,33 +764,36 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) unsigned int hit_layer = g4hit->get_layer(); // loop over all the hits - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) + for (const auto& [trkrID, _hitmap] : _hitmaps) { - TrkrHitSet::ConstRange range = iter->second->getHits(); - for(TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) + TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; + iter != all_hitsets.second; + ++iter) + { + TrkrHitSet::ConstRange range = iter->second->getHits(); + for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) { - TrkrDefs::hitkey hit_key = hitr->first; - - if (TrkrDefs::getLayer(hit_key) != hit_layer) continue; - - // loop over all truth hits connected to this hit - std::set g4hits = all_truth_hits(hit_key); - for (std::set::iterator jter = g4hits.begin(); - jter != g4hits.end(); - ++jter) - { - PHG4Hit* candidate = *jter; - if (candidate->get_hit_id() == g4hit->get_hit_id()) - { - hits.insert(hit_key); - } - } + TrkrDefs::hitkey hit_key = hitr->first; + + if (TrkrDefs::getLayer(hit_key) != hit_layer) continue; + + // loop over all truth hits connected to this hit + std::set g4hits = all_truth_hits(hit_key); + for (std::set::iterator jter = g4hits.begin(); + jter != g4hits.end(); + ++jter) + { + PHG4Hit* candidate = *jter; + if (candidate->get_hit_id() == g4hit->get_hit_id()) + { + hits.insert(hit_key); + } + } } + } } - + if (_do_cache) _cache_all_hits_from_g4hit.insert(make_pair(g4hit, hits)); return hits; @@ -919,7 +953,12 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) void SvtxHitEval::get_node_pointers(PHCompositeNode* topNode) { // need things off of the DST... - _hitmap = findNode::getClass(topNode, "TRKR_HITSET"); + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * _hitmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (_hitmap) + _hitmaps[trkrID] = _hitmap; + } _clustermap = findNode::getClass(topNode, "CORRECTED_TRKR_CLUSTER"); if(!_clustermap) @@ -941,8 +980,8 @@ void SvtxHitEval::get_node_pointers(PHCompositeNode* topNode) bool SvtxHitEval::has_node_pointers() { if (_strict) - assert(_hitmap); - else if (!_hitmap) + assert(_hitmaps.size()); + else if (!_hitmaps.size()) { return false; } diff --git a/simulation/g4simulation/g4eval/SvtxHitEval.h b/simulation/g4simulation/g4eval/SvtxHitEval.h index eefb1d0d54..8d1db965c8 100644 --- a/simulation/g4simulation/g4eval/SvtxHitEval.h +++ b/simulation/g4simulation/g4eval/SvtxHitEval.h @@ -80,7 +80,7 @@ class SvtxHitEval bool has_node_pointers(); SvtxTruthEval _trutheval; - TrkrHitSetContainer* _hitmap; + std::map _hitmaps; TrkrClusterContainer* _clustermap; TrkrHitTruthAssoc* _hit_truth_map; From e8229e3a825e866b6cb5c9945f4d087dba244466 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 27 Mar 2023 23:52:51 -0400 Subject: [PATCH 042/468] split `TRKR_HITSET` by subsystem --- .../g4simulation/g4eval/SvtxEvaluator.cc | 516 ++++++++++-------- 1 file changed, 280 insertions(+), 236 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index a28ffa879f..79f996f4c3 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -815,34 +815,38 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float occ216 = 0; float occ31 = 0; float occ316 = 0; - - TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET"); - if (hitmap_in) + + for ([[maybe_unused]] const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitmap_in) { TrkrHitSetContainer::ConstRange all_hitsets = hitmap_in->getHitSets(); for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; - hitsetiter != all_hitsets.second; - ++hitsetiter) - { - // we have a single hitset, get the layer - unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); - if(layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) - { - // count all hits in this hitset - TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - nhit[layer]++; - nhit_tpc_all++; - if ((float) layer == _nlayers_maps + _nlayers_intt) nhit_tpc_in++; - if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc - 1) nhit_tpc_out++; - if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) nhit_tpc_mid++; - } - } - } + hitsetiter != all_hitsets.second; + ++hitsetiter) + { + // we have a single hitset, get the layer + unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + { + // count all hits in this hitset + TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + nhit[layer]++; + nhit_tpc_all++; + if ((float) layer == _nlayers_maps + _nlayers_intt) nhit_tpc_in++; + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc - 1) nhit_tpc_out++; + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) nhit_tpc_mid++; + } + } + } } + } // for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) + /**********/ PHG4TpcCylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); @@ -1540,187 +1544,191 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) _timer->restart(); } // need things off of the DST... - TrkrHitSetContainer *hitmap = findNode::getClass(topNode, "TRKR_HITSET"); - PHG4TpcCylinderGeomContainer* geom_container = - findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); - if (!geom_container) + for ([[maybe_unused]] const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) { - std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; - return; - } + TrkrHitSetContainer* hitmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + PHG4TpcCylinderGeomContainer* geom_container = + findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); + if (!geom_container) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; + return; + } - if (hitmap) - { - TrkrHitSetContainer::ConstRange all_hitsets = hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) + if (hitmap) { - TrkrDefs::hitsetkey hitset_key = iter->first; - TrkrHitSet *hitset = iter->second; - - // get all hits for this hitset - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - TrkrDefs::hitkey hit_key = hitr->first; - TrkrHit *hit = hitr->second; - PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); - PHG4Particle* g4particle = trutheval->get_particle(g4hit); - float event = _ievent; - float hitID = hit_key; - float e = hit->getEnergy(); - float adc = hit->getAdc(); - float layer = TrkrDefs::getLayer(hitset_key); - float sector = TpcDefs::getSectorId(hitset_key); - float side = TpcDefs::getSide(hitset_key); - float cellID = 0; - float ecell = hit->getAdc(); - - float phibin = NAN; - float zbin = NAN; - float phi = NAN; - float z = NAN; - - if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc ) - { - PHG4TpcCylinderGeom* GeoLayer = geom_container->GetLayerCellGeom(layer); - phibin = (float) TpcDefs::getPad(hit_key); - zbin = (float) TpcDefs::getTBin(hit_key); - phi = GeoLayer->get_phicenter(phibin); - z = GeoLayer->get_zcenter(zbin); - } + TrkrHitSetContainer::ConstRange all_hitsets = hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; + iter != all_hitsets.second; + ++iter) + { + TrkrDefs::hitsetkey hitset_key = iter->first; + TrkrHitSet* hitset = iter->second; + + // get all hits for this hitset + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + TrkrDefs::hitkey hit_key = hitr->first; + TrkrHit* hit = hitr->second; + PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); + PHG4Particle* g4particle = trutheval->get_particle(g4hit); + float event = _ievent; + float hitID = hit_key; + float e = hit->getEnergy(); + float adc = hit->getAdc(); + float layer = TrkrDefs::getLayer(hitset_key); + float sector = TpcDefs::getSectorId(hitset_key); + float side = TpcDefs::getSide(hitset_key); + float cellID = 0; + float ecell = hit->getAdc(); + + float phibin = NAN; + float zbin = NAN; + float phi = NAN; + float z = NAN; + + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + { + PHG4TpcCylinderGeom* GeoLayer = geom_container->GetLayerCellGeom(layer); + phibin = (float) TpcDefs::getPad(hit_key); + zbin = (float) TpcDefs::getTBin(hit_key); + phi = GeoLayer->get_phicenter(phibin); + z = GeoLayer->get_zcenter(zbin); + } - float g4hitID = NAN; - float gedep = NAN; - float gx = NAN; - float gy = NAN; - float gz = NAN; - float gt = NAN; - float gtrackID = NAN; - float gflavor = NAN; - float gpx = NAN; - float gpy = NAN; - float gpz = NAN; - float gvx = NAN; - float gvy = NAN; - float gvz = NAN; - float gvt = NAN; - float gfpx = NAN; - float gfpy = NAN; - float gfpz = NAN; - float gfx = NAN; - float gfy = NAN; - float gfz = NAN; - float gembed = NAN; - float gprimary = NAN; - - float efromtruth = NAN; + float g4hitID = NAN; + float gedep = NAN; + float gx = NAN; + float gy = NAN; + float gz = NAN; + float gt = NAN; + float gtrackID = NAN; + float gflavor = NAN; + float gpx = NAN; + float gpy = NAN; + float gpz = NAN; + float gvx = NAN; + float gvy = NAN; + float gvz = NAN; + float gvt = NAN; + float gfpx = NAN; + float gfpy = NAN; + float gfpz = NAN; + float gfx = NAN; + float gfy = NAN; + float gfz = NAN; + float gembed = NAN; + float gprimary = NAN; + + float efromtruth = NAN; + + if (g4hit) + { + g4hitID = g4hit->get_hit_id(); + gedep = g4hit->get_edep(); + gx = g4hit->get_avg_x(); + gy = g4hit->get_avg_y(); + gz = g4hit->get_avg_z(); + gt = g4hit->get_avg_t(); + + if (g4particle) + { + if (_scan_for_embedded) + { + if (trutheval->get_embed(g4particle) <= 0) continue; + } + + gtrackID = g4particle->get_track_id(); + gflavor = g4particle->get_pid(); + gpx = g4particle->get_px(); + gpy = g4particle->get_py(); + gpz = g4particle->get_pz(); + + PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle); + + if (vtx) + { + gvx = vtx->get_x(); + gvy = vtx->get_y(); + gvz = vtx->get_z(); + gvt = vtx->get_t(); + } + + PHG4Hit* outerhit = nullptr; + if (_do_eval_light == false) + outerhit = trutheval->get_outermost_truth_hit(g4particle); + if (outerhit) + { + gfpx = outerhit->get_px(1); + gfpy = outerhit->get_py(1); + gfpz = outerhit->get_pz(1); + gfx = outerhit->get_x(1); + gfy = outerhit->get_y(1); + gfz = outerhit->get_z(1); + } + gembed = trutheval->get_embed(g4particle); + gprimary = trutheval->is_primary(g4particle); + } // if (g4particle){ + } - if (g4hit) - { - g4hitID = g4hit->get_hit_id(); - gedep = g4hit->get_edep(); - gx = g4hit->get_avg_x(); - gy = g4hit->get_avg_y(); - gz = g4hit->get_avg_z(); - gt = g4hit->get_avg_t(); - - if (g4particle) - { - if (_scan_for_embedded) - { - if (trutheval->get_embed(g4particle) <= 0) continue; - } - - gtrackID = g4particle->get_track_id(); - gflavor = g4particle->get_pid(); - gpx = g4particle->get_px(); - gpy = g4particle->get_py(); - gpz = g4particle->get_pz(); - - PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle); - - if (vtx) - { - gvx = vtx->get_x(); - gvy = vtx->get_y(); - gvz = vtx->get_z(); - gvt = vtx->get_t(); - } - - PHG4Hit* outerhit = nullptr; - if (_do_eval_light == false) - outerhit = trutheval->get_outermost_truth_hit(g4particle); - if (outerhit) - { - gfpx = outerhit->get_px(1); - gfpy = outerhit->get_py(1); - gfpz = outerhit->get_pz(1); - gfx = outerhit->get_x(1); - gfy = outerhit->get_y(1); - gfz = outerhit->get_z(1); - } - gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); - } // if (g4particle){ - } - - if (g4particle) - { - efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); - } + if (g4particle) + { + efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); + } - float hit_data[] = { - event, - (float) _iseed, - hitID, - e, - adc, - layer, - sector, - side, - cellID, - ecell, - (float) phibin, - (float) zbin, - phi, - z, - g4hitID, - gedep, - gx, - gy, - gz, - gt, - gtrackID, - gflavor, - gpx, - gpy, - gpz, - gvx, - gvy, - gvz, - gvt, - gfpx, - gfpy, - gfpz, - gfx, - gfy, - gfz, - gembed, - gprimary, - efromtruth, - nhit_tpc_all, - nhit_tpc_in, - nhit_tpc_mid, - nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; - - _ntp_hit->Fill(hit_data); - } + float hit_data[] = { + event, + (float) _iseed, + hitID, + e, + adc, + layer, + sector, + side, + cellID, + ecell, + (float) phibin, + (float) zbin, + phi, + z, + g4hitID, + gedep, + gx, + gy, + gz, + gt, + gtrackID, + gflavor, + gpx, + gpy, + gpz, + gvx, + gvy, + gvz, + gvt, + gfpx, + gfpy, + gfpz, + gfx, + gfy, + gfz, + gembed, + gprimary, + efromtruth, + nhit_tpc_all, + nhit_tpc_in, + nhit_tpc_mid, + nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; + + _ntp_hit->Fill(hit_data); + } + } } - } + } // for ([[maybe_unused]] const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) + if (Verbosity() >= 1) { _timer->stop(); @@ -1747,7 +1755,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - TrkrHitSetContainer* hitsets = findNode::getClass(topNode, "TRKR_HITSET"); + std::map hitsetsmap; + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitsets) + hitsetsmap[trkrID] = hitsets; + } TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); if (Verbosity() > 1){ @@ -1759,14 +1773,14 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) cout << "got clusterhitmap" << endl; else cout << "no clusterhitmap" << endl; - if (hitsets != nullptr) + if (hitsetsmap.size() != 0) cout << "got hitsets" << endl; else cout << "no hitsets" << endl; } - if (clustermap && clusterhitmap && hitsets ){ + if (clustermap && clusterhitmap && hitsetsmap.size()>0 ){ for(const auto& hitsetkey:clustermap->getHitSetKeys()) { int hitsetlayer = TrkrDefs::getLayer(hitsetkey); @@ -1853,23 +1867,32 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } */ float sumadc = 0; - TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); - std::pair::const_iterator, std::multimap::const_iterator> - hitrange = clusterhitmap->getHits(cluster_key); - for(std::multimap::const_iterator - clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer) - { - TrkrHit* hit = hitset->second->getHit(clushititer->second); - if(!hit) continue; - ++size; - sumadc += (hit->getAdc() - 70); - if((hit->getAdc()-70)>maxadc) - maxadc = (hit->getAdc()-70); - } - e = sumadc; - - float trackID = NAN; + auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); + if (hitsetsmap_iter != hitsetsmap.end()) + { + TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; + assert(hitsets); + + TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); + std::pair::const_iterator, std::multimap::const_iterator> + hitrange = clusterhitmap->getHits(cluster_key); + for (std::multimap::const_iterator + clushititer = hitrange.first; + clushititer != hitrange.second; ++clushititer) + { + TrkrHit* hit = hitset->second->getHit(clushititer->second); + if (!hit) continue; + + ++size; + sumadc += (hit->getAdc() - 70); + if ((hit->getAdc() - 70) > maxadc) + maxadc = (hit->getAdc() - 70); + } + e = sumadc; + } + + float trackID = NAN; if (track!=NULL) trackID = track->get_id(); float g4hitID = NAN; @@ -2036,8 +2059,10 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) _ntp_cluster->Fill(cluster_data); } } - } - } + } // if (clustermap && clusterhitmap && hitsets ){ + + } // if (_ntp_cluster && !_scan_for_embedded) + else if (_ntp_cluster && _scan_for_embedded) { if (Verbosity() > 1) @@ -2055,10 +2080,18 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - TrkrHitSetContainer* hitsets = findNode::getClass(topNode, "TRKR_HITSET"); + + std::map hitsetsmap; + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitsets) + hitsetsmap[trkrID] = hitsets; + } + TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); - if (trackmap != nullptr && clustermap != nullptr && clusterhitmap != nullptr && hitsets != nullptr){ + if (trackmap != nullptr && clustermap != nullptr && clusterhitmap != nullptr && hitsetsmap.size() != 0){ for (SvtxTrackMap::Iter iter = trackmap->begin(); iter != trackmap->end(); ++iter) @@ -2159,21 +2192,30 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) // count all hits for this cluster float maxadc = -999; + // count all hits for this cluster TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key); - TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); - std::pair::const_iterator, std::multimap::const_iterator> - hitrange = clusterhitmap->getHits(cluster_key); - for(std::multimap::const_iterator - clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer) - { - TrkrHit* hit = hitset->second->getHit(clushititer->second); - ++size; - if(hit->getAdc()>maxadc) - maxadc = hit->getAdc(); - } - - float trackID = NAN; + + auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); + if (hitsetsmap_iter != hitsetsmap.end()) + { + TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; + assert(hitsets); + TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); + std::pair::const_iterator, std::multimap::const_iterator> + hitrange = clusterhitmap->getHits(cluster_key); + for (std::multimap::const_iterator + clushititer = hitrange.first; + clushititer != hitrange.second; ++clushititer) + { + TrkrHit* hit = hitset->second->getHit(clushititer->second); + ++size; + if (hit->getAdc() > maxadc) + maxadc = hit->getAdc(); + } + } + + float trackID = NAN; trackID = track->get_id(); float g4hitID = NAN; @@ -2323,8 +2365,10 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) _ntp_cluster->Fill(cluster_data); } } - } - } + } // if (trackmap != nullptr && clustermap != nullptr && clusterhitmap != nullptr && hitsets != nullptr){ + + } // else if (_ntp_cluster && _scan_for_embedded) + if (Verbosity() >= 1){ _timer->stop(); cout << "cluster time: " << _timer->get_accumulated_time() / 1000. << " sec" << endl; From 1016d0b796c4ab0983fcf5d49984ee0f2e46642d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 28 Mar 2023 00:18:55 -0400 Subject: [PATCH 043/468] split `TRKR_HITSET` by subsystem --- .../g4simulation/g4eval/TrackEvaluation.cc | 29 ++++++++++++++++--- .../g4simulation/g4eval/TrackEvaluation.h | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/simulation/g4simulation/g4eval/TrackEvaluation.cc b/simulation/g4simulation/g4eval/TrackEvaluation.cc index 1dd23a104c..a75ae277e8 100644 --- a/simulation/g4simulation/g4eval/TrackEvaluation.cc +++ b/simulation/g4simulation/g4eval/TrackEvaluation.cc @@ -386,7 +386,12 @@ int TrackEvaluation::load_nodes( PHCompositeNode* topNode ) m_container = findNode::getClass(topNode, "TrackEvaluationContainer"); // hitset container - m_hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitsetcontainer) + m_hitsetcontainermap[trkrID] = hitsetcontainer; + } // g4hits m_g4hits_tpc = findNode::getClass(topNode, "G4HIT_TPC"); @@ -447,7 +452,7 @@ void TrackEvaluation::evaluate_event() void TrackEvaluation::evaluate_clusters() { - if(!(m_cluster_map&&m_hitsetcontainer&&m_container)) return; + if(!(m_cluster_map&&m_hitsetcontainermap.size()>0&&m_container)) return; // clear array m_container->clearClusters(); @@ -460,7 +465,15 @@ void TrackEvaluation::evaluate_clusters() // create cluster structure auto cluster_struct = create_cluster( key, cluster, track ); add_cluster_size( cluster_struct, cluster); - add_cluster_energy( cluster_struct, key, m_cluster_hit_map, m_hitsetcontainer ); + + + auto hitsetsmap_iter = m_hitsetcontainermap.find(TrkrDefs::getTrkrId(hitsetkey)); + if (hitsetsmap_iter != m_hitsetcontainermap.end()) + { + TrkrHitSetContainer* hitsetcontainer = hitsetsmap_iter->second; + assert(hitsetcontainer); + add_cluster_energy( cluster_struct, key, m_cluster_hit_map, hitsetcontainer ); + } // truth information const auto g4hits = find_g4hits( key ); @@ -516,7 +529,15 @@ void TrackEvaluation::evaluate_tracks() // create new cluster struct auto cluster_struct = create_cluster( cluster_key, cluster, track ); add_cluster_size( cluster_struct, cluster); - add_cluster_energy( cluster_struct, cluster_key, m_cluster_hit_map, m_hitsetcontainer ); + + auto hitsetsmap_iter = m_hitsetcontainermap.find(TrkrDefs::getTrkrId(cluster_key)); + if (hitsetsmap_iter != m_hitsetcontainermap.end()) + { + TrkrHitSetContainer* hitsetcontainer = hitsetsmap_iter->second; + assert(hitsetcontainer); + add_cluster_energy( cluster_struct, cluster_key, m_cluster_hit_map, hitsetcontainer ); + } + // truth information const auto g4hits = find_g4hits( cluster_key ); const bool is_micromegas( TrkrDefs::getTrkrId(cluster_key) == TrkrDefs::micromegasId ); diff --git a/simulation/g4simulation/g4eval/TrackEvaluation.h b/simulation/g4simulation/g4eval/TrackEvaluation.h index 9b612eb2c3..cb221d122f 100644 --- a/simulation/g4simulation/g4eval/TrackEvaluation.h +++ b/simulation/g4simulation/g4eval/TrackEvaluation.h @@ -121,7 +121,7 @@ class TrackEvaluation : public SubsysReco ActsGeometry *m_tGeometry = nullptr; //! hits - TrkrHitSetContainer* m_hitsetcontainer = nullptr; + std::map m_hitsetcontainermap; //! clusters TrkrClusterContainer* m_cluster_map = nullptr; From 7658610c7e312eae7822b5fd100ffd9c28bdc0bf Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 28 Mar 2023 10:14:41 -0400 Subject: [PATCH 044/468] Remove directed fitter machinery --- offline/packages/trackreco/PHActsTrkFitter.cc | 142 +++--------------- offline/packages/trackreco/PHActsTrkFitter.h | 7 - 2 files changed, 19 insertions(+), 130 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a0c5f66c23..7734d9a195 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -321,22 +321,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(sourceLinks.empty()) { continue; } - /// If using directed navigation, collect surface list to navigate - SurfacePtrVec surfaces; - if(m_fitSiliconMMs) - { - sourceLinks = getSurfaceVector(sourceLinks, surfaces); - - // skip if there is no surfaces - if( surfaces.empty() ) continue; - - // make sure micromegas are in the tracks, if required - if( m_useMicromegas && - std::none_of( surfaces.begin(), surfaces.end(), [this]( const auto& surface ) - { return m_tGeometry->maps().isMicromegasSurface( surface ); } ) ) - { continue; } - } - Acts::Vector3 momentum( tpcseed->get_px(m_clusterContainer, m_tGeometry), tpcseed->get_py(m_clusterContainer, m_tGeometry), @@ -397,7 +381,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) fitTimer.stop(); fitTimer.restart(); auto mtj = std::make_shared(); - auto result = fitTrack(wrappedSls, seed, kfOptions, surfaces,mtj); + auto result = fitTrack(wrappedSls, seed, kfOptions, mtj); fitTimer.stop(); auto fitTime = fitTimer.get_accumulated_time(); @@ -466,9 +450,10 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } //___________________________________________________________________________________ -SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - short int crossing ) +SourceLinkVec PHActsTrkFitter::getSourceLinks( + TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + short int crossing ) { SourceLinkVec sourcelinks; @@ -637,6 +622,14 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, continue; } + if(m_fitSiliconMMs) + { + if(TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) + { + continue; + } + } + auto cluster = m_clusterContainer->findCluster(cluskey); Surface surf = m_tGeometry->maps().getSurface(cluskey, cluster); @@ -731,9 +724,10 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, << std::endl; } - sourcelinks.push_back(sl); - measurements.push_back(meas); - + + sourcelinks.push_back(sl); + measurements.push_back(meas); + } SLTrackTimer.stop(); @@ -821,108 +815,10 @@ bool PHActsTrkFitter::getTrackFitResult(const FitResult &fitOutput, SvtxTrack* t ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( const std::vector>& sourceLinks, const ActsTrackFittingAlgorithm::TrackParameters& seed, - const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, - const SurfacePtrVec& surfSequence, + const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, std::shared_ptr& mtj) { - if(m_fitSiliconMMs) - { - return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, mtj); - } else { - return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, mtj); - } -} - -SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, - SurfacePtrVec& surfaces) const -{ - SourceLinkVec siliconMMSls; - -// if(Verbosity() > 1) -// std::cout << "Sorting " << sourceLinks.size() << " SLs" << std::endl; - - for(const auto& sl : sourceLinks) - { - if(Verbosity() > 1) - { std::cout << "SL available on : " << sl.geometryId() << std::endl; } - - const auto surf = m_tGeometry->geometry().tGeometry->findSurface(sl.geometryId()); - // skip TPC surfaces - if( m_tGeometry->maps().isTpcSurface( surf ) ) continue; - - // also skip micromegas surfaces if not used - if( m_tGeometry->maps().isMicromegasSurface( surf ) && !m_useMicromegas ) continue; - - // update vectors - siliconMMSls.push_back(sl); - surfaces.push_back(surf); - } - - /// Surfaces need to be sorted in order, i.e. from smallest to - /// largest radius extending from target surface - /// Add a check to ensure this - if(!surfaces.empty()) - { checkSurfaceVec(surfaces); } - - if(Verbosity() > 1) - { - for(const auto& surf : surfaces) - { - std::cout << "Surface vector : " << surf->geometryId() << std::endl; - } - } - - return siliconMMSls; -} - -void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec &surfaces) const -{ - for(int i = 0; i < surfaces.size() - 1; i++) - { - const auto& surface = surfaces.at(i); - const auto thisVolume = surface->geometryId().volume(); - const auto thisLayer = surface->geometryId().layer(); - - const auto nextSurface = surfaces.at(i+1); - const auto nextVolume = nextSurface->geometryId().volume(); - const auto nextLayer = nextSurface->geometryId().layer(); - - /// Implement a check to ensure surfaces are sorted - if(nextVolume == thisVolume) - { - if(nextLayer < thisLayer) - { - std::cout - << "PHActsTrkFitter::checkSurfaceVec - " - << "Surface not in order... removing surface" - << surface->geometryId() << std::endl; - - surfaces.erase(surfaces.begin() + i); - - /// Subtract one so we don't skip a surface - --i; - continue; - } - - } else { - - if(nextVolume < thisVolume) - { - std::cout - << "PHActsTrkFitter::checkSurfaceVec - " - << "Volume not in order... removing surface" - << surface->geometryId() << std::endl; - - surfaces.erase(surfaces.begin() + i); - - /// Subtract one so we don't skip a surface - --i; - continue; - - } - } - } - + return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, mtj); } void PHActsTrkFitter::updateSvtxTrack(Trajectory traj, SvtxTrack* track) diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 1521619214..9eb80c6247 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -134,15 +134,8 @@ class PHActsTrkFitter : public SubsysReco const ActsTrackFittingAlgorithm::TrackParameters& seed, const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, - const SurfacePtrVec& surfSequence, std::shared_ptr& mtj); - /// Functions to get list of sorted surfaces for direct navigation, if - /// applicable - SourceLinkVec getSurfaceVector(const SourceLinkVec& sourceLinks, - SurfacePtrVec& surfaces) const; - void checkSurfaceVec(SurfacePtrVec& surfaces) const; - bool getTrackFitResult(const FitResult& fitOutput, SvtxTrack* track); Acts::BoundSymMatrix setDefaultCovariance() const; From 997878d35eaa84e86dbeb86d79c0d18d4f175ef2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 28 Mar 2023 10:33:28 -0400 Subject: [PATCH 045/468] generalize skip layer --- offline/packages/trackreco/PHActsTrkFitter.cc | 3 ++- offline/packages/trackreco/PHActsTrkFitter.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a0c5f66c23..719bdc8a4b 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -627,7 +627,8 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, TrkrDefs::cluskey cluskey = global_moved[i].first; Acts::Vector3 global = global_moved[i].second; - if(TrkrDefs::getLayer(cluskey) == m_ignoreLayer) + if(std::find(m_ignoreLayer.begin(), m_ignoreLayer.end(), + TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end()) { if(Verbosity() > 3) { diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 1521619214..6d97e75c02 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -109,7 +109,7 @@ class PHActsTrkFitter : public SubsysReco /// Set flag for pp running void set_pp_mode(bool ispp) { m_pp_mode = ispp; } - void ignoreLayer(int layer) { m_ignoreLayer = layer; } + void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } private: @@ -202,8 +202,8 @@ class PHActsTrkFitter : public SubsysReco TpcClusterMover _clusterMover; ClusterErrorPara _ClusErrPara; - int m_ignoreLayer = std::numeric_limits::max(); - + std::set m_ignoreLayer; + std::string m_fieldMap = ""; int _n_iteration = 0; From c65f57f29ded7b3cf28fd92b1c6b9e85e402c0d1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 28 Mar 2023 10:48:58 -0400 Subject: [PATCH 046/468] use set::find --- offline/packages/trackreco/PHActsTrkFitter.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 719bdc8a4b..4ffa111543 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -627,8 +627,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, TrkrDefs::cluskey cluskey = global_moved[i].first; Acts::Vector3 global = global_moved[i].second; - if(std::find(m_ignoreLayer.begin(), m_ignoreLayer.end(), - TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end()) + if(m_ignoreLayer.find(TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end()) { if(Verbosity() > 3) { From c94a0ab5f11535eec4366096ac62530e207da18c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 28 Mar 2023 10:50:59 -0400 Subject: [PATCH 047/468] remove unused varable --- offline/packages/trackreco/PHActsTrkFitter.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 27e29aa3be..f1868df916 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -80,10 +80,6 @@ class PHActsTrkFitter : public SubsysReco void fitSiliconMMs(bool fitSiliconMMs) {m_fitSiliconMMs = fitSiliconMMs;} - /// require micromegas in SiliconMM fits - void setUseMicromegas( bool value ) - { m_useMicromegas = value; } - void setUpdateSvtxTrackStates(bool fillSvtxTrackStates) { m_fillSvtxTrackStates = fillSvtxTrackStates; } @@ -166,9 +162,6 @@ class PHActsTrkFitter : public SubsysReco /// Acts::DirectedNavigator with a list of sorted silicon+MM surfaces bool m_fitSiliconMMs = false; - /// requires micromegas present when fitting silicon-MM surfaces - bool m_useMicromegas = true; - /// A bool to update the SvtxTrackState information (or not) bool m_fillSvtxTrackStates = true; From bfba39b8bbb1df7f72c8b001e7b57ecfed1ccff1 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Tue, 28 Mar 2023 11:30:40 -0400 Subject: [PATCH 048/468] Last changes --- .../tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc index 39a1250297..511f5e4d77 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc @@ -11,15 +11,12 @@ #include -#include -#include #include #include #include #include -#include -#include + #include #include @@ -169,10 +166,7 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) - //double phi_bins[nphi+1]; - //for (int p=0;p<=nphi;p++){ - // phi_bins[p]=2*pi/nphi*p; - //} + double z_bins[2*nz+1]; for (int z=0;z<=2*nz;z++){ z_bins[z]=-z_rdo+z_rdo/nz*z; From 8b30be43064095f31b422a59dc60b12245818edd Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 28 Mar 2023 15:52:08 -0400 Subject: [PATCH 049/468] confirm silicon+tpot fit works --- offline/packages/trackreco/PHActsTrkFitter.cc | 83 +++++++++++-------- offline/packages/trackreco/PHActsTrkFitter.h | 2 +- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 436451f30a..f1444bc065 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -193,7 +193,6 @@ int PHActsTrkFitter::process_event(PHCompositeNode */*topNode*/) { std::cout << " SvtxTrackMap size is now " << m_trackMap->size() << std::endl; - } return Fun4AllReturnCodes::EVENT_OK; @@ -287,7 +286,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(!tpcseed) { std::cout << "no tpc seed"< 0) + if(Verbosity() > 1) { if(siseed) std::cout << " silicon seed position is (x,y,z) = " << siseed->get_x() << " " << siseed->get_y() << " " << siseed->get_z() << std::endl; std::cout << " tpc seed position is (x,y,z) = " << tpcseed->get_x() << " " << tpcseed->get_y() << " " << tpcseed->get_z() << std::endl; @@ -303,6 +302,27 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) const auto tpcSourceLinks = getSourceLinks(tpcseed, measurements, crossing); sourceLinks.insert( sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end() ); + if(m_fitSiliconMMs) + { + bool sil = siseed != nullptr ? true : false; + bool tpot = false; + + for(auto& sl : sourceLinks) + { + auto key = sl.cluskey(); + if(TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::micromegasId) + { + tpot = true; + } + } + //if(sil && tpot) + if(!sil or !tpot) + { + if(Verbosity() > 3) std::cout << "no silicon+tpot measurements, skipping" << std::endl; + continue; + } + } + // position comes from the silicon seed, unless there is no silicon seed Acts::Vector3 position(0,0,0); if(siseed) @@ -407,12 +427,11 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(m_fitSiliconMMs) { - - unsigned int trid = m_directedTrackMap->size(); + unsigned int trid = m_silmmTrackMap->size(); newTrack.set_id(trid); if( getTrackFitResult(fitOutput, &newTrack) ) - { m_directedTrackMap->insertWithKey(&newTrack, trid); } + { m_silmmTrackMap->insertWithKey(&newTrack, trid); } } else { @@ -480,7 +499,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( if(!cluster) { if(Verbosity() > 0) std::cout << "Failed to get cluster with key " << key << " for track " << m_seedMap->find(track) << std::endl; - else std::cout<< "PHActsTrkFitter :: Key: "<< key << " for track " << m_seedMap->find(track) <find(track) < 0) - { - std::cout << " zinit " << global[2] << " xinit " << global[0] << " yinit " << global[1] << " side " << side << " crossing " << crossing - << " cluskey " << key << " subsurfkey " << subsurfkey << std::endl; - } - // add the global positions to a vector to give to the cluster mover global_raw.push_back(std::make_pair(key, global)); @@ -612,7 +625,9 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( TrkrDefs::cluskey cluskey = global_moved[i].first; Acts::Vector3 global = global_moved[i].second; - if(m_ignoreLayer.find(TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end()) + if(m_ignoreLayer.find(TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end() + or + (m_fitSiliconMMs && TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId)) { if(Verbosity() > 3) { @@ -622,14 +637,6 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( continue; } - if(m_fitSiliconMMs) - { - if(TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) - { - continue; - } - } - auto cluster = m_clusterContainer->findCluster(cluskey); Surface surf = m_tGeometry->maps().getSurface(cluskey, cluster); @@ -665,7 +672,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( localPos(1) = loct(1); } - if(Verbosity() > 0) + if(Verbosity() > 1) { std::cout << " cluster global after mover: " << global << std::endl; std::cout << " cluster local X " << cluster->getLocalX() << " cluster local Y " << cluster->getLocalY() << std::endl; @@ -999,20 +1006,6 @@ int PHActsTrkFitter::createNodes(PHCompositeNode* topNode) dstNode->addNode(svtxNode); } - if(m_fitSiliconMMs) - { - m_directedTrackMap = findNode::getClass(topNode, - "SvtxSiliconMMTrackMap"); - if(!m_directedTrackMap) - { - /// Copy this trackmap, then use it for the rest of processing - m_directedTrackMap = new SvtxTrackMap_v2; - - PHIODataNode *trackNode = - new PHIODataNode(m_directedTrackMap,"SvtxSiliconMMTrackMap","PHObject"); - svtxNode->addNode(trackNode); - } - } m_trajectories = findNode::getClass>(topNode, "ActsTrajectories"); if(!m_trajectories) @@ -1041,6 +1034,24 @@ int PHActsTrkFitter::createNodes(PHCompositeNode* topNode) svtxNode->addNode(node); } + if(m_fitSiliconMMs) + { + m_silmmTrackMap = findNode::getClass(topNode, + "SvtxSiliconMMTrackMap"); + + if(!m_silmmTrackMap) + { + /// Copy this trackmap, then use it for the rest of processing + m_silmmTrackMap = new SvtxTrackMap_v2; + + PHIODataNode *trackNode = + new PHIODataNode(m_silmmTrackMap, + "SvtxSiliconMMTrackMap", + "PHObject"); + svtxNode->addNode(trackNode); + } + } + if(m_actsEvaluator) { m_seedTracks = findNode::getClass(topNode,_seed_track_map_name); diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index f1868df916..047f281a0d 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -149,7 +149,7 @@ class PHActsTrkFitter : public SubsysReco /// TrackMap containing SvtxTracks alignmentTransformationContainer *m_alignmentTransformationMap = nullptr; // added for testing purposes SvtxTrackMap *m_trackMap = nullptr; - SvtxTrackMap *m_directedTrackMap = nullptr; + SvtxTrackMap *m_silmmTrackMap = nullptr; TrkrClusterContainer *m_clusterContainer = nullptr; TrackSeedContainer *m_seedMap = nullptr; TrackSeedContainer *m_tpcSeeds = nullptr; From b167022f37eb5cebce5c8f83b24e9b5ad64aba8d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 29 Mar 2023 08:58:52 -0400 Subject: [PATCH 050/468] clean up mm sl check --- offline/packages/trackreco/PHActsTrkFitter.cc | 29 ++++++++++--------- offline/packages/trackreco/PHActsTrkFitter.h | 2 ++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index f1444bc065..614c5e5e6e 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -304,19 +304,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(m_fitSiliconMMs) { - bool sil = siseed != nullptr ? true : false; - bool tpot = false; - - for(auto& sl : sourceLinks) - { - auto key = sl.cluskey(); - if(TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::micromegasId) - { - tpot = true; - } - } - //if(sil && tpot) - if(!sil or !tpot) + if(!checkMM(sourceLinks) or !siseed) { if(Verbosity() > 3) std::cout << "no silicon+tpot measurements, skipping" << std::endl; continue; @@ -468,6 +456,21 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } +bool PHActsTrkFitter::checkMM(SourceLinkVec& sls) +{ + bool tpot = false; + for(auto& sl : sls) + { + auto key = sl.cluskey(); + if(TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::micromegasId) + { + tpot = true; + } + } + + return tpot; +} + //___________________________________________________________________________________ SourceLinkVec PHActsTrkFitter::getSourceLinks( TrackSeed* track, diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 047f281a0d..2360253243 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -137,6 +137,8 @@ class PHActsTrkFitter : public SubsysReco Acts::BoundSymMatrix setDefaultCovariance() const; void printTrackSeed(const ActsTrackFittingAlgorithm::TrackParameters& seed) const; + bool checkMM(SourceLinkVec& sls); + /// Event counter int m_event = 0; From 7bb37758ef3e9d262af3ebbd0fcb732c54f4b444 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Wed, 29 Mar 2023 09:42:44 -0400 Subject: [PATCH 051/468] fixme update --- simulation/g4simulation/g4eval/Tools.cc | 16 +++++++++++++--- .../g4eval/TruthRecoTrackMatching.cc | 13 +++++++++++-- .../g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/Tools.cc index 07e38fa726..9be265a419 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/Tools.cc @@ -164,6 +164,7 @@ namespace G4Eval { in_intt = (layer >2 && layer <7); in_tpc = (layer >6 && layer <55); + std::cout << "FIXME Comparing layer: " << layer << std::endl; float phi_step = m_phistep[layer]; float z_step = in_mvtx ? m_zstep_mvtx : m_zstep_tpc; @@ -183,19 +184,25 @@ namespace G4Eval { zsize_T = clus_R->getZSize() * z_step; } - float dphi = fabs(phi_T-phi_R); - while (dphi > M_PI) dphi = fabs(dphi-2*M_PI); + phi_delta = fabs(phi_T-phi_R); + while (phi_delta > M_PI) phi_delta = fabs(phi_delta-2*M_PI); z_delta = fabs (z_T-z_R); float phi_stat = (m_nphi_widths * phisize_R ); bool is_match = (phi_delta < phi_stat); float fit_statistic = (phi_delta / phi_stat); + float z_stat = 0; if (!in_intt) { - float z_stat = (m_nz_widths * zsize_R ); + z_stat = (m_nz_widths * zsize_R ); // FIXME + /* float z_stat = (m_nz_widths * zsize_R ); */ is_match = is_match && (z_delta < z_stat); fit_statistic += z_delta / z_stat; } + std::cout << " FIXME razberry comp layer ("<get_tpc_seed()!=nullptr } , no_data { !in_silicon && !has_tpc } { + std::cout << " FIMXE: new track apple has_tpc: " << has_tpc << " in_silicon " << in_silicon << std::endl; } ClusKeyIter ClusKeyIter::begin() { @@ -307,6 +315,7 @@ namespace G4Eval { int ClusCntr::addClusKeys(SvtxTrack* track) { svtx_keys.clear(); for (auto ckey : ClusKeyIter(track)) { + std::cout << "FIXME: orange layer: " << ((int)TrkrDefs::getLayer(ckey)) << std::endl; svtx_keys.push_back( {TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey} ); } std::sort(svtx_keys.begin(), svtx_keys.end()); @@ -316,6 +325,7 @@ namespace G4Eval { int ClusCntr::addClusKeys(TrkrTruthTrack* track) { phg4_keys.clear(); for (auto ckey : track->getClusters()) { + std::cout << "FIXME: blue TRUE layer: " << ((int)TrkrDefs::getLayer(ckey)) << std::endl; phg4_keys.push_back( {TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey} ); } std::sort(phg4_keys.begin(), phg4_keys.end()); diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc index 563d9630f2..171bda4dcb 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc @@ -94,8 +94,6 @@ int TruthRecoTrackMatching::InitRun(PHCompositeNode *topNode) //` m_nmatched_id_reco = &(m_EmbRecoMatchContainer->map_nTruthPerReco()); m_nmatched_id_true = &(m_EmbRecoMatchContainer->map_nRecoPerTruth()); return Fun4AllReturnCodes::EVENT_OK; - if (Verbosity()>50) topNode->print(); - return 0; } @@ -130,6 +128,16 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) auto index_reco = reco->first; auto track = reco->second; recoData.push_back( {track->get_phi(), track->get_eta(), track->get_pt(), index_reco } ); + std::cout << " FIXME svtxtrack has seed? PEAR " << (reco->second->get_silicon_seed()==nullptr) << std::endl; + } + if (true) { // FIXME + std::cout << " FIXME banana all Svtx Clusters: " << std::endl; + for (auto& hitsetkey : m_RecoClusterContainer->getHitSetKeys()) { + auto c_range = m_RecoClusterContainer->getClusters(hitsetkey); + for (auto& iter = c_range.first; iter != c_range.second; ++iter) { + std::cout << " FIXME reco cluster layer peach : " << ((int)TrkrDefs::getLayer(iter->first)) << std::endl; + } + } } // sort the recoData table by phi std::sort(recoData.begin(), recoData.end(), CompRECOtoPhi()); @@ -864,6 +872,7 @@ void TruthRecoTrackMatching::fill_tree() { m_i1_true_matched.push_back(cnt); ++itrk; } + // fill clusters of matched reco tracks std::set set_reco_matched; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index ff9f97dc42..1e24c7062d 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -339,7 +339,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) /* if (Verbosity()) std::cout << " truth clusterer was a null pointer " << std::endl; */ truth_clusterer = new TpcClusterBuilder(truthclustercontainer, m_tGeometry, seggeo); } else { - if (Verbosity()) std::cout << " truth clusterer was NOT a null pointer " << std::endl; + if (Verbosity()>10) std::cout << " truth clusterer was NOT a null pointer " << std::endl; } From dcd82e4b025061c5a0e693d4590ee26271ee33d2 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Wed, 29 Mar 2023 10:31:40 -0400 Subject: [PATCH 052/468] fix bug --e ``phi_delta'' in place of ``d_phi'' in g4tools.cc --- .../g4simulation/g4eval/FillTruthRecoMatchTree.h | 2 +- simulation/g4simulation/g4eval/Makefile.am | 4 ++-- .../g4simulation/g4eval/TruthRecoTrackMatching.cc | 12 +----------- .../g4simulation/g4eval/TruthRecoTrackMatching.h | 2 +- .../g4simulation/g4eval/{Tools.cc => g4tools.cc} | 12 ++---------- .../g4simulation/g4eval/{Tools.h => g4tools.h} | 0 6 files changed, 7 insertions(+), 25 deletions(-) rename simulation/g4simulation/g4eval/{Tools.cc => g4tools.cc} (95%) rename simulation/g4simulation/g4eval/{Tools.h => g4tools.h} (100%) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index 7142f2e108..31cea9a01a 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -43,7 +43,7 @@ * save un-matched Svtx tracks = false */ -#include "Tools.h" +#include "g4tools.h" #include #include diff --git a/simulation/g4simulation/g4eval/Makefile.am b/simulation/g4simulation/g4eval/Makefile.am index 072ff97e27..f3548b4ee8 100644 --- a/simulation/g4simulation/g4eval/Makefile.am +++ b/simulation/g4simulation/g4eval/Makefile.am @@ -64,7 +64,7 @@ pkginclude_HEADERS = \ SvtxTruthEval.h \ SvtxTruthRecoTableEval.h \ SvtxVertexEval.h \ - Tools.h \ + g4tools.h \ TrackEvaluation.h \ TrackEvaluationContainer.h \ TrackEvaluationContainerv1.h \ @@ -112,7 +112,7 @@ libg4eval_la_SOURCES = \ SvtxTruthEval.cc \ SvtxTruthRecoTableEval.cc \ SvtxVertexEval.cc \ - Tools.cc \ + g4tools.cc \ TrackEvaluation.cc \ TrackSeedTrackMapConverter.cc \ TruthRecoTrackMatching.cc diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc index 171bda4dcb..0a4a8f42cb 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc @@ -1,5 +1,5 @@ #include "TruthRecoTrackMatching.h" -#include "Tools.h" +#include "g4tools.h" #include #include @@ -128,16 +128,6 @@ int TruthRecoTrackMatching::process_event(PHCompositeNode* topnode) auto index_reco = reco->first; auto track = reco->second; recoData.push_back( {track->get_phi(), track->get_eta(), track->get_pt(), index_reco } ); - std::cout << " FIXME svtxtrack has seed? PEAR " << (reco->second->get_silicon_seed()==nullptr) << std::endl; - } - if (true) { // FIXME - std::cout << " FIXME banana all Svtx Clusters: " << std::endl; - for (auto& hitsetkey : m_RecoClusterContainer->getHitSetKeys()) { - auto c_range = m_RecoClusterContainer->getClusters(hitsetkey); - for (auto& iter = c_range.first; iter != c_range.second; ++iter) { - std::cout << " FIXME reco cluster layer peach : " << ((int)TrkrDefs::getLayer(iter->first)) << std::endl; - } - } } // sort the recoData table by phi std::sort(recoData.begin(), recoData.end(), CompRECOtoPhi()); diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h index bbfd6c98af..d43274b609 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h @@ -1,7 +1,7 @@ #ifndef TRUTHTRKMATCHER__H #define TRUTHTRKMATCHER__H -#include "Tools.h" // has some G4Eval tools (TrkrClusterComparer) +#include "g4tools.h" // has some G4Eval tools (TrkrClusterComparer) #include #include diff --git a/simulation/g4simulation/g4eval/Tools.cc b/simulation/g4simulation/g4eval/g4tools.cc similarity index 95% rename from simulation/g4simulation/g4eval/Tools.cc rename to simulation/g4simulation/g4eval/g4tools.cc index 9be265a419..0f8fe9ff8b 100644 --- a/simulation/g4simulation/g4eval/Tools.cc +++ b/simulation/g4simulation/g4eval/g4tools.cc @@ -1,4 +1,4 @@ -#include "Tools.h" +#include "g4tools.h" #include #include @@ -164,7 +164,6 @@ namespace G4Eval { in_intt = (layer >2 && layer <7); in_tpc = (layer >6 && layer <55); - std::cout << "FIXME Comparing layer: " << layer << std::endl; float phi_step = m_phistep[layer]; float z_step = in_mvtx ? m_zstep_mvtx : m_zstep_tpc; @@ -194,15 +193,10 @@ namespace G4Eval { float fit_statistic = (phi_delta / phi_stat); float z_stat = 0; if (!in_intt) { - z_stat = (m_nz_widths * zsize_R ); // FIXME - /* float z_stat = (m_nz_widths * zsize_R ); */ + z_stat = (m_nz_widths * zsize_R ); is_match = is_match && (z_delta < z_stat); fit_statistic += z_delta / z_stat; } - std::cout << " FIXME razberry comp layer ("<getClusters()) { - std::cout << "FIXME: blue TRUE layer: " << ((int)TrkrDefs::getLayer(ckey)) << std::endl; phg4_keys.push_back( {TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey} ); } std::sort(phg4_keys.begin(), phg4_keys.end()); diff --git a/simulation/g4simulation/g4eval/Tools.h b/simulation/g4simulation/g4eval/g4tools.h similarity index 100% rename from simulation/g4simulation/g4eval/Tools.h rename to simulation/g4simulation/g4eval/g4tools.h From 74d2e695247e17a7793c87b75288baea6ebab324 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 29 Mar 2023 10:44:29 -0400 Subject: [PATCH 053/468] adapt to cluster v5 --- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index e75599d9ab..f72046c6a1 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -333,7 +333,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) clusZ = globClusPos(2); // cluster errors - if( m_cluster_version >= 4 ) + if( m_cluster_version == 4 ) { const auto errors_square = m_cluster_error_parametrization.get_cluster_error( track->get_tpc_seed(), cluster, clusR, cluskey ); clusRPhiErr = std::sqrt( errors_square.first ); From 3924fd45c7b49baa6f0988ab4c1e4ea26fd3e1a1 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 29 Mar 2023 11:15:19 -0400 Subject: [PATCH 054/468] Dealing with variable definitions --- .../readDigitalCurrents.h | 34 +++++++++---------- .../tpc/fillSpaceChargeMaps/Makefile.am | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h index 6768bbaeb1..4147f1242b 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef READDIGITALCURRENTS_H -#define READDIGITALCURRENTS_H +#ifndef READDIGITALCURRENTS_READDIGITALCURRENTS_H +#define READDIGITALCURRENTS_READDIGITALCURRENTS_H #include @@ -75,13 +75,13 @@ class readDigitalCurrents : public SubsysReco //double pi = 3.14159265358979323846;//2 * acos(0.0); protected: - Fun4AllHistoManager *hm; + Fun4AllHistoManager *hm = nullptr; std::string _filename; - //TFile *outfile; + //TFile *outfile = nullptr; std::map _timestamps; std::vector _keys; - float _ampIBFfrac; - int _collSyst; + float _ampIBFfrac = 0.02; + int _collSyst = 0; std::ofstream myCSVFile; private: @@ -92,17 +92,17 @@ class readDigitalCurrents : public SubsysReco int _f_ccgc = 0; - TH2* _h_modules_measuredibf; - - TH1* _h_R; - TH1* _h_hits; - TH3* _h_DC_SC; - TH2* _h_DC_SC_XY; - TH2* _h_hit_XY; - TH2* _h_DC_E; - TH3* _h_SC_ibf; - float _event_timestamp; - float _event_bunchXing; + TH2* _h_modules_measuredibf = nullptr; + + TH1* _h_R = nullptr; + TH1* _h_hits = nullptr; + TH3* _h_DC_SC = nullptr; + TH2* _h_DC_SC_XY = nullptr; + TH2* _h_hit_XY = nullptr; + TH2* _h_DC_E = nullptr; + TH3* _h_SC_ibf = nullptr; + float _event_timestamp = 0; + float _event_bunchXing = 0; //double pi = 2 * acos(0.0); double adc_pedestal=0.;//74.4; diff --git a/calibrations/tpc/fillSpaceChargeMaps/Makefile.am b/calibrations/tpc/fillSpaceChargeMaps/Makefile.am index 5590f57386..ae1a48d25e 100644 --- a/calibrations/tpc/fillSpaceChargeMaps/Makefile.am +++ b/calibrations/tpc/fillSpaceChargeMaps/Makefile.am @@ -7,7 +7,7 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib + -L$(OFFLINE_MAIN)/lib pkginclude_HEADERS = \ fillSpaceChargeMaps.h \ From 113945fb24682e80ed74be165d86b9f1c3e8491f Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 29 Mar 2023 11:44:35 -0400 Subject: [PATCH 055/468] split `TRKR_HITSET` by subsystem --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 338 ++++++++++-------- .../g4simulation/g4eval/SvtxEvaluator.cc | 2 +- 2 files changed, 184 insertions(+), 156 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index f36d48ac51..6e1b0a9005 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -398,50 +398,54 @@ void TrkrNtuplizer::printOutputInfo(PHCompositeNode* topNode) cout << "===Tracking Summary============================" << endl; - TrkrHitSetContainer* hitsetmap = findNode::getClass(topNode, "TRKR_HITSET"); + unsigned int nclusters[100] = {0}; + unsigned int nhits[100] = {0}; - TrkrClusterContainer* clustermap = findNode::getClass(topNode, "CORRECTED_TRKR_CLUSTER"); - if (!clustermap) + for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) { - clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); - } + TrkrHitSetContainer* hitsetmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); - unsigned int nclusters[100] = {0}; - unsigned int nhits[100] = {0}; + TrkrClusterContainer* clustermap = findNode::getClass(topNode, "CORRECTED_TRKR_CLUSTER"); + if (!clustermap) + { + clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); + } - ActsGeometry* tgeometry = findNode::getClass(topNode, "ActsGeometry"); - if (!tgeometry) - { - std::cout << PHWHERE << "No Acts geometry on node tree. Can't continue." - << std::endl; - } + ActsGeometry* tgeometry = findNode::getClass(topNode, "ActsGeometry"); - if (hitsetmap) - { - TrkrHitSetContainer::ConstRange all_hitsets = hitsetmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; - hitsetiter != all_hitsets.second; - ++hitsetiter) + if (!tgeometry) { - // we have a single hitset, get the layer - unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); + std::cout << PHWHERE << "No Acts geometry on node tree. Can't continue." + << std::endl; + } - // count all hits in this hitset - TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - ++nhits[layer]; - } - auto range = clustermap->getClusters(hitsetiter->first); - for (auto clusIter = range.first; clusIter != range.second; ++clusIter) + if (hitsetmap) + { + TrkrHitSetContainer::ConstRange all_hitsets = hitsetmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; + hitsetiter != all_hitsets.second; + ++hitsetiter) { - const auto cluskey = clusIter->first; - // const auto cluster = clusIter->second; - // unsigned int layer = TrkrDefs::getLayer(cluskey); - nclusters[TrkrDefs::getLayer(cluskey)]++; + // we have a single hitset, get the layer + unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); + + // count all hits in this hitset + TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + ++nhits[layer]; + } + auto range = clustermap->getClusters(hitsetiter->first); + for (auto clusIter = range.first; clusIter != range.second; ++clusIter) + { + const auto cluskey = clusIter->first; + // const auto cluster = clusIter->second; + // unsigned int layer = TrkrDefs::getLayer(cluskey); + nclusters[TrkrDefs::getLayer(cluskey)]++; + } } } } @@ -525,37 +529,41 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) float occ31 = 0; float occ316 = 0; - TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET"); - if (hitmap_in) + for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) { - TrkrHitSetContainer::ConstRange all_hitsets = hitmap_in->getHitSets(); - for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; - hitsetiter != all_hitsets.second; - ++hitsetiter) + TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + + if (hitmap_in) { - // we have a single hitset, get the layer - unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); - if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + TrkrHitSetContainer::ConstRange all_hitsets = hitmap_in->getHitSets(); + for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; + hitsetiter != all_hitsets.second; + ++hitsetiter) { - // count all hits in this hitset - TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) + // we have a single hitset, get the layer + unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { - nhit[layer]++; - nhit_tpc_all++; - if ((float) layer == _nlayers_maps + _nlayers_intt) - { - nhit_tpc_in++; - } - if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc - 1) + // count all hits in this hitset + TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) { - nhit_tpc_out++; - } - if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) - { - nhit_tpc_mid++; + nhit[layer]++; + nhit_tpc_all++; + if ((float) layer == _nlayers_maps + _nlayers_intt) + { + nhit_tpc_in++; + } + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc - 1) + { + nhit_tpc_out++; + } + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) + { + nhit_tpc_mid++; + } } } } @@ -756,89 +764,92 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) _timer->restart(); } // need things off of the DST... - TrkrHitSetContainer* hitmap = findNode::getClass(topNode, "TRKR_HITSET"); - PHG4TpcCylinderGeomContainer* geom_container_local = - findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); - if (!geom_container_local) + for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) { - std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; - return; - } + TrkrHitSetContainer* hitmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + PHG4TpcCylinderGeomContainer* geom_container_local = + findNode::getClass(topNode, "CYLINDERCELLGEOM_SVTX"); + if (!geom_container_local) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; + return; + } - if (hitmap) - { - TrkrHitSetContainer::ConstRange all_hitsets = hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) + if (hitmap) { - TrkrDefs::hitsetkey hitset_key = iter->first; - TrkrHitSet* hitset = iter->second; - - // get all hits for this hitset - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) + TrkrHitSetContainer::ConstRange all_hitsets = hitmap->getHitSets(); + for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; + iter != all_hitsets.second; + ++iter) { - TrkrDefs::hitkey hit_key = hitr->first; - TrkrHit* hit = hitr->second; - float event = _ievent; - float hitID = hit_key; - float e = hit->getEnergy(); - float adc = hit->getAdc(); - float layer_local = TrkrDefs::getLayer(hitset_key); - float sector = TpcDefs::getSectorId(hitset_key); - float side = TpcDefs::getSide(hitset_key); - float cellID = 0; - float ecell = hit->getAdc(); - - float phibin = NAN; - float tbin = NAN; - float phi = NAN; - float z = NAN; - - if (layer_local >= _nlayers_maps + _nlayers_intt && layer_local < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + TrkrDefs::hitsetkey hitset_key = iter->first; + TrkrHitSet* hitset = iter->second; + + // get all hits for this hitset + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) { - PHG4TpcCylinderGeom* GeoLayer_local = geom_container_local->GetLayerCellGeom(layer_local); - phibin = (float) TpcDefs::getPad(hit_key); - tbin = (float) TpcDefs::getTBin(hit_key); - phi = GeoLayer_local->get_phicenter(phibin); - - double zdriftlength = tbin * m_tGeometry->get_drift_velocity() * AdcClockPeriod; - // convert z drift length to z position in the TPC - // cout << " tbin: " << tbin << " vdrift " <get_drift_velocity() << " l drift: " << zdriftlength <get_zbins(); - double m_tdriftmax = AdcClockPeriod * NTBins / 2.0; - double clusz = (m_tdriftmax * m_tGeometry->get_drift_velocity()) - zdriftlength; - if (side == 0) + TrkrDefs::hitkey hit_key = hitr->first; + TrkrHit* hit = hitr->second; + float event = _ievent; + float hitID = hit_key; + float e = hit->getEnergy(); + float adc = hit->getAdc(); + float layer_local = TrkrDefs::getLayer(hitset_key); + float sector = TpcDefs::getSectorId(hitset_key); + float side = TpcDefs::getSide(hitset_key); + float cellID = 0; + float ecell = hit->getAdc(); + + float phibin = NAN; + float tbin = NAN; + float phi = NAN; + float z = NAN; + + if (layer_local >= _nlayers_maps + _nlayers_intt && layer_local < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { - clusz = -clusz; + PHG4TpcCylinderGeom* GeoLayer_local = geom_container_local->GetLayerCellGeom(layer_local); + phibin = (float) TpcDefs::getPad(hit_key); + tbin = (float) TpcDefs::getTBin(hit_key); + phi = GeoLayer_local->get_phicenter(phibin); + + double zdriftlength = tbin * m_tGeometry->get_drift_velocity() * AdcClockPeriod; + // convert z drift length to z position in the TPC + // cout << " tbin: " << tbin << " vdrift " <get_drift_velocity() << " l drift: " << zdriftlength <get_zbins(); + double m_tdriftmax = AdcClockPeriod * NTBins / 2.0; + double clusz = (m_tdriftmax * m_tGeometry->get_drift_velocity()) - zdriftlength; + if (side == 0) + { + clusz = -clusz; + } + z = clusz; } - z = clusz; - } - float hit_data[] = { - event, - (float) _iseed, - hitID, - e, - adc, - layer_local, - sector, - side, - cellID, - ecell, - (float) phibin, - (float) tbin, - phi, - z, - nhit_tpc_all, - nhit_tpc_in, - nhit_tpc_mid, - nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; - - _ntp_hit->Fill(hit_data); + float hit_data[] = { + event, + (float) _iseed, + hitID, + e, + adc, + layer_local, + sector, + side, + cellID, + ecell, + (float) phibin, + (float) tbin, + phi, + z, + nhit_tpc_all, + nhit_tpc_in, + nhit_tpc_mid, + nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; + + _ntp_hit->Fill(hit_data); + } } } } @@ -873,7 +884,15 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - TrkrHitSetContainer* hitsets = findNode::getClass(topNode, "TRKR_HITSET"); + + std::map hitsetsmap; + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitsets) + hitsetsmap[trkrID] = hitsets; + } + TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); if (Verbosity() > 1) @@ -894,7 +913,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) { cout << "no clusterhitmap" << endl; } - if (hitsets != nullptr) + if (hitsetsmap.size() != 0) { cout << "got hitsets" << endl; } @@ -904,7 +923,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } } - if (clustermap && clusterhitmap && hitsets) + if (clustermap && clusterhitmap && hitsetsmap.size() != 0) { for (const auto& hitsetkey : clustermap->getHitSetKeys()) { @@ -1004,26 +1023,35 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } */ float sumadc = 0; - TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey_local); - std::pair::const_iterator, std::multimap::const_iterator> - hitrange = clusterhitmap->getHits(cluster_key); - for (std::multimap::const_iterator - clushititer = hitrange.first; - clushititer != hitrange.second; ++clushititer) + + auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); + if (hitsetsmap_iter != hitsetsmap.end()) { - TrkrHit* hit = hitset->second->getHit(clushititer->second); - if (!hit) + TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; + assert(hitsets); + + TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey_local); + std::pair::const_iterator, std::multimap::const_iterator> + hitrange = clusterhitmap->getHits(cluster_key); + for (std::multimap::const_iterator + clushititer = hitrange.first; + clushititer != hitrange.second; ++clushititer) { - continue; - } + TrkrHit* hit = hitset->second->getHit(clushititer->second); + if (!hit) + { + continue; + } - ++size; - sumadc += (hit->getAdc() - 70); - if ((hit->getAdc() - 70) > maxadc) - { - maxadc = (hit->getAdc() - 70); + ++size; + sumadc += (hit->getAdc() - 70); + if ((hit->getAdc() - 70) > maxadc) + { + maxadc = (hit->getAdc() - 70); + } } - } + } // if (hitsetsmap_iter != hitsetsmap.end()) + e = sumadc; float trackID = NAN; diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 79f996f4c3..e09965efbd 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1889,8 +1889,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) if ((hit->getAdc() - 70) > maxadc) maxadc = (hit->getAdc() - 70); } - e = sumadc; } + e = sumadc; float trackID = NAN; if (track!=NULL) trackID = track->get_id(); From 4f137325284230705743ffe5ec4bb0b381bb342c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 29 Mar 2023 21:00:39 -0400 Subject: [PATCH 056/468] Update Fun4All_FillDCMap.C suppress cppcheck warnings for R__LOAD_LIBRARY --- .../tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C index 6b613bcd18..3d70fe33cb 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C @@ -11,9 +11,11 @@ #include - +// cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libfun4all.so) +// cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libreadDigitalCurrents.so) +// cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libg4dst.so) void Fun4All_FillDCMap( const int nEvents = 1000, const int eventsInFileStart = 0, const int eventsBeamCrossing = 1508071, const string &fname = "/sphenix/user/shulga/Work/IBF/macros/detectors/sPHENIX/Files/DST_G4Hits_sHijing_0-12fm_005000_006000.root", const string &foutputname = "./Files/hists_G4Hits_sHijing_0-12fm_000000_001000.root" )//DST_G4sPHENIX_1000evt.root")//G4sPHENIX.root" ) @@ -60,4 +62,4 @@ void Fun4All_FillDCMap( const int nEvents = 1000, const int eventsInFileStart = cout << endl << "gSystem->Exit(0)" << endl; gSystem->Exit(0); -} \ No newline at end of file +} From 12e48839292924010b30d0f08ec412963f397b67 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 30 Mar 2023 07:47:29 -0400 Subject: [PATCH 057/468] Update readDigitalCurrents.h remove superfluous but confusing #pragma once (this can have bad side effects, please use the usual include guards) --- calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h index 4147f1242b..88b7801629 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h @@ -10,9 +10,6 @@ #include #include -#pragma once -//#include - class Fun4AllHistoManager; class PHCompositeNode; From b218a962041aa636356091c78e6c8168f2c88a24 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 08:21:59 -0400 Subject: [PATCH 058/468] testing --- .../packages/trackbase_historic/TrackSeed_v1.cc | 14 +++++++++++--- offline/packages/trackreco/PHSimpleKFProp.cc | 8 +++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 9746b249c5..7f85763488 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -1,7 +1,7 @@ #include "TrackSeed_v1.h" #include - +#include namespace { @@ -89,12 +89,20 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, if(layer < startLayer or layer > endLayer) { continue; } + auto clus = dynamic_cast(clusters->findCluster(key)); + std::cout << "clus edge is " << (int)clus->getEdge() << std::endl; + if(clus->getEdge() > 0) + { continue; } Acts::Vector3 pos = tGeometry->getGlobalPosition( - key, clusters->findCluster(key)); + key, clus); positions.insert(std::make_pair(key, pos)); } - + if(positions.size() < 3) + { + std::cout << "Can't circle fit less than 3 points " << std::endl; + return; + } circleFitByTaubin(positions, startLayer, endLayer); } diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index fd751f6b84..6c55d0ebb7 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -1168,14 +1168,16 @@ std::vector PHSimpleKFProp::RemoveBadClusters(const std::vector& seeds, PositionMap& positions) +void PHSimpleKFProp::publishSeeds(std::vector& seeds, PositionMap& /*positions*/) { for(auto& seed: seeds ) { /// The ALICEKF gives a better charge determination at high pT int q = seed.get_charge(); - seed.circleFitByTaubin(positions,7,55); - seed.lineFit(positions,7,55); + seed.circleFitByTaubin(_cluster_map, _tgeometry, 7, 55); + seed.lineFit(_cluster_map,_tgeometry, 7, 55); + //seed.circleFitByTaubin(positions,7,55); + //seed.lineFit(positions,7,55); seed.set_qOverR(fabs(seed.get_qOverR()) * q); _track_map->insert(&seed); From 5fd24268d8232bec1c2f83831e02c9ecc78573f0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 08:33:25 -0400 Subject: [PATCH 059/468] add base class functions --- offline/packages/trackbase/TrkrCluster.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index d3bf6aef46..50738190f5 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -62,10 +62,17 @@ class TrkrCluster : public PHObject // virtual void setAdc(unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } - + virtual void setMaxAdc(uint16_t) {} + virtual unsigned int getMaxAdc() {return UINT_MAX; } + virtual char getOverlap() { return std::numeric_limits::max(); } + virtual void setOverlap(char) {} + virtual char getEdge(){ return std::numeric_limits::max(); } + virtual void setEdge(char) {} virtual void setTime(const float) {} virtual float getTime() const { return NAN;} + + // // convenience interface // From 14e803aac2d12aa7bbbec53cf69c8fe46f1bdef0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 09:06:19 -0400 Subject: [PATCH 060/468] testing --- offline/packages/trackbase_historic/TrackSeed_v1.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 7f85763488..04ec922347 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -1,7 +1,8 @@ #include "TrackSeed_v1.h" +#include #include -#include + namespace { @@ -89,7 +90,7 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, if(layer < startLayer or layer > endLayer) { continue; } - auto clus = dynamic_cast(clusters->findCluster(key)); + auto clus = clusters->findCluster(key); std::cout << "clus edge is " << (int)clus->getEdge() << std::endl; if(clus->getEdge() > 0) { continue; } From 10fa3e5d2ec7e3db51526650148fe4cfc657fb0d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 09:12:02 -0400 Subject: [PATCH 061/468] fix run time warnings --- offline/packages/trackbase/TrkrCluster.h | 6 +++--- offline/packages/trackbase/TrkrClusterv5.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 50738190f5..cc60e8ca3b 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -63,10 +63,10 @@ class TrkrCluster : public PHObject virtual void setAdc(unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } virtual void setMaxAdc(uint16_t) {} - virtual unsigned int getMaxAdc() {return UINT_MAX; } - virtual char getOverlap() { return std::numeric_limits::max(); } + virtual unsigned int getMaxAdc() const {return UINT_MAX; } + virtual char getOverlap() const { return std::numeric_limits::max(); } virtual void setOverlap(char) {} - virtual char getEdge(){ return std::numeric_limits::max(); } + virtual char getEdge() const { return std::numeric_limits::max(); } virtual void setEdge(char) {} virtual void setTime(const float) {} virtual float getTime() const { return NAN;} diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 196015be33..30ed9a9a1b 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -75,11 +75,11 @@ class TrkrClusterv5 : public TrkrCluster m_adc = adc; } - unsigned int getMaxAdc() const { + unsigned int getMaxAdc() const override { return m_maxadc; } - void setMaxAdc(uint16_t maxadc) { + void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } @@ -127,11 +127,11 @@ class TrkrClusterv5 : public TrkrCluster float getZSize() const override { return (float) m_zsize; } void setZSize(char zsize) { m_zsize = zsize; } - char getOverlap() { return m_overlap; } - void setOverlap(char overlap) { m_overlap = overlap; } + char getOverlap() const override{ return m_overlap; } + void setOverlap(char overlap) override { m_overlap = overlap; } - char getEdge() { return m_edge; } - void setEdge(char edge) { m_edge = edge; } + char getEdge() const override{ return m_edge; } + void setEdge(char edge) override { m_edge = edge; } //float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} From 8b4e2b330b4a97d7c0e2b0bc74edfa258ac61e0b Mon Sep 17 00:00:00 2001 From: bogui56 Date: Thu, 30 Mar 2023 11:01:58 -0400 Subject: [PATCH 062/468] adc truncation fix --- offline/packages/trackbase/TrkrClusterv5.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 196015be33..96d701187c 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -66,9 +66,7 @@ class TrkrClusterv5 : public TrkrCluster // cluster info // unsigned int getAdc() const override { - uint8_t tmp = m_adc; - return tmp ; - + return m_adc ; } void setAdc(unsigned int adc) override { From f1553c3620564c1510bc42b062e2d1c19684c2f4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 11:03:39 -0400 Subject: [PATCH 063/468] iwyu --- simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index ff9f97dc42..abbe1145b3 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -23,7 +23,6 @@ #include #include -#include #include #include From 3e941d6b92454275a86df6c93df886bcce4b29af Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 11:04:00 -0400 Subject: [PATCH 064/468] fix overshadowed functions --- offline/packages/trackbase/TrkrCluster.h | 2 +- offline/packages/trackbase/TrkrClusterv4.h | 14 +++++++------- offline/packages/trackbase/TrkrClusterv5.h | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index cc60e8ca3b..46edfc90ce 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -70,7 +70,7 @@ class TrkrCluster : public PHObject virtual void setEdge(char) {} virtual void setTime(const float) {} virtual float getTime() const { return NAN;} - + virtual char getSize() const {return std::numeric_limits::max(); } // diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index 19f89a8041..870e0f74aa 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -77,14 +77,14 @@ class TrkrClusterv4 : public TrkrCluster m_adc |= tmp; } - unsigned int getMaxAdc() const { + unsigned int getMaxAdc() const override { uint8_t tmp = (m_adc >> 8); unsigned int out = 0; out |= tmp; return out; } - void setMaxAdc(uint16_t maxadc) { + void setMaxAdc(uint16_t maxadc) override { if(maxadc>0xff)maxadc=0xff; uint16_t tmp = (maxadc << 8); m_adc |= tmp; @@ -120,7 +120,7 @@ class TrkrClusterv4 : public TrkrCluster void setError(unsigned int, unsigned int, float) override { std::cout << "Deprecated seterr trkrcluster function!" << std::endl; } - char getSize() { return m_phisize * m_zsize; } + char getSize() const override { return m_phisize * m_zsize; } // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } @@ -129,11 +129,11 @@ class TrkrClusterv4 : public TrkrCluster float getZSize() const override { return (float) m_zsize; } void setZSize(char zsize) { m_zsize = zsize; } - char getOverlap() { return m_overlap; } - void setOverlap(char overlap) { m_overlap = overlap; } + char getOverlap() const override { return m_overlap; } + void setOverlap(char overlap) override { m_overlap = overlap; } - char getEdge() { return m_edge; } - void setEdge(char edge) { m_edge = edge; } + char getEdge() const override { return m_edge; } + void setEdge(char edge) override { m_edge = edge; } //float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 30ed9a9a1b..8dae85e46d 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -118,7 +118,7 @@ class TrkrClusterv5 : public TrkrCluster void setError(unsigned int, unsigned int, float) override { std::cout << "Deprecated seterr trkrcluster function!" << std::endl; } - char getSize() { return m_phisize * m_zsize; } + char getSize() const override { return m_phisize * m_zsize; } // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } @@ -127,7 +127,7 @@ class TrkrClusterv5 : public TrkrCluster float getZSize() const override { return (float) m_zsize; } void setZSize(char zsize) { m_zsize = zsize; } - char getOverlap() const override{ return m_overlap; } + char getOverlap() const override { return m_overlap; } void setOverlap(char overlap) override { m_overlap = overlap; } char getEdge() const override{ return m_edge; } From a86078b6bf248ee43d7d70bb82bb3ecdc8d44b69 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 12:22:28 -0400 Subject: [PATCH 065/468] testing --- offline/packages/trackbase_historic/TrackSeed_v1.cc | 3 ++- offline/packages/trackreco/PHSimpleKFProp.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 04ec922347..5b27be2ce7 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -83,9 +83,10 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, uint8_t endLayer) { std::map positions; - + std::cout << "Calling here"< endLayer) { continue; } diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index 6c55d0ebb7..59eb5f7fc6 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -1174,6 +1174,7 @@ void PHSimpleKFProp::publishSeeds(std::vector& seeds, PositionMap& { /// The ALICEKF gives a better charge determination at high pT int q = seed.get_charge(); + std::cout << "circle fitting"< Date: Thu, 30 Mar 2023 14:22:44 -0400 Subject: [PATCH 066/468] testing --- offline/packages/trackbase_historic/TrackSeed_v1.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 5b27be2ce7..5f53c4b28e 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -83,10 +83,9 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, uint8_t endLayer) { std::map positions; - std::cout << "Calling here"< endLayer) { continue; } @@ -105,6 +104,7 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, std::cout << "Can't circle fit less than 3 points " << std::endl; return; } + std::cout << "circle fitting " << positions.size() << " clusters"< Date: Thu, 30 Mar 2023 14:39:14 -0400 Subject: [PATCH 067/468] more trkr cluster cleanup --- offline/packages/trackbase/TrkrClusterv4.cc | 4 ++++ offline/packages/trackbase/TrkrClusterv5.cc | 24 ++++++--------------- offline/packages/trackbase/TrkrClusterv5.h | 3 --- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv4.cc b/offline/packages/trackbase/TrkrClusterv4.cc index 7d390f4520..c76a4cce1c 100644 --- a/offline/packages/trackbase/TrkrClusterv4.cc +++ b/offline/packages/trackbase/TrkrClusterv4.cc @@ -69,5 +69,9 @@ void TrkrClusterv4::CopyFrom( const TrkrCluster& source ) setSubSurfKey( source.getSubSurfKey() ); setAdc( source.getAdc() ); + setPhiSize(source.getPhiSize()); + setZSize(source.getZSize()); + setOverlap(source.getOverlap()); + setEdge(source.getEdge()); } diff --git a/offline/packages/trackbase/TrkrClusterv5.cc b/offline/packages/trackbase/TrkrClusterv5.cc index da851f9d29..0a4371b9bd 100644 --- a/offline/packages/trackbase/TrkrClusterv5.cc +++ b/offline/packages/trackbase/TrkrClusterv5.cc @@ -69,25 +69,15 @@ void TrkrClusterv5::CopyFrom( const TrkrCluster& source ) setLocalX( source.getLocalX() ); setLocalY( source.getLocalY() ); - setSubSurfKey( source.getSubSurfKey() ); setAdc( source.getAdc() ); + setMaxAdc( source.getMaxAdc()); + setPhiError(source.getPhiError()); + setZError(source.getZError()); + setPhiSize(source.getPhiSize()); + setZSize(source.getZSize()); + setOverlap(source.getOverlap()); + setEdge(source.getEdge()); } -void TrkrClusterv5::CopyFrom( TrkrClusterv5* source ) -{ - - setLocalX( source->getLocalX() ); - setLocalY( source->getLocalY() ); - setSubSurfKey( source->getSubSurfKey() ); - setAdc( source->getAdc() ); - setMaxAdc( source->getMaxAdc() ); - setPhiError( source->getPhiError() ); - setZError( source->getZError() ); - setPhiSize( source->getPhiSize() ); - setZSize( source->getZSize() ); - setOverlap( source->getOverlap() ); - setEdge( source->getEdge() ); - -} diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 8dae85e46d..275c01acf2 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -46,9 +46,6 @@ class TrkrClusterv5 : public TrkrCluster void CopyFrom( TrkrCluster* source ) override { CopyFrom( *source ); } - //! copy content - void CopyFrom( TrkrClusterv5* source ); - // // cluster position // From 60c1fe587ad46ed7413f3f5f5d3d6565fd815fa1 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Thu, 30 Mar 2023 15:42:19 -0400 Subject: [PATCH 068/468] update --- .../g4tpc/PHG4TpcElectronDrift.cc | 85 +-------- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 14 +- .../g4tracking/TruthClusterizerBase.cc | 178 ++++++++++++++++++ .../g4tracking/TruthClusterizerBase.h | 75 ++++++++ 4 files changed, 265 insertions(+), 87 deletions(-) create mode 100644 simulation/g4simulation/g4tracking/TruthClusterizerBase.cc create mode 100644 simulation/g4simulation/g4tracking/TruthClusterizerBase.h diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 1e24c7062d..928180c3f2 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -4,6 +4,7 @@ #include "PHG4TpcElectronDrift.h" #include "PHG4TpcDistortion.h" #include "PHG4TpcPadPlane.h" // for PHG4TpcPadPlane +#include "PHG4TpcTruthClusterizer.h" #include #include @@ -68,7 +69,6 @@ #include // for _Rb_tree_cons... #include // for pair -#include "TpcClusterBuilder.h" using std::cout; using std::endl; @@ -161,37 +161,6 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } - truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); - if (!truthtracks) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - truthtracks = new TrkrTruthTrackContainerv1(); - auto newNode = new PHIODataNode(truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - truthclustercontainer = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); - if (!truthclustercontainer) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - truthclustercontainer = new TrkrClusterContainerv4; - auto newNode = new PHIODataNode(truthclustercontainer, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - seggeonodename = "CYLINDERCELLGEOM_SVTX"; // + detector; seggeo = findNode::getClass(topNode, seggeonodename); if (!seggeo) @@ -200,7 +169,6 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) auto newNode = new PHIODataNode(seggeo, seggeonodename, "PHObject"); runNode->addNode(newNode); } - UpdateParametersWithMacro(); PHNodeIterator runIter(runNode); @@ -322,6 +290,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } std::cout << std::endl; } + m_truthclusterizer->init(topNode); return Fun4AllReturnCodes::EVENT_OK; } @@ -335,16 +304,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if (truth_clusterer == nullptr) { - /* if (Verbosity()) std::cout << " truth clusterer was a null pointer " << std::endl; */ - truth_clusterer = new TpcClusterBuilder(truthclustercontainer, m_tGeometry, seggeo); - } else { - if (Verbosity()>10) std::cout << " truth clusterer was NOT a null pointer " << std::endl; - } - - static constexpr unsigned int print_layer = 18; - truth_clusterer->is_embedded_track = false; std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer /* std::map> truthtrack_hits; */ @@ -362,8 +322,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) std::cout << "Could not locate g4 hit node " << hitnodename << std::endl; gSystem->Exit(1); } - PHG4TruthInfoContainer *truthinfo = - findNode::getClass(topNode, "G4TruthInfo"); m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); if(!m_tGeometry) @@ -384,8 +342,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) unsigned int dump_interval = 5000; // dump temp_hitsetcontainer to the node tree after this many g4hits unsigned int dump_counter = 0; - int trkid = -1; - for (auto hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter) { count_g4hits++; @@ -397,22 +353,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) continue; } - int trkid_new = hiter->second->get_trkid(); - if (trkid != trkid_new) - { // starting a new track - truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ false); - trkid = trkid_new; - truth_clusterer->is_embedded_track = (truthinfo->isEmbeded(trkid)); - if (Verbosity() > 1000){ - std::cout << " New track " << trkid << " is embed? : " - << truth_clusterer->is_embedded_track << std::endl; - } - if (truth_clusterer->is_embedded_track) - { // build new TrkrTruthTrack - current_track = truthtracks->getTruthTrack(trkid, truthinfo); - truth_clusterer->set_current_track(current_track); - } - } + m_truthclusterizer->check_g4hit(hiter->second); // for very high occupancy events, accessing the TrkrHitsets on the node tree // for every drifted electron seems to be very slow // Instead, use a temporary map to accumulate the charge from all @@ -563,7 +504,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) nt->Fill(ihit, t_start, t_final, t_sigma, rad_final, z_start, z_final); } // this fills the cells and updates the hits in temp_hitsetcontainer for this drifted electron hitting the GEM stack - padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(), + padplane->MapToPadPlane(m_truthclusterizer, single_hitsetcontainer.get(), temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, side, hiter, ntpad, nthit); } // end loop over electrons for this g4hit @@ -673,8 +614,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } // end loop over g4hits - truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ true); - if (Verbosity() > 20) { std::cout << "From PHG4TpcElectronDrift: hitsetcontainer printout at end:" << std::endl; @@ -718,15 +657,11 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) ++event_num; // if doing more than one event, event_num will be incremented. - if (Verbosity() > 500) - { - std::cout << " TruthTrackContainer results at end of event in PHG4TpcElectronDrift::process_event " << std::endl; - truthtracks->identify(); - } - - if (Verbosity()>800) { - truth_clusterer->print(truthtracks); - truth_clusterer->print_file(truthtracks,"drift_clusters.txt"); + if (m_truthclusterizer) { + if (Verbosity() > 800) { + m_truthclusterizer->print_clusters(); + } + m_truthclusterizer->end_of_event(); } return Fun4AllReturnCodes::EVENT_OK; @@ -808,7 +743,7 @@ void PHG4TpcElectronDrift::SetDefaultParameters() } PHG4TpcElectronDrift::~PHG4TpcElectronDrift() { - if (truth_clusterer != nullptr) delete truth_clusterer; + delete m_truthclusterizer; } void PHG4TpcElectronDrift::setTpcDistortion(PHG4TpcDistortion *distortionMap) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 4d3f6ff183..cd109795dd 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -26,9 +26,7 @@ class TrkrHitSetContainer; class TrkrHitTruthAssoc; class TrkrTruthTrackContainer; class TrkrClusterContainer; -class TrkrTruthTrack; class DistortedTrackContainer; -class TpcClusterBuilder; class PHG4TpcCylinderGeomContainer; class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface @@ -65,18 +63,13 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface void registerPadPlane(PHG4TpcPadPlane *padplane); private: - //! map a given x,y,z coordinates to plane hits - /* TpcClusterBuilder MapToPadPlane(const double x, const double y, const */ - /* double z, const unsigned int side, PHG4HitContainer::ConstIterator hiter, */ - /* TNtuple *ntpad, TNtuple *nthit); */ + + PHG4TpcTruthClusterizer m_truthclusterizer; std::ofstream f_out; TrkrHitSetContainer *hitsetcontainer = nullptr; TrkrHitTruthAssoc *hittruthassoc = nullptr; - TrkrTruthTrackContainer *truthtracks = nullptr; - TrkrTruthTrack *current_track = nullptr; - TrkrClusterContainer *truthclustercontainer = nullptr; // the TrkrClusterContainer for truth clusters std::unique_ptr temp_hitsetcontainer; std::unique_ptr single_hitsetcontainer; std::unique_ptr padplane; @@ -131,9 +124,6 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface double max_time = NAN; - /* std::array layer_clusterers; // Generate TrkrClusterv4's for TrkrTruthTracks */ - TpcClusterBuilder* truth_clusterer { nullptr }; - /* void buildTruthClusters(std::map&); */ //! rng de-allocator diff --git a/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc b/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc new file mode 100644 index 0000000000..015cded9b1 --- /dev/null +++ b/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc @@ -0,0 +1,178 @@ +#include "TruthClusterizerBase.h" + +#include +#include +#include +#include +#include +#include + +/* #include */ +#include +#include +#include +#include +#include +#include +#include +#include // for TrkrHit + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include // for PHObject +#include +#include + +#include // for TMatrixF +#include // for TMatrixT, operator* +#include // for TMatrixTRow + + +#include +#include +#include +#include +#include + +TruthClusterizerBase::TruthClusterizerBase(int _verbosity) + : m_verbosity { _verbosity } + , m_hits { new TrkrHitSetContainerv1 } +{} + +void TruthClusterizerBase::init_nodes(PHCompositeNode*& topNode) { + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + assert(dstNode); + PHNodeIterator dstiter(dstNode); + auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!DetNode) + { + DetNode = new PHCompositeNode("TRKR"); + dstNode->addNode(DetNode); + } + + m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + if (!m_truthtracks) + { + PHNodeIterator dstiter(dstNode); + m_truthtracks = new TrkrTruthTrackContainerv1(); + auto newNode = new PHIODataNode(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); + DetNode->addNode(newNode); + } + + m_clusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + if (!m_clusters) + { + m_clusters = new TrkrClusterContainerv4; + auto newNode = new PHIODataNode(m_clusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); + DetNode->addNode(newNode); + } + + m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_truthinfo) + { + std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl; + assert(m_truthinfo); + } +} + +TruthClusterizerBase::~TruthClusterizerBase() { + delete m_hits; +} + +void TruthClusterizerBase::check_g4hit_status(PHG4Hit* hit) { + int new_trkid = (hit==nullptr) ? -1 : hit->get_trkid(); + m_is_new_track = (new_trkid != m_trkid); + if (m_verbosity>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<isEmbeded(m_trkid); +} + +// to call if m_was_emb=true and after clustering +void TruthClusterizerBase::transfer_clusters(TrkrClusterContainer* pass_clusters) { + m_hits->Reset(); // clear out the old hits + for (auto hitsetkey : pass_clusters->getHitSetKeys()) { + m_hitsetkey_cnt.try_emplace(hitsetkey,0); + unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; + auto range = pass_clusters->getClusters(hitsetkey); + for (auto cluster = range.first; cluster != range.second; ++cluster) { + auto ckey = TrkrDefs::genClusKey(hitsetkey, cnt); + m_clusters->addClusterSpecifyKey(ckey, cluster->second); + m_current_track->addCluster(ckey); + ++cnt; + } + } + m_was_emb = false; +} + +// if m_is_new_track +void TruthClusterizerBase::update_track() { + m_current_track = m_is_emb ? m_truthtracks->getTruthTrack(m_trkid, m_truthinfo) : nullptr; +} + +void TruthClusterizerBase::addhitset( + TrkrDefs::hitsetkey hitsetkey, + TrkrDefs::hitkey hitkey, + float neffelectrons) +{ + if (!m_is_emb) return; + TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(hitsetkey); + // See if this hit already exists + TrkrHit *hit = nullptr; + hit = hitsetit->second->getHit(hitkey); + if (!hit) + { + // create a new one + hit = new TrkrHitv2(); + hitsetit->second->addHitSpecificKey(hitkey, hit); + } + // Either way, add the energy to it -- adc values will be added at digitization + hit->addEnergy(neffelectrons); +} + +void TruthClusterizerBase::print_clusters(int nclusprint) { + std::cout << PHWHERE << ": content of clusters " << std::endl; + auto& tmap = m_truthtracks->getMap(); + std::cout << " Number of tracks: " << tmap.size() << std::endl; + for (auto& _pair : tmap) { + auto& track = _pair.second; + + printf("id(%2i) phi:eta:pt(", (int)track->getTrackid()); + std::cout << "phi:eta:pt("; + printf("%5.2f:%5.2f:%5.2f", track->getPhi(), track->getPseudoRapidity(), track->getPt()); + /* Form("%5.2:%5.2:%5.2", track->getPhi(), track->getPseudoRapidity(), track->getPt()) */ + //<getPhi()<<":"<getPseudoRapidity()<<":"<getPt() + std::cout << ") nclusters(" << track->getClusters().size() <<") "; + if (m_verbosity <= 10) { std::cout << std::endl; } + else { + int nclus = 0; + for (auto cluskey : track->getClusters()) { + std::cout << " " + << ((int) TrkrDefs::getHitSetKeyFromClusKey(cluskey)) <<":index(" << + ((int) TrkrDefs::getClusIndex(cluskey)) << ")"; + ++nclus; + if (nclusprint > 0 && nclus >= nclusprint) { + std::cout << " ... "; + break; + } + } + } + } + std::cout << PHWHERE << " ----- end of clusters " << std::endl; +} + diff --git a/simulation/g4simulation/g4tracking/TruthClusterizerBase.h b/simulation/g4simulation/g4tracking/TruthClusterizerBase.h new file mode 100644 index 0000000000..16b445a4dd --- /dev/null +++ b/simulation/g4simulation/g4tracking/TruthClusterizerBase.h @@ -0,0 +1,75 @@ +#ifndef G4TRACKING_TRUTHCLUSTERIZERBASE +#define G4TRACKING_TRUTHCLUSTERIZERBASE + +// Generated March 2023, David Stewart +// +// Virtual base class used to cluster TrkrHits into TrkrClusters, but using only the reconstructed hits +// from phg4 embedded (``truth'') tracks. In each of the following modules, a child-class will be derived +// with the "cluster_hits()" virtual function implemented +// - PHG4MvtxHitReco +// - PHG4InttHitReco +// - PHG4TpcElectronDrift +// - (maybe?) tpot? +// +// It's job is to: +// (1) build TrkrTruthTracks in the TrkrTruthTrackContainer +// (2) build TrkrClusters in the truth clusters TrkrClusterContainer +// It does this by collecting the TrkrHit's associated with each PHG4 truth track, and when they +// are all collected, it calls the down-stream macros (the same ones which do the Svtx clustering) +// on this subset of the TrkrHits, and assigning these clusters to the TrkrClusterContainer and +// the associated TrkrTruthTrackContainer. + +#include +#include +#include +#include + +class PHCompositeNode; +class TrkrHitSetContainer; +class TrkrClusterContainer; +class TrkrTruthTrackContainer; +class TrkrTruthTrack; +class PHG4TruthInfoContainer; +class PHG4Hit; + +class TruthClusterizerBase { + protected: + int m_verbosity ; + TrkrHitSetContainer* m_hits ; + TrkrTruthTrackContainer* m_truthtracks { nullptr }; + TrkrClusterContainer* m_clusters { nullptr }; // cluster container passed to individual clusterers + PHG4TruthInfoContainer* m_truthinfo { nullptr }; + int m_trkid { -1 }; + bool m_is_emb { false }; + bool m_was_emb { false }; + bool m_is_new_track { false }; + TrkrTruthTrack* m_current_track { nullptr }; + + + std::map m_hitsetkey_cnt {}; // counter for making ckeys form hitsetkeys + + // implemented individually for mvtx, intt and tpc cluster hits + /* static int dummy_cluster_hits() { */ + /* return Fun4AllReturnCodes::EVENT_OK; */ + /* }; */ + + public: + TruthClusterizerBase ( int verbosity=0 ); + void init_nodes ( PHCompositeNode*& topNode ); + virtual ~TruthClusterizerBase(); + + // main use functions + void check_g4hit_status (PHG4Hit*); + void transfer_clusters(TrkrClusterContainer*); + void update_track(); + void transfer_clusters(); + + void addhitset (TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons); + + // convenience + void set_verbosity(int _) { m_verbosity = _; }; + void print_clusters(int nclusprint=20); + +}; + +#endif From 2ae2f92a4e6a63edd4ff5907c04b6285665bab5a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Mar 2023 20:45:22 -0400 Subject: [PATCH 069/468] trigger jenkins From ec974652ebc09b623dc88a7aaf57b457ec82e0ad Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 31 Mar 2023 11:06:39 -0400 Subject: [PATCH 070/468] clean up --- offline/packages/trackbase_historic/TrackSeed_v1.cc | 4 ++-- offline/packages/trackreco/PHSimpleKFProp.cc | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 5f53c4b28e..371276531d 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -91,7 +91,7 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, { continue; } auto clus = clusters->findCluster(key); - std::cout << "clus edge is " << (int)clus->getEdge() << std::endl; + if(clus->getEdge() > 0) { continue; } Acts::Vector3 pos = tGeometry->getGlobalPosition( @@ -104,7 +104,7 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, std::cout << "Can't circle fit less than 3 points " << std::endl; return; } - std::cout << "circle fitting " << positions.size() << " clusters"<& seeds, PositionMap& { /// The ALICEKF gives a better charge determination at high pT int q = seed.get_charge(); - std::cout << "circle fitting"<insert(&seed); From 74e8279673ed3e1b662a17c826d27271c83254e1 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 31 Mar 2023 14:57:34 -0400 Subject: [PATCH 071/468] working update EXCEPT on TPC, which is only started --- offline/packages/mvtx/MvtxHitPruner.cc | 16 +- offline/packages/mvtx/MvtxHitPruner.h | 3 - simulation/g4simulation/g4eval/g4tools.cc | 1 - simulation/g4simulation/g4intt/Makefile.am | 4 +- .../g4simulation/g4intt/PHG4InttDigitizer.cc | 2 +- .../g4simulation/g4intt/PHG4InttHitReco.cc | 62 +- .../g4simulation/g4intt/PHG4InttHitReco.h | 5 +- .../g4intt/PHG4InttTruthClusterizer.cc | 615 ++++++++++++++++++ .../g4intt/PHG4InttTruthClusterizer.h | 77 +++ simulation/g4simulation/g4mvtx/Makefile.am | 6 +- .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 57 +- .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 5 +- .../g4mvtx/PHG4MvtxTruthClusterizer.cc | 584 +++++++++++++++++ .../g4mvtx/PHG4MvtxTruthClusterizer.h | 72 ++ .../g4tpc/PHG4TpcElectronDrift.cc | 2 + .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 2 +- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 2 +- .../g4tpc/PHG4TpcTruthClusterizer.cc | 66 ++ .../g4tpc/PHG4TpcTruthClusterizer.h | 39 ++ .../g4simulation/g4tracking/Makefile.am | 8 +- .../g4tracking/TruthClusterizerBase.cc | 21 +- .../g4tracking/TruthClusterizerBase.h | 8 +- 22 files changed, 1516 insertions(+), 141 deletions(-) create mode 100644 simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc create mode 100644 simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h create mode 100644 simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc create mode 100644 simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h create mode 100644 simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc create mode 100644 simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index b1a2a52f7c..8183ac24c4 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -79,18 +79,16 @@ int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } -int MvtxHitPruner::process_event(PHCompositeNode *topNode) { +int MvtxHitPruner::process_event(PHCompositeNode *topNode) +{ + // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); if (!m_hits) { cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl; return Fun4AllReturnCodes::ABORTRUN; } - return process_TrkrHitSetContainer(m_hits); -} -int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) -{ // We want to combine all strobe values for a given hitset // Start by looping over all MVTX hitsets and making a map of physical sensor to hitsetkey-with-strobe //============================================================================= @@ -98,7 +96,7 @@ int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) std::set bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero) TrkrHitSetContainer::ConstRange hitsetrange = - _m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); + m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr) @@ -122,7 +120,7 @@ int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it) { auto bare_hitsetkey = *bare_it; - TrkrHitSet* bare_hitset = (_m_hits->findOrAddHitSet(bare_hitsetkey))->second; + TrkrHitSet* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl; auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey); @@ -136,7 +134,7 @@ int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) if(Verbosity() > 0) cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; // copy all hits to the hitset with strobe 0 - TrkrHitSet* hitset = _m_hits->findHitSet(hitsetkey); + TrkrHitSet* hitset = m_hits->findHitSet(hitsetkey); if(Verbosity() > 0) std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl; @@ -165,7 +163,7 @@ int MvtxHitPruner::process_TrkrHitSetContainer(TrkrHitSetContainer* _m_hits) } // all hits are copied over to the strobe zero hitset, remove this hitset - _m_hits->removeHitSet(hitsetkey); + m_hits->removeHitSet(hitsetkey); } } } diff --git a/offline/packages/mvtx/MvtxHitPruner.h b/offline/packages/mvtx/MvtxHitPruner.h index 11743b4d66..f62ef39473 100644 --- a/offline/packages/mvtx/MvtxHitPruner.h +++ b/offline/packages/mvtx/MvtxHitPruner.h @@ -39,9 +39,6 @@ class MvtxHitPruner : public SubsysReco //! end of process int End(PHCompositeNode */*topNode*/) override { return 0; } - // will run process event on the container that is passed in - int process_TrkrHitSetContainer(TrkrHitSetContainer*); - private: // node tree storage pointers diff --git a/simulation/g4simulation/g4eval/g4tools.cc b/simulation/g4simulation/g4eval/g4tools.cc index 0f8fe9ff8b..d4d1d4eb97 100644 --- a/simulation/g4simulation/g4eval/g4tools.cc +++ b/simulation/g4simulation/g4eval/g4tools.cc @@ -225,7 +225,6 @@ namespace G4Eval { , has_tpc { _track->get_tpc_seed()!=nullptr } , no_data { !in_silicon && !has_tpc } { - std::cout << " FIMXE: new track apple has_tpc: " << has_tpc << " in_silicon " << in_silicon << std::endl; } ClusKeyIter ClusKeyIter::begin() { diff --git a/simulation/g4simulation/g4intt/Makefile.am b/simulation/g4simulation/g4intt/Makefile.am index 93d5dbab5a..b7fa33a614 100644 --- a/simulation/g4simulation/g4intt/Makefile.am +++ b/simulation/g4simulation/g4intt/Makefile.am @@ -30,7 +30,7 @@ pkginclude_HEADERS = \ PHG4InttDigitizer.h \ PHG4InttHitReco.h \ PHG4InttSubsystem.h \ - TruthInttClusterBuilder.h + PHG4InttTruthClusterizer.h ROOTDICTS = \ InttDeadMap_Dict.cc \ @@ -51,7 +51,7 @@ libg4intt_la_SOURCES = \ PHG4InttHitReco.cc \ PHG4InttSteppingAction.cc \ PHG4InttSubsystem.cc \ - TruthInttClusterBuilder.cc + PHG4InttTruthClusterizer.cc libg4intt_la_LIBADD = \ libg4intt_io.la \ diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index 816c6ffa0b..ebd9689ff1 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -1,7 +1,7 @@ // This is the new trackbase container version #include "PHG4InttDigitizer.h" - +#include "PHG4InttTruthClusterizer.h" #include "InttDeadMap.h" #include diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index 79439dcece..ea8a72317e 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -1,4 +1,6 @@ #include "PHG4InttHitReco.h" +#include "PHG4InttTruthClusterizer.h" + #include #include // for PHG4CylinderGeom @@ -52,6 +54,7 @@ PHG4InttHitReco::PHG4InttHitReco(const std::string &name) , m_Tmin(NAN) , m_Tmax(NAN) , m_crossingPeriod(NAN) + , m_truthclusterizer { new PHG4InttTruthClusterizer } { InitializeParameters(); @@ -68,7 +71,7 @@ PHG4InttHitReco::~PHG4InttHitReco() gsl_vector_free(m_LocalOutVec); gsl_vector_free(m_PathVec); gsl_vector_free(m_SegmentVec); - delete m_truth_clusterer; + delete m_truthclusterizer; } int PHG4InttHitReco::InitRun(PHCompositeNode *topNode) @@ -176,40 +179,7 @@ int PHG4InttHitReco::InitRun(PHCompositeNode *topNode) m_Tmax = get_double_param("tmax"); m_crossingPeriod = get_double_param("beam_crossing_period"); - // - m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); - if (!m_truthtracks) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - m_truthtracks = new TrkrTruthTrackContainerv1(); - auto newNode = new PHIODataNode(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - m_truthclusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); - if (!m_truthclusters) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - m_truthclusters = new TrkrClusterContainerv4; - auto newNode = new PHIODataNode(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - - m_truth_clusterer = new TruthInttClusterBuilder(m_truthclusters, - m_truthtracks, Verbosity() ); + m_truthclusterizer->init_run(topNode, Verbosity()); return Fun4AllReturnCodes::EVENT_OK; } @@ -251,24 +221,12 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits(); - // get nodes for the truth_clusterer - PHG4TruthInfoContainer *truthinfo = - findNode::getClass(topNode, "G4TruthInfo"); - m_truth_clusterer->set_truthinfo(truthinfo); - - // get the geometry node - PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); - if (!geom_container) { - std::cout << PHWHERE << "Failed to get geom_container in TruthInttClusterBuilder.cc" << std::endl; - } - m_truth_clusterer->set_geom_container(geom_container); - for (PHG4HitContainer::ConstIterator hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter) { const int sphxlayer = hiter->second->get_detid(); CylinderGeomIntt *layergeom = dynamic_cast(geo->GetLayerGeom(sphxlayer)); - m_truth_clusterer->check_g4hit(hiter->second); + m_truthclusterizer->check_g4hit(hiter->second); // checking ADC timing integration window cut // uses default values for now @@ -488,7 +446,7 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) double hit_energy = venergy[i1].first * TrkrDefs::InttEnergyScaleup; hit->addEnergy(hit_energy); - m_truth_clusterer->addhitset(hitsetkey, hitkey, hit_energy); + m_truthclusterizer->addhitset(hitsetkey, hitkey, hit_energy); // Add this hit to the association map hittruthassoc->addAssoc(hitsetkey, hitkey, hiter->first); @@ -499,7 +457,6 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) } } } // end loop over g4hits - m_truth_clusterer->reset(); // print the list of entries in the association table if (Verbosity() > 0) @@ -508,6 +465,11 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) hitsetcontainer->identify(); hittruthassoc->identify(); } + + // spit out the truth clusters + if (Verbosity() > 5) m_truthclusterizer->print_clusters(); + m_truthclusterizer->end_of_event(); + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.h b/simulation/g4simulation/g4intt/PHG4InttHitReco.h index b49824c41a..c2fc804def 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.h +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.h @@ -3,7 +3,6 @@ #ifndef G4INTT_PHG4INTTHITRECO_H #define G4INTT_PHG4INTTHITRECO_H -#include "TruthInttClusterBuilder.h" #include @@ -18,6 +17,7 @@ class PHCompositeNode; class TrkrTruthTrackContainer; class TrkrClusterContainer; +class PHG4InttTruthClusterizer; class PHG4InttHitReco : public SubsysReco, public PHParameterInterface @@ -37,6 +37,7 @@ class PHG4InttHitReco : public SubsysReco, public PHParameterInterface void Detector(const std::string &d) { m_Detector = d; } + PHG4InttTruthClusterizer* get_truth_clusterizer() { return m_truthclusterizer; }; protected: std::string m_Detector = "INTT"; std::string m_HitNodeName; @@ -50,7 +51,7 @@ class PHG4InttHitReco : public SubsysReco, public PHParameterInterface double m_Tmax; double m_crossingPeriod; - TruthInttClusterBuilder* m_truth_clusterer { nullptr }; + PHG4InttTruthClusterizer* m_truthclusterizer; gsl_vector *m_LocalOutVec = nullptr; gsl_vector *m_PathVec = nullptr; diff --git a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc new file mode 100644 index 0000000000..3b45668904 --- /dev/null +++ b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc @@ -0,0 +1,615 @@ +#include "PHG4InttTruthClusterizer.h" +#include "PHG4InttDigitizer.h" +#include "InttDeadMap.h" + +#include +#include // for Fun4AllBase::VERBOSITY_MORE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for TrkrHit +#include +#include +#include +#include +#include +#include +#include // for exit +#include +#include // for allocator_traits<... +#include +#include // for __decay_and_strip... + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic ignored "-Wshadow" +#include +#include +#pragma GCC diagnostic pop + +using namespace boost; +#include + +#include +#include +#include +#include +#include + + +int PHG4InttTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) +{ + _D__DigitizeLadderCells(m_topNode); // adapted from g4intt/PHG4InttDigitizer + _C__ClusterLadderCells(m_topNode, clusters); // adapted from intt/InttClusterizer + + return Fun4AllReturnCodes::EVENT_OK; +} + +PHG4InttTruthClusterizer::PHG4InttTruthClusterizer ( ) { }; + +void PHG4InttTruthClusterizer::init_run(PHCompositeNode*& _topNode, int _verbosity) { + init_clusterizer_base(_topNode, _verbosity); + // from PHG4MvtxDigitizer (_D_) + _D__InitRun(_topNode); + // nothing to do intialize for MvtxHitPruner +} + +void PHG4InttTruthClusterizer::check_g4hit(PHG4Hit* hit) { + if (m_verbosity>10) std::cout << " -> Checking PHG4Hit" << std::endl; + check_g4hit_status(hit); + if (m_was_emb) { + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Pre clustering " << (int) m_hits->size() << " hits" << std::endl; + } + TrkrClusterContainerv4 clusters{}; + clusterize_hits (&clusters); + transfer_clusters (&clusters); + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Clustered " << (int) clusters.size() << " clusters" << std::endl; + } + } + if (m_is_new_track) update_track(); +} + +void PHG4InttTruthClusterizer::end_of_event() { + check_g4hit(nullptr); // flush out last data if ended in truth track + m_hitsetkey_cnt.clear(); + if (m_verbosity>2) { + std::cout << PHWHERE << " :: tracks with clusters after clustering in Intt" << std::endl; + for (auto& track : m_truthtracks->getMap()) { + std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); + for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); + std::cout << std::endl; + } + } +} + + + // --------------------------------------- + // Implementation of: + // (1) g4intt/PHG4InttDigitizer _D__ + // note that no noise is added during the digitization + // --------------------------------------- +int PHG4InttTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) +{ + std::cout << "PHG4InttTruthClusterizer::_D__InitRun: detector = " << detector << std::endl; + //------------- + // Add Hit Node + //------------- + PHNodeIterator iter(topNode); + + // Looking for the DST node + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + _D__CalculateLadderCellADCScale(topNode); + + /* Create the run and par nodes + * These parameters are not currently used in the PHG4InttDigitizer + if (false) { // this will be saved when PHG4InttDigitizer runs -- skip in PHG4InttTruthClusterizer + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); + + std::string paramnodename = "G4CELLPARAM_" + detector; + std::string geonodename = "G4CELLGEO_" + detector; + + UpdateParametersWithMacro(); // not used + // save this to the run wise tree to store on DST + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(detector); + runNode->addNode(RunDetNode); + } + SaveToNodeTree(RunDetNode, paramnodename); + // save this to the parNode for use + PHNodeIterator parIter(parNode); + PHCompositeNode *ParDetNode = dynamic_cast(parIter.findFirst("PHCompositeNode", detector)); + if (!ParDetNode) + { + ParDetNode = new PHCompositeNode(detector); + parNode->addNode(ParDetNode); + } + PutOnParNode(ParDetNode, geonodename); + } + + mNoiseMean = get_double_param("NoiseMean"); + mNoiseSigma = get_double_param("NoiseSigma"); + mEnergyPerPair = get_double_param("EnergyPerPair"); + */ + + //---------------- + // Report Settings + //---------------- + + if (Verbosity() > 0) + { + std::cout << "====================== PHG4InttTruthClusterizer::_D__InitRun() =====================" << std::endl; + for (std::map::iterator iter1 = _max_adc.begin(); + iter1 != _max_adc.end(); + ++iter1) + { + std::cout << " Max ADC in Layer #" << iter1->first << " = " << iter1->second << std::endl; + } + for (std::map::iterator iter2 = _energy_scale.begin(); + iter2 != _energy_scale.end(); + ++iter2) + { + std::cout << " Energy per ADC in Layer #" << iter2->first << " = " << 1.0e6 * iter2->second << " keV" << std::endl; + } + std::cout << "===========================================================================" << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHG4InttTruthClusterizer::_D__CalculateLadderCellADCScale(PHCompositeNode* topNode) +{ + // FPHX 3-bit ADC, thresholds are set in "set_fphx_adc_scale". + + //PHG4CellContainer *cells = findNode::getClass(topNode, "G4CELL_INTT"); + PHG4CylinderGeomContainer *geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + + //if (!geom_container || !cells) return; + if (!geom_container) return; + + PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end(); + for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first; + layeriter != layerrange.second; + ++layeriter) + { + int layer = layeriter->second->get_layer(); + if (_max_fphx_adc.find(layer) == _max_fphx_adc.end()) + { + std::cout << "Error: _max_fphx_adc is not available." << std::endl; + gSystem->Exit(1); + } + float thickness = (layeriter->second)->get_thickness(); // cm + float mip_e = 0.003876 * thickness; // GeV + _energy_scale.insert(std::make_pair(layer, mip_e)); + } + return; +} + + +void PHG4InttTruthClusterizer::_D__DigitizeLadderCells(PHCompositeNode* topNode) { + //--------------------------- + // Get common Nodes + //--------------------------- + const InttDeadMap *deadmap = findNode::getClass(topNode, "DEADMAP_INTT"); + if (Verbosity() >= Fun4AllBase::VERBOSITY_MORE) + { + if (deadmap) + { + std::cout << "PHG4InttDigitizer::DigitizeLadderCells - Use deadmap "; + deadmap->identify(); + } + else + { + std::cout << "PHG4InttDigitizer::DigitizeLadderCells - Can not find deadmap, all channels enabled " << std::endl; + } + } + + // Get the TrkrHitSetContainer node + auto& trkrhitsetcontainer = m_hits; // alias local to name used in PHG4InttDigitizer + //------------- + // Digitization + //------------- + + // We want all hitsets for the Intt + TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::inttId); + for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; + hitset_iter != hitset_range.second; + ++hitset_iter) + { + // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer + // get the hitset key so we can find the layer + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; + const int layer = TrkrDefs::getLayer(hitsetkey); + const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); + const int ladder_z = InttDefs::getLadderZId(hitsetkey); + + if (Verbosity() > 1) + { + std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; + } + // get all of the hits from this hitset + TrkrHitSet *hitset = hitset_iter->second; + TrkrHitSet::ConstRange hit_range = hitset->getHits(); + std::set dead_hits; // hits on dead channel + for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; + hit_iter != hit_range.second; + ++hit_iter) + { + // ++m_nCells; // not really used by PHG4InttDigitizer + + TrkrHit *hit = hit_iter->second; + TrkrDefs::hitkey hitkey = hit_iter->first; + int strip_col = InttDefs::getCol(hitkey); // strip z index + int strip_row = InttDefs::getRow(hitkey); // strip phi index + + // Apply deadmap here if desired + if (deadmap) + { + if (deadmap->isDeadChannelIntt( + layer, + ladder_phi, + ladder_z, + strip_col, + strip_row)) + { + // ++m_nDeadCells; // not really used by PHG4InttDigitizer + + if (Verbosity() >= Fun4AllBase::VERBOSITY_MORE) + { + std::cout << "PHG4InttDigitizer::DigitizeLadderCells - dead strip at layer " << layer << ": "; + hit->identify(); + } + + dead_hits.insert(hit_iter->first); // store hitkey of dead channels to be remove later + continue; + } + } // if (deadmap) + + if (_energy_scale.count(layer) > 1) + { + assert(!"Error: _energy_scale has two or more keys."); + } + const float mip_e = _energy_scale[layer]; + + std::vector > vadcrange = _max_fphx_adc[layer]; + + int adc = 0; + for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) + { + if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup < vadcrange[irange].second * (double) mip_e) + { + adc = (unsigned short) irange; + } + } + hit->setAdc(adc); + + if (Verbosity() > 2) + { + std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi + << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; + } + } // end loop over hits in this hitset + + // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC + for (const auto &key : dead_hits) + { + if (Verbosity() > 2) + { + std::cout << " PHG4InttDigitizer: remove hit with key: " << key << std::endl; + } + hitset->removeHit(key); + } + } // end loop over hitsets + return; +} + +void PHG4InttTruthClusterizer::set_adc_scale(const int &layer, const std::vector &userrange) +{ + if (userrange.size() != nadcbins) + { + std::cout << "Error: vector in set_fphx_adc_scale(vector) must have eight elements." << std::endl; + gSystem->Exit(1); + } + //sort(userrange.begin(), userrange.end()); // TODO, causes GLIBC error + + std::vector > vadcrange; + for (unsigned int irange = 0; irange < userrange.size(); ++irange) + { + if (irange == userrange.size() - 1) + { + vadcrange.push_back(std::make_pair(userrange[irange], FLT_MAX)); + } + else + { + vadcrange.push_back(std::make_pair(userrange[irange], userrange[irange + 1])); + } + } + _max_fphx_adc.insert(std::make_pair(layer, vadcrange)); +} + + + +void PHG4InttTruthClusterizer::_C__ClusterLadderCells(PHCompositeNode* topNode, TrkrClusterContainer* m_clusterlist) +{ + if (Verbosity() > 0) + std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl; + + //---------- + // Get Nodes + //---------- + + // get the geometry node + PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + if (!geom_container) return; + + //----------- + // Clustering + //----------- + + // loop over the InttHitSet objects + TrkrHitSetContainer::ConstRange hitsetrange = + m_hits->getHitSets(TrkrDefs::TrkrId::inttId); // from TruthClusterizerBase + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor + TrkrHitSet *hitset = hitsetitr->second; + + if(Verbosity() > 1) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl; + if (Verbosity() > 2) + hitset->identify(); + + // we have a single hitset, get the info that identifies the sensor + int layer = TrkrDefs::getLayer(hitsetitr->first); + int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first); + + // we will need the geometry object for this layer to get the global position + CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); + float pitch = geom->get_strip_y_spacing(); + float length = geom->get_strip_z_spacing(); + + // fill a vector of hits to make things easier - gets every hit in the hitset + std::vector > hitvec; + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + hitvec.push_back(std::make_pair(hitr->first, hitr->second)); + } + if (Verbosity() > 2) + std::cout << "hitvec.size(): " << hitvec.size() << std::endl; + + typedef adjacency_list Graph; + Graph G; + + // Find adjacent strips + for (unsigned int i = 0; i < hitvec.size(); i++) + { + for (unsigned int j = i + 1; j < hitvec.size(); j++) + { + if (_C__ladder_are_adjacent(hitvec[i], hitvec[j], layer)) + { + add_edge(i, j, G); + } + } + + add_edge(i, i, G); + } + + // Find the connections between the vertices of the graph (vertices are the rawhits, + // connections are made when they are adjacent to one another) + std::vector component(num_vertices(G)); + + // this is the actual clustering, performed by boost + connected_components(G, &component[0]); + + // Loop over the components(hit cells) compiling a list of the + // unique connected groups (ie. clusters). + std::set cluster_ids; // unique components + + std::multimap > clusters; + for (unsigned int i = 0; i < component.size(); i++) + { + cluster_ids.insert(component[i]); // one entry per unique cluster id + clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id + } + + // loop over the cluster ID's and make the clusters from the connected hits + for (std::set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) + { + int clusid = *clusiter; + //cout << " intt clustering: add cluster number " << clusid << std::endl; + // get all hits for this cluster ID only + std::pair>::iterator, + std::multimap>::iterator> clusrange = clusters.equal_range(clusid); + std::multimap>::iterator mapiter = clusrange.first; + + // make the cluster directly in the node tree + TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); + + if (Verbosity() > 2) + std::cout << "Filling cluster with key " << ckey << std::endl; + + // get the bunch crossing number from the hitsetkey + /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */ + + // determine the size of the cluster in phi and z, useful for track fitting the cluster + std::set phibins; + std::set zbins; + + // determine the cluster position... + double xlocalsum = 0.0; + double ylocalsum = 0.0; + double zlocalsum = 0.0; + unsigned int clus_adc = 0.0; + unsigned int clus_maxadc = 0.0; + unsigned nhits = 0; + + //std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl; + for (mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) + { + // mapiter->second.first is the hit key + //cout << " adding hitkey " << mapiter->second.first << std::endl; + int col = InttDefs::getCol( (mapiter->second).first); + int row = InttDefs::getRow( (mapiter->second).first); + zbins.insert(col); + phibins.insert(row); + + // mapiter->second.second is the hit + unsigned int hit_adc = (mapiter->second).second->getAdc(); + + // now get the positions from the geometry + double local_hit_location[3] = {0., 0., 0.}; + geom->find_strip_center_localcoords(ladder_z_index, + row, col, + local_hit_location); + + if (_make_e_weights[layer]) + { + xlocalsum += local_hit_location[0] * (double) hit_adc; + ylocalsum += local_hit_location[1] * (double) hit_adc; + zlocalsum += local_hit_location[2] * (double) hit_adc; + } + else + { + xlocalsum += local_hit_location[0]; + ylocalsum += local_hit_location[1]; + zlocalsum += local_hit_location[2]; + } + if(hit_adc > clus_maxadc) + clus_maxadc = hit_adc; + clus_adc += hit_adc; + ++nhits; + + // add this cluster-hit association to the association map of (clusterkey,hitkey) + if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl; + if (Verbosity() > 2) + { + std::cout << " From geometry object: hit x " << local_hit_location[0] << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl; + std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl; + + } + } + + static const float invsqrt12 = 1./sqrt(12); + + // scale factors (phi direction) + /* + they corresponds to clusters of size 1 and 2 in phi + other clusters, which are very few and pathological, get a scale factor of 1 + These scale factors are applied to produce cluster pulls with width unity + */ + + float phierror = pitch * invsqrt12; + + static constexpr std::array scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; + if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; + else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; + else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; + // z error. All clusters have a z-size of 1. + const float zerror = length * invsqrt12; + + double cluslocaly = NAN; + double cluslocalz = NAN; + + if (_make_e_weights[layer]) + { + cluslocaly = ylocalsum / (double) clus_adc; + cluslocalz = zlocalsum / (double) clus_adc; + } + else + { + cluslocaly = ylocalsum / nhits; + cluslocalz = zlocalsum / nhits; + } + if(m_cluster_version==4){ + auto clus = std::make_unique(); + // Fill the cluster fields + clus->setAdc(clus_adc); + clus->setPhiSize(phibins.size()); + clus->setZSize(1); + + if(Verbosity() > 10) clus->identify(); + + clus->setLocalX(cluslocaly); + clus->setLocalY(cluslocalz); + // silicon has a 1-1 map between hitsetkey and surfaces. So set to + // 0 + clus->setSubSurfKey(0); + m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); + + }else if(m_cluster_version==5){ + auto clus = std::make_unique(); + clus->setAdc(clus_adc); + clus->setMaxAdc(clus_maxadc); + clus->setLocalX(cluslocaly); + clus->setLocalY(cluslocalz); + clus->setPhiError(phierror); + clus->setZError(zerror); + clus->setPhiSize(phibins.size()); + clus->setZSize(1); + // All silicon surfaces have a 1-1 map to hitsetkey. + // So set subsurface key to 0 + clus->setSubSurfKey(0); + + if (Verbosity() > 2) + clus->identify(); + + m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); + } + } // end loop over cluster ID's + } // end loop over hitsets + + return; +} + +bool PHG4InttTruthClusterizer::_C__ladder_are_adjacent( const std::pair &lhs, const std::pair &rhs, const int layer) +{ + if (get_z_clustering(layer)) + { + if (fabs( InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first) ) <= 1) + { + if (fabs( InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first) ) <= 1) + { + return true; + } + } + } + else + if (fabs( InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first) ) == 0) + { + if (fabs( InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first) ) <= 1) + { + return true; + } + } + + return false; +} diff --git a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h new file mode 100644 index 0000000000..4176825939 --- /dev/null +++ b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h @@ -0,0 +1,77 @@ +#ifndef G4INTT_TRUTHCLUSTERIZER__H +#define G4INTT_TRUTHCLUSTERIZER__H + +#include +#include + +class PHCompositeNode; +class TrkrHit; + +class PHG4InttTruthClusterizer : public TruthClusterizerBase { + public: + + PHG4InttTruthClusterizer ( ); + + //void init_run(PHCompositeNode*& _topNode); + + // regular functions (in common iwht PHG4MvtxTruthClusterizer and PHG4TpcTruthClusterizer) + void init_run(PHCompositeNode*& _topnode, int _verbosity); + int clusterize_hits(TrkrClusterContainer*); + void check_g4hit(PHG4Hit*); + void end_of_event(); + ~PHG4InttTruthClusterizer(){}; + + // all data below is implemented for the clusterize_hits() function + // It does the work that the following modules do for SvtxTrack's: + // (1) g4intt/PHG4InttDigitizer -- use prefix _D__ + // (2) intt/InttClusterizer -- use prefix _C__ + + // --------------------------------------- + // (1) g4intt/PHG4InttDigitizer _D__ + // note that no noise is added during the digitization + // --------------------------------------- + public: + void say_hi() { std::cout << " BANANA hello world " << std::endl; }; + void set_adc_scale(const int &layer, const std::vector &userrange); + void _D__DigitizeLadderCells(PHCompositeNode *topNode); + private: + int _D__InitRun(PHCompositeNode* topNode); + void _D__CalculateLadderCellADCScale(PHCompositeNode* topNode); + + // settings + std::map _max_adc; + std::map > > _max_fphx_adc; + std::map _energy_scale; + std::string detector = "INTT"; + const unsigned int nadcbins = 8; + // unsigned int m_nCells = 0; // not really used by PHG4InttDigitizer + // unsigned int m_nDeadCells = 0; // not really used by PHG4InttDigitizer + + // --------------------------------------- + // (2) intt/InttClusterizer _C__ + // --------------------------------------- + public: + void _C__ClusterLadderCells(PHCompositeNode* topNode, TrkrClusterContainer*); + void PrintClusters(PHCompositeNode* topNode); + void set_cluster_version(int value) { m_cluster_version = value; } + + private: + bool _C__ladder_are_adjacent(const std::pair &lhs, const std::pair &rhs, const int layer); + int m_cluster_version = 4; + + void set_z_clustering(const int layer, const bool make_z_clustering) + { _make_z_clustering.insert(std::make_pair(layer, make_z_clustering)); } + bool get_z_clustering(const int layer) const + { + if (_make_z_clustering.find(layer) == _make_z_clustering.end()) return true; + return _make_z_clustering.find(layer)->second; + } + + std::map _thresholds_by_layer; // layer->threshold + std::map _make_z_clustering; // layer->z_clustering_option + std::map _make_e_weights; // layer->energy_weighting_option + +}; + +#endif + diff --git a/simulation/g4simulation/g4mvtx/Makefile.am b/simulation/g4simulation/g4mvtx/Makefile.am index 2e1caf2eb7..d624f7d609 100644 --- a/simulation/g4simulation/g4mvtx/Makefile.am +++ b/simulation/g4simulation/g4mvtx/Makefile.am @@ -23,7 +23,7 @@ libg4mvtx_la_LIBADD = \ -lg4detectors \ -ltrack_io \ -lg4tracking_io \ - -lmvtx \ + -lmvtx \ -lmvtx_io pkginclude_HEADERS = \ @@ -32,7 +32,7 @@ pkginclude_HEADERS = \ PHG4MvtxSubsystem.h \ PHG4EICMvtxSubsystem.h \ PHG4MvtxDigitizer.h \ - TruthMvtxClusterBuilder.h + PHG4MvtxTruthClusterizer.h libg4mvtx_la_SOURCES = \ PHG4MvtxHitReco.cc \ @@ -47,7 +47,7 @@ libg4mvtx_la_SOURCES = \ PHG4MvtxCable.cc \ PHG4MvtxServiceStructure.cc \ PHG4MvtxSupport.cc \ - TruthMvtxClusterBuilder.cc + PHG4MvtxTruthClusterizer.cc ################################################ # linking tests diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index c7b0ed8eec..f799eabf3c 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -1,6 +1,7 @@ // this is the new trackbase version #include "PHG4MvtxHitReco.h" +#include "PHG4MvtxTruthClusterizer.h" #include #include @@ -59,6 +60,7 @@ PHG4MvtxHitReco::PHG4MvtxHitReco(const std::string &name, const std::string &det , m_tmax(5000.) , m_strobe_width(5.) , m_strobe_separation(0.) + , m_truthclusterizer { new PHG4MvtxTruthClusterizer } { if (Verbosity()) { @@ -147,39 +149,7 @@ int PHG4MvtxHitReco::InitRun(PHCompositeNode *topNode) trkrnode->addNode(newNode); } - m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); - if (!m_truthtracks) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - m_truthtracks = new TrkrTruthTrackContainerv1(); - auto newNode = new PHIODataNode(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - m_truthclusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); - if (!m_truthclusters) - { - PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); - if (!DetNode) - { - DetNode = new PHCompositeNode("TRKR"); - dstNode->addNode(DetNode); - } - - m_truthclusters = new TrkrClusterContainerv4; - auto newNode = new PHIODataNode(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); - DetNode->addNode(newNode); - } - m_truth_clusterer = new TruthMvtxClusterBuilder(m_truthclusters, m_truthtracks, Verbosity()); - m_truth_clusterer->set_verbosity(Verbosity()); - m_truth_clusterer->set_HitPruner(m_hit_pruner); + m_truthclusterizer->init_run(topNode, Verbosity()); return Fun4AllReturnCodes::EVENT_OK; } @@ -193,16 +163,6 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) exit(1); } - PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_MVTX"); - if (!geom_container) { - std::cout << PHWHERE << " Couldn't get geometry container CYLINDERGEOM_MVTX" << std::endl; - } - m_truth_clusterer->set_geom_container(geom_container); - - PHG4TruthInfoContainer *truthinfo = - findNode::getClass(topNode, "G4TruthInfo"); - m_truth_clusterer->set_truthinfo(truthinfo); - // load relevant nodes // G4Hits const std::string g4hitnodename = "G4HIT_" + m_detector; auto g4hitContainer = findNode::getClass(topNode, g4hitnodename); @@ -266,7 +226,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) // get hit auto g4hit = g4hit_it->second; - m_truth_clusterer->check_g4hit(g4hit); + m_truthclusterizer->check_g4hit(g4hit); //cout << "From PHG4MvtxHitReco: Call hit print method: " << std::endl; if (Verbosity() > 4) @@ -644,7 +604,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) double hitenergy = venergy[i1].first * TrkrDefs::MvtxEnergyScaleup; hit->addEnergy(hitenergy); - m_truth_clusterer->addhitset(hitsetkey, hitkey, hitenergy); + m_truthclusterizer->addhitset(hitsetkey, hitkey, hitenergy); if (Verbosity() > 0) std::cout << " added hit " << hitkey << " to hitset " << hitsetkey << " with strobe id " << strobe << " in layer " << layer @@ -664,7 +624,6 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) } // end loop over layers - m_truth_clusterer->reset(); // print the list of entries in the association table if (Verbosity() > 2) @@ -674,7 +633,8 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) } // spit out the truth clusters - m_truth_clusterer->print_clusters(); + if (Verbosity() > 5) m_truthclusterizer->print_clusters(); + m_truthclusterizer->end_of_event(); return Fun4AllReturnCodes::EVENT_OK; } @@ -744,6 +704,5 @@ TrkrDefs::hitsetkey PHG4MvtxHitReco::zero_strobe_bits(TrkrDefs::hitsetkey hitset } PHG4MvtxHitReco::~PHG4MvtxHitReco() { - delete m_truth_clusterer; + delete m_truthclusterizer; } - diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 74ea4d748c..8346921967 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -14,6 +14,7 @@ #include // for unique_ptr #include +class PHG4MvtxTruthClusterizer; class PHCompositeNode; class TrkrTruthTrackContainer; class TrkrClusterContainer; @@ -68,9 +69,7 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface bool m_in_sphenix_srdo = false; - TrkrTruthTrackContainer* m_truthtracks { nullptr }; - TrkrClusterContainer* m_truthclusters { nullptr }; - TruthMvtxClusterBuilder* m_truth_clusterer { nullptr }; + PHG4MvtxTruthClusterizer *m_truthclusterizer { nullptr }; class Deleter { diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc new file mode 100644 index 0000000000..c5daae393d --- /dev/null +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc @@ -0,0 +1,584 @@ +#include "PHG4MvtxTruthClusterizer.h" +#include "PHG4MvtxDigitizer.h" + +#include + +#include // for TrkrHit +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for PHNode +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma GCC diagnostic ignored "-Wshadow" +#include +#include +#pragma GCC diagnostic pop + +using boost::add_edge; +using boost::concepts::Graph; +using boost::concepts::Graph; +using boost::connected_components; +using boost::num_vertices; +using boost::undirectedS; +using boost::adjacency_list; +using boost::vecS; + +using std::cout; +using std::endl; +using std::make_pair; +using std::set; +using std::map; +using std::multimap; +using std::vector; +using std::make_pair; + +int PHG4MvtxTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) +{ + std::cout << " clusters " << (clusters == nullptr) << std::endl; + // digitize MVTX + _D__DigitizeMvtxLadderCells(); // adapted from PHG4MvtxDigitizer + _P__MvtxHitPruner(); // adapted from mvtx/MvtxHitPruner + _C__ClusterMvtx(clusters); // adapted from mvtx/MvtxClusterizer + return Fun4AllReturnCodes::EVENT_OK; +} + + +PHG4MvtxTruthClusterizer::PHG4MvtxTruthClusterizer ( ) + : _energy_threshold ( 0.95e-6 ) +{ }; + +void PHG4MvtxTruthClusterizer::init_run(PHCompositeNode*& _topNode, int _verbosity) { + init_clusterizer_base(_topNode, _verbosity); + + // from PHG4MvtxDigitizer (_D_) + _D__InitRun(_topNode); + // nothing to do intialize for MvtxHitPruner +} + +void PHG4MvtxTruthClusterizer::check_g4hit(PHG4Hit* hit) { + if (m_verbosity>10) std::cout << " -> Checking PHG4Hit" << std::endl; + check_g4hit_status(hit); + if (m_was_emb) { + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Pre clustering " << (int) m_hits->size() << " hits" << std::endl; + } + TrkrClusterContainerv4 clusters{}; + clusterize_hits (&clusters); + transfer_clusters (&clusters); + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Clustered " << (int) clusters.size() << " clusters" << std::endl; + } + } + if (m_is_new_track) update_track(); +} + +void PHG4MvtxTruthClusterizer::end_of_event() { + check_g4hit(nullptr); // flush out last data if ended in truth track + m_hitsetkey_cnt.clear(); + if (m_verbosity>2) { + std::cout << PHWHERE << " :: tracks with clusters after clustering in MVTX" << std::endl; + for (auto& track : m_truthtracks->getMap()) { + std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); + for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); + std::cout << std::endl; + } + } +} + +int PHG4MvtxTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) +{ + //------------- + // Add Hit Node + //------------- + PHNodeIterator iter(topNode); + + // Looking for the DST node + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + cout << PHWHERE << "DST Node missing, doing nothing." << endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + _D__CalculateMvtxLadderCellADCScale(topNode); + + //---------------- + // Report Settings + //---------------- + + if (Verbosity() > 0) + { + cout << "====================== PHG4MvtxTruthClusterizer copy of PHG4MvtxDigitizer::InitRun() =====================" << endl; + for (auto &miter : _max_adc) + { + cout << " Max ADC in Layer #" << miter.first << " = " << miter.second << endl; + } + for (auto &miter : _energy_scale) + { + cout << " Energy per ADC in Layer #" << miter.first << " = " << 1.0e6 * miter.second << " keV" << endl; + } + cout << "===========================================================================" << endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHG4MvtxTruthClusterizer::_D__CalculateMvtxLadderCellADCScale(PHCompositeNode *topNode) +{ + // defaults to 8-bit ADC, short-axis MIP placed at 1/4 dynamic range + PHG4CylinderGeomContainer *geom_container = findNode::getClass(topNode, "CYLINDERGEOM_MVTX"); + + if (!geom_container) return; + + if (Verbosity()) cout << "Found CYLINDERGEOM_MVTX node" << endl; + + PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end(); + for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first; + layeriter != layerrange.second; + ++layeriter) + { + int layer = layeriter->second->get_layer(); + float thickness = (layeriter->second)->get_pixel_thickness(); + float pitch = (layeriter->second)->get_pixel_x(); + float length = (layeriter->second)->get_pixel_z(); + + float minpath = pitch; + if (length < minpath) minpath = length; + if (thickness < minpath) minpath = thickness; + float mip_e = 0.003876 * minpath; + + if (Verbosity()) + cout << "mip_e = " << mip_e << endl; + + if (_max_adc.find(layer) == _max_adc.end()) + { + _max_adc[layer] = 255; + _energy_scale[layer] = mip_e / 64; + } + } + return; +} + +void PHG4MvtxTruthClusterizer::_D__DigitizeMvtxLadderCells() { + //---------- + // Get Nodes + //---------- + auto trkrhitsetcontainer = m_hits; + + //============= + // Get the TrkrHitSetContainer node + // Digitization + + // We want all hitsets for the Mvtx + TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::mvtxId); + for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; + hitset_iter != hitset_range.second; + ++hitset_iter) + { + // we have an itrator to one TrkrHitSet for the mvtx from the trkrHitSetContainer + // get the hitset key so we can find the layer + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; + int layer = TrkrDefs::getLayer(hitsetkey); + if (Verbosity() > 1) cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << endl; + + // get all of the hits from this hitset + TrkrHitSet *hitset = hitset_iter->second; + TrkrHitSet::ConstRange hit_range = hitset->getHits(); + std::set hits_rm; + for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; + hit_iter != hit_range.second; + ++hit_iter) + { + TrkrHit *hit = hit_iter->second; + + // Convert the signal value to an ADC value and write that to the hit + //unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); + if (Verbosity() > 0) + cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; + // Remove the hits with energy under threshold + bool rm_hit = false; + if ((hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup) < _energy_threshold) + { + if (Verbosity() > 0) std::cout << " remove hit, below energy threshold of " << _energy_threshold << std::endl; + rm_hit = true; + } + unsigned short adc = (unsigned short) (hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup * _energy_scale[layer])); + if (adc > _max_adc[layer]) adc = _max_adc[layer]; + hit->setAdc(adc); + + if (rm_hit) hits_rm.insert(hit_iter->first); + } + + for (const auto &key : hits_rm) + { + if (Verbosity() > 0) cout << " PHG4MvtxDigitizer: remove hit with key: " << key << endl; + hitset->removeHit(key); + } + } + return; +} + +int PHG4MvtxTruthClusterizer::_P__MvtxHitPruner() { + // We want to combine all strobe values for a given hitset + // Start by looping over all MVTX hitsets and making a map of physical sensor to hitsetkey-with-strobe + //============================================================================= + std::multimap hitset_multimap; // will map (bare hitset, hitset with strobe) + std::set bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero) + + TrkrHitSetContainer::ConstRange hitsetrange = + m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + auto hitsetkey = hitsetitr->first; + + // get the hitsetkey value for strobe 0 + unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); + unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first); + unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); + auto bare_hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, 0); + + hitset_multimap.insert(std::make_pair(bare_hitsetkey, hitsetkey)); + bare_hitset_set.insert(bare_hitsetkey); + + if(Verbosity() > 0) cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; + } + + // Now consolidate all hits into the hitset with strobe 0, and delete the other hitsets + //============================================================== + for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it) + { + auto bare_hitsetkey = *bare_it; + TrkrHitSet* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; + if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl; + + auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey); + for(auto it = bare_hitsetrange.first; it != bare_hitsetrange.second; ++ it) + { + auto hitsetkey = it->second; + + int strobe = MvtxDefs::getStrobeId(hitsetkey); + if(strobe != 0) + { + if(Verbosity() > 0) cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; + + // copy all hits to the hitset with strobe 0 + TrkrHitSet* hitset = m_hits->findHitSet(hitsetkey); + + if(Verbosity() > 0) + std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl; + + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + auto hitkey = hitr->first; + if(Verbosity() > 0) std::cout << " found hitkey " << hitkey << std::endl; + // if it is already there, leave it alone, this is a duplicate hit + auto tmp_hit = bare_hitset->getHit(hitkey); + if(tmp_hit) + { + if(Verbosity() > 0) std::cout << " hitkey " << hitkey << " is already in bare hitsest, do not copy" << std::endl; + continue; + } + + // otherwise copy the hit over + if(Verbosity() > 0) std::cout << " copying over hitkey " << hitkey << std::endl; + auto old_hit = hitr->second; + TrkrHit *new_hit = new TrkrHitv2(); + new_hit->setAdc(old_hit->getAdc()); + bare_hitset->addHitSpecificKey(hitkey, new_hit); + } + + // all hits are copied over to the strobe zero hitset, remove this hitset + m_hits->removeHitSet(hitsetkey); + } + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------- +// mvtx/MvtxClusterizer _C__ +// --------------------------------------- +bool PHG4MvtxTruthClusterizer::_C__are_adjacent(const std::pair &lhs, const std::pair &rhs) +{ + if (GetZClustering()) + { + // column is first, row is second + if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) <= 1) + { + if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) + { + return true; + } + } + } + else + { + if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) == 0) + { + if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) + { + return true; + } + } + } + + return false; +} + +void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterlist) { + // already inherit m_hits from class + if (Verbosity() > 0) + cout << "Entering PHG4MvtxTruthClusterizer::_C__ MvtxClusterizer::ClusterMvtx " << endl; + + PHG4CylinderGeomContainer* geom_container = findNode::getClass(m_topNode, "CYLINDERGEOM_MVTX"); + if (!geom_container) return; + + //----------- + // Clustering + //----------- + + // loop over each MvtxHitSet object (chip) + TrkrHitSetContainer::ConstRange hitsetrange = + m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + TrkrHitSet *hitset = hitsetitr->second; + + if(Verbosity() > 0) + { + unsigned int layer = TrkrDefs::getLayer (hitsetitr ->first); + unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first); + unsigned int chip = MvtxDefs::getChipId (hitsetitr ->first); + unsigned int strobe = MvtxDefs::getStrobeId (hitsetitr ->first); + cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << endl; + } + + if (Verbosity() > 2) + hitset->identify(); + + // fill a vector of hits to make things easier + std::vector > hitvec; + + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + hitvec.push_back(make_pair(hitr->first, hitr->second)); + } + if (Verbosity() > 2) cout << "hitvec.size(): " << hitvec.size() << endl; + + if(Verbosity() > 0) + { + for (unsigned int i = 0; i < hitvec.size(); i++) + { + auto hitkey = hitvec[i].first; + auto row = MvtxDefs::getRow(hitkey); + auto col = MvtxDefs::getCol(hitkey); + std::cout << " hitkey " << hitkey << " row " << row << " col " << col << std::endl; + } + + } + + // do the clustering + typedef adjacency_list Graph; + Graph G; + + // loop over hits in this chip + for (unsigned int i = 0; i < hitvec.size(); i++) + { + for (unsigned int j = 0; j < hitvec.size(); j++) + { + if (_C__are_adjacent(hitvec[i], hitvec[j])) + add_edge(i, j, G); + } + } + + // Find the connections between the vertices of the graph (vertices are the rawhits, + // connections are made when they are adjacent to one another) + vector component(num_vertices(G)); + + // this is the actual clustering, performed by boost + connected_components(G, &component[0]); + + // Loop over the components(hits) compiling a list of the + // unique connected groups (ie. clusters). + set cluster_ids; // unique components + //multimap clusters; + multimap > clusters; + for (unsigned int i = 0; i < component.size(); i++) + { + cluster_ids.insert(component[i]); + clusters.insert(make_pair(component[i], hitvec[i])); + } + int total_clusters = 0; + for (set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) + { + int clusid = *clusiter; + auto clusrange = clusters.equal_range(clusid); + + if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl; + + ++total_clusters; + auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); + + // determine the size of the cluster in phi and z + set phibins; + set zbins; + + // determine the cluster position... + double locxsum = 0.; + double loczsum = 0.; + const unsigned int nhits = std::distance( clusrange.first, clusrange.second ); + + double locclusx = NAN; + double locclusz = NAN; + + // we need the geometry object for this layer to get the global positions + int layer = TrkrDefs::getLayer(ckey); + auto layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); + if (!layergeom) + exit(1); + + for ( auto mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) + { + // size + int col = MvtxDefs::getCol( (mapiter->second).first); + int row = MvtxDefs::getRow( (mapiter->second).first); + zbins.insert(col); + phibins.insert(row); + + // get local coordinates, in stae reference frame, for hit + auto local_coords = layergeom->get_local_coords_from_pixel(row,col); + + /* + manually offset position along y (thickness of the sensor), + to account for effective hit position in the sensor, resulting from diffusion. + Effective position corresponds to 1um above the middle of the sensor + */ + local_coords.SetY( 1e-4 ); + + // update cluster position + locxsum += local_coords.X(); + loczsum += local_coords.Z(); + // add the association between this cluster key and this hitkey to the table + } //mapiter + + // This is the local position + locclusx = locxsum / nhits; + locclusz = loczsum / nhits; + + const double pitch = layergeom->get_pixel_x(); + const double length = layergeom->get_pixel_z(); + const double phisize = phibins.size() * pitch; + const double zsize = zbins.size() * length; + + static const double invsqrt12 = 1./std::sqrt(12); + + // scale factors (phi direction) + /* + they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in phi and z + other clusters, which are very few and pathological, get a scale factor of 1 + These scale factors are applied to produce cluster pulls with width unity + */ + + double phierror = pitch * invsqrt12; + + static constexpr std::array scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }}; + if ( phibins.size() == 1 && zbins.size() == 1 ) phierror*=scalefactors_phi[0]; + else if( phibins.size() == 2 && zbins.size() == 1 ) phierror*=scalefactors_phi[1]; + else if( phibins.size() == 1 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; + else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0]; + else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1]; + else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; + else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3]; + + + // scale factors (z direction) + /* + they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z and phi + other clusters, which are very few and pathological, get a scale factor of 1 + */ + static constexpr std::array scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }}; + double zerror = length*invsqrt12; + if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0]; + else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1]; + else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2]; + else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3]; + + if(Verbosity() > 0) + cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " << zsize + << " local x " << locclusx << " local y " << locclusz + << endl; + + if (m_cluster_version==4){ + auto clus = std::make_unique(); + clus->setAdc(nhits); + clus->setLocalX(locclusx); + clus->setLocalY(locclusz); + + clus->setPhiSize(phibins.size()); + clus->setZSize(zbins.size()); + // All silicon surfaces have a 1-1 map to hitsetkey. + // So set subsurface key to 0 + clus->setSubSurfKey(0); + + if (Verbosity() > 2) + clus->identify(); + + m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); + }else if(m_cluster_version==5){ + auto clus = std::make_unique(); + clus->setAdc(nhits); + clus->setMaxAdc(1); + clus->setLocalX(locclusx); + clus->setLocalY(locclusz); + clus->setPhiError(phierror); + clus->setZError(zerror); + clus->setPhiSize(phibins.size()); + clus->setZSize(zbins.size()); + // All silicon surfaces have a 1-1 map to hitsetkey. + // So set subsurface key to 0 + clus->setSubSurfKey(0); + + if (Verbosity() > 2) + clus->identify(); + + m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); + } + } // clusitr loop + } // loop over hitsets + + return; + +} + diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h new file mode 100644 index 0000000000..c2e8ff42c4 --- /dev/null +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h @@ -0,0 +1,72 @@ +#ifndef G4MVTX_TRUTHCLUSTERIZER__H +#define G4MVTX_TRUTHCLUSTERIZER__H + +#include + +class PHCompositeNode; +class TrkrHit; + +class PHG4MvtxTruthClusterizer : public TruthClusterizerBase { + public: + + PHG4MvtxTruthClusterizer (); + + //void init_run(PHCompositeNode*& _topNode); + + // regular functions (in common iwht PHG4InttTruthClusterizer and PHG4TpcTruthClusterizer) + void init_run ( PHCompositeNode*& _topNode, int _verbosity ); + int clusterize_hits(TrkrClusterContainer*); + void check_g4hit(PHG4Hit*); + void end_of_event(); + ~PHG4MvtxTruthClusterizer(){}; + + // all data below is implemented for the clusterize_hits() function + // It does the work that the following modules do for SvtxTrack's: + // (1) g4mvtx/PHG4MvtxDigitizer -- use prefix _D__ + // (2) mvtx/MvtxHitPruner -- use prefix _P__ + // (3) mvtx/MvtxClusterizer -- use prefix _C__ + + // --------------------------------------- + // (1) g4mvtx/PHG4MvtxDigitizer _D__ + // --------------------------------------- + private: + std::map _max_adc; + std::map _energy_scale; + float _energy_threshold; + public: + // Need to update the G4INTT macro accordingly with the set_adc_scale values + void set_adc_scale(const int layer, const unsigned short max_adc, const float energy_per_adc) + { + _max_adc.insert(std::make_pair(layer, max_adc)); + _energy_scale.insert(std::make_pair(layer, energy_per_adc)); + } + void set_energy_threshold(const float threshold) { _energy_threshold = threshold; } + float _D__get_energy_threshold() { return _energy_threshold; } + + int _D__InitRun (PHCompositeNode *topNode); + void _D__CalculateMvtxLadderCellADCScale (PHCompositeNode *topNode); // called by _D_InitRun + void _D__DigitizeMvtxLadderCells (); + + // --------------------------------------- + // (2) mvtx/MvtxHitPruner _P__ + // --------------------------------------- + public: + int _P__MvtxHitPruner(); + + // --------------------------------------- + // (3) mvtx/MvtxClusterizer _C__ + // --------------------------------------- + private: + bool m_makeZClustering { true }; // z_clustering_option + int m_cluster_version { 4 }; + bool _C__are_adjacent(const std::pair &lhs, const std::pair &rhs); + + public: + void set_cluster_version(int value) { m_cluster_version = value; } + void _C__ClusterMvtx(TrkrClusterContainer* clusters); + bool GetZClustering() const { return m_makeZClustering; }; + void SetZClustering(const bool make_z_clustering) { m_makeZClustering = make_z_clustering; }; + +}; + +#endif diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 928180c3f2..573b416428 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -88,6 +88,7 @@ PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) , PHParameterInterface(name) , temp_hitsetcontainer(new TrkrHitSetContainerv1) , single_hitsetcontainer(new TrkrHitSetContainerv1) + , m_truthclusterizer { new PHG4InttTruthClusterizer } { InitializeParameters(); RandomGenerator.reset(gsl_rng_alloc(gsl_rng_mt19937)); @@ -98,6 +99,7 @@ PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) int PHG4TpcElectronDrift::Init(PHCompositeNode *topNode) { padplane->Init(topNode); + m_truthclusterizer->init_run(topNode, Verbosity()); event_num = 0; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index cd109795dd..675dc11b8e 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -64,7 +64,7 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface private: - PHG4TpcTruthClusterizer m_truthclusterizer; + PHG4TpcTruthClusterizer* m_truthclusterizer; std::ofstream f_out; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index af41b9d117..299246c21b 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -188,7 +188,7 @@ double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() void PHG4TpcPadPlaneReadout::MapToPadPlane( - TpcClusterBuilder *tpc_truth_clusterer, + PHG4TpcTruthClusterizer *tpc_truth_clusterer, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, diff --git a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc new file mode 100644 index 0000000000..9e41af4ff7 --- /dev/null +++ b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc @@ -0,0 +1,66 @@ +#include "PHG4TpcTruthClusterizer.h" +#include "PHG4TpcDigitizer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PHG4TpcTruthClusterizer::PHG4TpcTruthClusterizer ( + PHG4TpcDigitizer* _digitiser + , TpcClusterizer* _clusterizer + , int _verbosity ) + : TruthClusterizerBase (_verbosity) + , m_digitiser { _digitiser } + , m_clusterizer { _clusterizer } +{} + +void PHG4TpcTruthClusterizer::init_run(PHCompositeNode*& _topNode) { + m_topNode = _topNode; + init_nodes(_topNode); // base class TruthClusterizerBase gets required nodes +} + +int PHG4TpcTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) +{ + std::cout << (clusters == nulltpr) << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHG4TpcTruthClusterizer::check_g4hit(PHG4Hit* hit) { + if (m_verbosity>10) std::cout << " -> Checking PHG4Hit in Tpc" << std::endl; + check_g4hit_status(hit); + if (m_was_emb) { + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Pre Tpc Truth("<getTrackid() << ") clustering " << (int) m_hits->size() << " hits" << std::endl; + m_hits->identify(); + } + TrkrClusterContainerv4 clusters{}; + clusterize_hits (&clusters); + transfer_clusters (&clusters); + if (m_verbosity>3) { + std::cout << PHWHERE << std::endl + << " -> Clustered " << (int) clusters.size() << " Tpc Truth clusters" << std::endl; + } + } + if (m_is_new_track) update_track(); +} + +void PHG4TpcTruthClusterizer::end_of_event() { + check_g4hit(nullptr); // flush out last data if ended in truth track + m_hitsetkey_cnt.clear(); + if (m_verbosity>2) { + std::cout << PHWHERE << std::endl << " :: tracks with clusters after clustering in TPC" << std::endl; + for (auto& track : m_truthtracks->getMap()) { + std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); + for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); + std::cout << std::endl; + } + } +} + diff --git a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h new file mode 100644 index 0000000000..5ca4950f41 --- /dev/null +++ b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h @@ -0,0 +1,39 @@ +#ifndef G4TPC_TRUTHCLUSTERIZER__H +#define G4TPC_TRUTHCLUSTERIZER__H + +#include + // This is the helper class for PHG4TpcElectronDrift. It will cluster the + // PHG4Hits which come from each individual embedded ("Truth") track. It uses + // pointers to the PHG4TpcDigitizer and TpcClusterizer modules , which also + // do the clustering for all the PHG4Hits together (from all truth tracks + // together + all other tracks + noise). + // + // Because it makes calls to these other modules, t needs to be initialized + // from the Fun4All driving macro *after* adding the above listed modules. + +class PHG4TpcDigitizer; +class TpcClusterizer; +class PHCompositeNode; + +class PHG4TpcTruthClusterizer : public TruthClusterizerBase { + private: + PHCompositeNode* m_topNode { nullptr }; + PHG4TpcDigitizer* m_digitiser ; + TpcClusterizer* m_clusterizer ; + + public: + PHG4TpcTruthClusterizer (); + + void init_run(PHCompositeNode*& _topNode, int _verbosity); + int clusterize_hits(TrkrClusterContainer*); + void check_g4hit(PHG4Hit*); + void end_of_event(); + ~PHG4TpcTruthClusterizer(){}; + + // all data below is implemented for the clusterize_hits() function + // It does the work that the following modules do for SvtxTrack's: + // (1) g4tpc/PHG4TpcDigitizer -- use prefix _D__ + // (2) tpc/TpcClusterizer -- use prefix _C__ // note that this can probably be *greatly* simplified +}; + +#endif diff --git a/simulation/g4simulation/g4tracking/Makefile.am b/simulation/g4simulation/g4tracking/Makefile.am index e7d9f20f7f..492c887f40 100644 --- a/simulation/g4simulation/g4tracking/Makefile.am +++ b/simulation/g4simulation/g4tracking/Makefile.am @@ -21,14 +21,15 @@ libg4tracking_io_la_LIBADD = \ -ltrack_io pkginclude_HEADERS = \ + TrkrTruthTrack.h \ + EmbRecoMatch.h \ EmbRecoMatchContainer.h \ EmbRecoMatchContainerv1.h \ - EmbRecoMatch.h \ EmbRecoMatchv1.h \ TrkrTruthTrackContainer.h \ TrkrTruthTrackContainerv1.h \ - TrkrTruthTrack.h \ - TrkrTruthTrackv1.h + TrkrTruthTrackv1.h \ + TruthClusterizerBase.h ROOTDICTS = \ EmbRecoMatchContainer_Dict.cc \ @@ -59,6 +60,7 @@ libg4tracking_io_la_SOURCES = \ TrkrTruthTrack.cc \ TrkrTruthTrackContainer.cc \ TrkrTruthTrackContainerv1.cc \ + TruthClusterizerBase.cc \ TrkrTruthTrackv1.cc # Rule for generating table CINT dictionaries. diff --git a/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc b/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc index 015cded9b1..6be7010575 100644 --- a/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc +++ b/simulation/g4simulation/g4tracking/TruthClusterizerBase.cc @@ -46,13 +46,14 @@ #include #include -TruthClusterizerBase::TruthClusterizerBase(int _verbosity) - : m_verbosity { _verbosity } - , m_hits { new TrkrHitSetContainerv1 } -{} - -void TruthClusterizerBase::init_nodes(PHCompositeNode*& topNode) { - PHNodeIterator iter(topNode); +TruthClusterizerBase::TruthClusterizerBase ( ) + : m_hits { new TrkrHitSetContainerv1 } +{ } + +void TruthClusterizerBase::init_clusterizer_base( PHCompositeNode*& _topNode, int _verbosity ) { + m_topNode = _topNode; + m_verbosity = _verbosity; + PHNodeIterator iter(m_topNode); auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); assert(dstNode); PHNodeIterator dstiter(dstNode); @@ -63,7 +64,7 @@ void TruthClusterizerBase::init_nodes(PHCompositeNode*& topNode) { dstNode->addNode(DetNode); } - m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + m_truthtracks = findNode::getClass(m_topNode, "TRKR_TRUTHTRACKCONTAINER"); if (!m_truthtracks) { PHNodeIterator dstiter(dstNode); @@ -72,7 +73,7 @@ void TruthClusterizerBase::init_nodes(PHCompositeNode*& topNode) { DetNode->addNode(newNode); } - m_clusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + m_clusters = findNode::getClass(m_topNode, "TRKR_TRUTHCLUSTERCONTAINER"); if (!m_clusters) { m_clusters = new TrkrClusterContainerv4; @@ -80,7 +81,7 @@ void TruthClusterizerBase::init_nodes(PHCompositeNode*& topNode) { DetNode->addNode(newNode); } - m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + m_truthinfo = findNode::getClass(m_topNode, "G4TruthInfo"); if (!m_truthinfo) { std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl; diff --git a/simulation/g4simulation/g4tracking/TruthClusterizerBase.h b/simulation/g4simulation/g4tracking/TruthClusterizerBase.h index 16b445a4dd..b084d7346b 100644 --- a/simulation/g4simulation/g4tracking/TruthClusterizerBase.h +++ b/simulation/g4simulation/g4tracking/TruthClusterizerBase.h @@ -34,8 +34,9 @@ class PHG4Hit; class TruthClusterizerBase { protected: - int m_verbosity ; TrkrHitSetContainer* m_hits ; + int m_verbosity { 0 }; + PHCompositeNode* m_topNode { nullptr }; TrkrTruthTrackContainer* m_truthtracks { nullptr }; TrkrClusterContainer* m_clusters { nullptr }; // cluster container passed to individual clusterers PHG4TruthInfoContainer* m_truthinfo { nullptr }; @@ -54,8 +55,8 @@ class TruthClusterizerBase { /* }; */ public: - TruthClusterizerBase ( int verbosity=0 ); - void init_nodes ( PHCompositeNode*& topNode ); + TruthClusterizerBase ( ); + void init_clusterizer_base ( PHCompositeNode*& _topNode, int verbosity ); virtual ~TruthClusterizerBase(); // main use functions @@ -67,6 +68,7 @@ class TruthClusterizerBase { void addhitset (TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons); // convenience + int Verbosity() { return m_verbosity; }; void set_verbosity(int _) { m_verbosity = _; }; void print_clusters(int nclusprint=20); From 729400b911124649f2ae0c82759785c059138c0f Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 31 Mar 2023 15:01:30 -0400 Subject: [PATCH 072/468] Undo started changes to Tpc clusterizer --- .../g4tpc/PHG4TpcElectronDrift.cc | 87 ++++++++++++++++--- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 14 ++- .../g4tpc/PHG4TpcTruthClusterizer.cc | 66 -------------- .../g4tpc/PHG4TpcTruthClusterizer.h | 39 --------- simulation/g4simulation/g4tpc/TruthTrack.cc | 11 --- 5 files changed, 87 insertions(+), 130 deletions(-) delete mode 100644 simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc delete mode 100644 simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h delete mode 100644 simulation/g4simulation/g4tpc/TruthTrack.cc diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 573b416428..ff9f97dc42 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -4,7 +4,6 @@ #include "PHG4TpcElectronDrift.h" #include "PHG4TpcDistortion.h" #include "PHG4TpcPadPlane.h" // for PHG4TpcPadPlane -#include "PHG4TpcTruthClusterizer.h" #include #include @@ -69,6 +68,7 @@ #include // for _Rb_tree_cons... #include // for pair +#include "TpcClusterBuilder.h" using std::cout; using std::endl; @@ -88,7 +88,6 @@ PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) , PHParameterInterface(name) , temp_hitsetcontainer(new TrkrHitSetContainerv1) , single_hitsetcontainer(new TrkrHitSetContainerv1) - , m_truthclusterizer { new PHG4InttTruthClusterizer } { InitializeParameters(); RandomGenerator.reset(gsl_rng_alloc(gsl_rng_mt19937)); @@ -99,7 +98,6 @@ PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) int PHG4TpcElectronDrift::Init(PHCompositeNode *topNode) { padplane->Init(topNode); - m_truthclusterizer->init_run(topNode, Verbosity()); event_num = 0; return Fun4AllReturnCodes::EVENT_OK; } @@ -163,6 +161,37 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } + truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + if (!truthtracks) + { + PHNodeIterator dstiter(dstNode); + auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!DetNode) + { + DetNode = new PHCompositeNode("TRKR"); + dstNode->addNode(DetNode); + } + + truthtracks = new TrkrTruthTrackContainerv1(); + auto newNode = new PHIODataNode(truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); + DetNode->addNode(newNode); + } + truthclustercontainer = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + if (!truthclustercontainer) + { + PHNodeIterator dstiter(dstNode); + auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!DetNode) + { + DetNode = new PHCompositeNode("TRKR"); + dstNode->addNode(DetNode); + } + + truthclustercontainer = new TrkrClusterContainerv4; + auto newNode = new PHIODataNode(truthclustercontainer, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); + DetNode->addNode(newNode); + } + seggeonodename = "CYLINDERCELLGEOM_SVTX"; // + detector; seggeo = findNode::getClass(topNode, seggeonodename); if (!seggeo) @@ -171,6 +200,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) auto newNode = new PHIODataNode(seggeo, seggeonodename, "PHObject"); runNode->addNode(newNode); } + UpdateParametersWithMacro(); PHNodeIterator runIter(runNode); @@ -292,7 +322,6 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } std::cout << std::endl; } - m_truthclusterizer->init(topNode); return Fun4AllReturnCodes::EVENT_OK; } @@ -306,7 +335,16 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } + if (truth_clusterer == nullptr) { + /* if (Verbosity()) std::cout << " truth clusterer was a null pointer " << std::endl; */ + truth_clusterer = new TpcClusterBuilder(truthclustercontainer, m_tGeometry, seggeo); + } else { + if (Verbosity()) std::cout << " truth clusterer was NOT a null pointer " << std::endl; + } + + static constexpr unsigned int print_layer = 18; + truth_clusterer->is_embedded_track = false; std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer /* std::map> truthtrack_hits; */ @@ -324,6 +362,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) std::cout << "Could not locate g4 hit node " << hitnodename << std::endl; gSystem->Exit(1); } + PHG4TruthInfoContainer *truthinfo = + findNode::getClass(topNode, "G4TruthInfo"); m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); if(!m_tGeometry) @@ -344,6 +384,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) unsigned int dump_interval = 5000; // dump temp_hitsetcontainer to the node tree after this many g4hits unsigned int dump_counter = 0; + int trkid = -1; + for (auto hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter) { count_g4hits++; @@ -355,7 +397,22 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) continue; } - m_truthclusterizer->check_g4hit(hiter->second); + int trkid_new = hiter->second->get_trkid(); + if (trkid != trkid_new) + { // starting a new track + truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ false); + trkid = trkid_new; + truth_clusterer->is_embedded_track = (truthinfo->isEmbeded(trkid)); + if (Verbosity() > 1000){ + std::cout << " New track " << trkid << " is embed? : " + << truth_clusterer->is_embedded_track << std::endl; + } + if (truth_clusterer->is_embedded_track) + { // build new TrkrTruthTrack + current_track = truthtracks->getTruthTrack(trkid, truthinfo); + truth_clusterer->set_current_track(current_track); + } + } // for very high occupancy events, accessing the TrkrHitsets on the node tree // for every drifted electron seems to be very slow // Instead, use a temporary map to accumulate the charge from all @@ -506,7 +563,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) nt->Fill(ihit, t_start, t_final, t_sigma, rad_final, z_start, z_final); } // this fills the cells and updates the hits in temp_hitsetcontainer for this drifted electron hitting the GEM stack - padplane->MapToPadPlane(m_truthclusterizer, single_hitsetcontainer.get(), + padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(), temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, side, hiter, ntpad, nthit); } // end loop over electrons for this g4hit @@ -616,6 +673,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } // end loop over g4hits + truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ true); + if (Verbosity() > 20) { std::cout << "From PHG4TpcElectronDrift: hitsetcontainer printout at end:" << std::endl; @@ -659,11 +718,15 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) ++event_num; // if doing more than one event, event_num will be incremented. - if (m_truthclusterizer) { - if (Verbosity() > 800) { - m_truthclusterizer->print_clusters(); - } - m_truthclusterizer->end_of_event(); + if (Verbosity() > 500) + { + std::cout << " TruthTrackContainer results at end of event in PHG4TpcElectronDrift::process_event " << std::endl; + truthtracks->identify(); + } + + if (Verbosity()>800) { + truth_clusterer->print(truthtracks); + truth_clusterer->print_file(truthtracks,"drift_clusters.txt"); } return Fun4AllReturnCodes::EVENT_OK; @@ -745,7 +808,7 @@ void PHG4TpcElectronDrift::SetDefaultParameters() } PHG4TpcElectronDrift::~PHG4TpcElectronDrift() { - delete m_truthclusterizer; + if (truth_clusterer != nullptr) delete truth_clusterer; } void PHG4TpcElectronDrift::setTpcDistortion(PHG4TpcDistortion *distortionMap) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 675dc11b8e..4d3f6ff183 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -26,7 +26,9 @@ class TrkrHitSetContainer; class TrkrHitTruthAssoc; class TrkrTruthTrackContainer; class TrkrClusterContainer; +class TrkrTruthTrack; class DistortedTrackContainer; +class TpcClusterBuilder; class PHG4TpcCylinderGeomContainer; class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface @@ -63,13 +65,18 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface void registerPadPlane(PHG4TpcPadPlane *padplane); private: - - PHG4TpcTruthClusterizer* m_truthclusterizer; + //! map a given x,y,z coordinates to plane hits + /* TpcClusterBuilder MapToPadPlane(const double x, const double y, const */ + /* double z, const unsigned int side, PHG4HitContainer::ConstIterator hiter, */ + /* TNtuple *ntpad, TNtuple *nthit); */ std::ofstream f_out; TrkrHitSetContainer *hitsetcontainer = nullptr; TrkrHitTruthAssoc *hittruthassoc = nullptr; + TrkrTruthTrackContainer *truthtracks = nullptr; + TrkrTruthTrack *current_track = nullptr; + TrkrClusterContainer *truthclustercontainer = nullptr; // the TrkrClusterContainer for truth clusters std::unique_ptr temp_hitsetcontainer; std::unique_ptr single_hitsetcontainer; std::unique_ptr padplane; @@ -124,6 +131,9 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface double max_time = NAN; + /* std::array layer_clusterers; // Generate TrkrClusterv4's for TrkrTruthTracks */ + TpcClusterBuilder* truth_clusterer { nullptr }; + /* void buildTruthClusters(std::map&); */ //! rng de-allocator diff --git a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc deleted file mode 100644 index 9e41af4ff7..0000000000 --- a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "PHG4TpcTruthClusterizer.h" -#include "PHG4TpcDigitizer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -PHG4TpcTruthClusterizer::PHG4TpcTruthClusterizer ( - PHG4TpcDigitizer* _digitiser - , TpcClusterizer* _clusterizer - , int _verbosity ) - : TruthClusterizerBase (_verbosity) - , m_digitiser { _digitiser } - , m_clusterizer { _clusterizer } -{} - -void PHG4TpcTruthClusterizer::init_run(PHCompositeNode*& _topNode) { - m_topNode = _topNode; - init_nodes(_topNode); // base class TruthClusterizerBase gets required nodes -} - -int PHG4TpcTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) -{ - std::cout << (clusters == nulltpr) << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -void PHG4TpcTruthClusterizer::check_g4hit(PHG4Hit* hit) { - if (m_verbosity>10) std::cout << " -> Checking PHG4Hit in Tpc" << std::endl; - check_g4hit_status(hit); - if (m_was_emb) { - if (m_verbosity>3) { - std::cout << PHWHERE << std::endl - << " -> Pre Tpc Truth("<getTrackid() << ") clustering " << (int) m_hits->size() << " hits" << std::endl; - m_hits->identify(); - } - TrkrClusterContainerv4 clusters{}; - clusterize_hits (&clusters); - transfer_clusters (&clusters); - if (m_verbosity>3) { - std::cout << PHWHERE << std::endl - << " -> Clustered " << (int) clusters.size() << " Tpc Truth clusters" << std::endl; - } - } - if (m_is_new_track) update_track(); -} - -void PHG4TpcTruthClusterizer::end_of_event() { - check_g4hit(nullptr); // flush out last data if ended in truth track - m_hitsetkey_cnt.clear(); - if (m_verbosity>2) { - std::cout << PHWHERE << std::endl << " :: tracks with clusters after clustering in TPC" << std::endl; - for (auto& track : m_truthtracks->getMap()) { - std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); - for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); - std::cout << std::endl; - } - } -} - diff --git a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h b/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h deleted file mode 100644 index 5ca4950f41..0000000000 --- a/simulation/g4simulation/g4tpc/PHG4TpcTruthClusterizer.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef G4TPC_TRUTHCLUSTERIZER__H -#define G4TPC_TRUTHCLUSTERIZER__H - -#include - // This is the helper class for PHG4TpcElectronDrift. It will cluster the - // PHG4Hits which come from each individual embedded ("Truth") track. It uses - // pointers to the PHG4TpcDigitizer and TpcClusterizer modules , which also - // do the clustering for all the PHG4Hits together (from all truth tracks - // together + all other tracks + noise). - // - // Because it makes calls to these other modules, t needs to be initialized - // from the Fun4All driving macro *after* adding the above listed modules. - -class PHG4TpcDigitizer; -class TpcClusterizer; -class PHCompositeNode; - -class PHG4TpcTruthClusterizer : public TruthClusterizerBase { - private: - PHCompositeNode* m_topNode { nullptr }; - PHG4TpcDigitizer* m_digitiser ; - TpcClusterizer* m_clusterizer ; - - public: - PHG4TpcTruthClusterizer (); - - void init_run(PHCompositeNode*& _topNode, int _verbosity); - int clusterize_hits(TrkrClusterContainer*); - void check_g4hit(PHG4Hit*); - void end_of_event(); - ~PHG4TpcTruthClusterizer(){}; - - // all data below is implemented for the clusterize_hits() function - // It does the work that the following modules do for SvtxTrack's: - // (1) g4tpc/PHG4TpcDigitizer -- use prefix _D__ - // (2) tpc/TpcClusterizer -- use prefix _C__ // note that this can probably be *greatly* simplified -}; - -#endif diff --git a/simulation/g4simulation/g4tpc/TruthTrack.cc b/simulation/g4simulation/g4tpc/TruthTrack.cc deleted file mode 100644 index ad72adaf13..0000000000 --- a/simulation/g4simulation/g4tpc/TruthTrack.cc +++ /dev/null @@ -1,11 +0,0 @@ - -#include - - - - - TLorentzVector v1; - v1.SetPxPyPzE(px1, py1, pz1, E1); - virtual int get_vtx_id() const { return -9999; } - - PHG4TruthInfoContainer::PHG4VtxPoint* GetVtx(const int vtxid); From be19d2c06f37ecf17778674442f7a248daf43ce9 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 31 Mar 2023 15:03:26 -0400 Subject: [PATCH 073/468] same as last commit --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 299246c21b..af41b9d117 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -188,7 +188,7 @@ double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() void PHG4TpcPadPlaneReadout::MapToPadPlane( - PHG4TpcTruthClusterizer *tpc_truth_clusterer, + TpcClusterBuilder *tpc_truth_clusterer, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, From 8fc9651a82190f35f2ac2dcaf5cad119bc7591c6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 16:24:47 -0400 Subject: [PATCH 074/468] split LinkDef files so we can build the dictionaries generically and allow scripting for Makefile.ams --- offline/packages/bbc/BbcLinkDef.h | 16 -------- offline/packages/bbc/BbcNorthSouthLinkDef.h | 5 +++ offline/packages/bbc/BbcNorthSouthV1LinkDef.h | 5 +++ offline/packages/bbc/BbcOutLinkDef.h | 5 +++ offline/packages/bbc/BbcOutV1LinkDef.h | 5 +++ offline/packages/bbc/BbcPmtContainerLinkDef.h | 5 +++ .../packages/bbc/BbcPmtContainerV1LinkDef.h | 5 +++ offline/packages/bbc/BbcPmtHitLinkDef.h | 5 +++ offline/packages/bbc/BbcPmtHitV1LinkDef.h | 5 +++ offline/packages/bbc/Makefile.am | 41 ++++++++++++++----- 10 files changed, 70 insertions(+), 27 deletions(-) delete mode 100644 offline/packages/bbc/BbcLinkDef.h create mode 100644 offline/packages/bbc/BbcNorthSouthLinkDef.h create mode 100644 offline/packages/bbc/BbcNorthSouthV1LinkDef.h create mode 100644 offline/packages/bbc/BbcOutLinkDef.h create mode 100644 offline/packages/bbc/BbcOutV1LinkDef.h create mode 100644 offline/packages/bbc/BbcPmtContainerLinkDef.h create mode 100644 offline/packages/bbc/BbcPmtContainerV1LinkDef.h create mode 100644 offline/packages/bbc/BbcPmtHitLinkDef.h create mode 100644 offline/packages/bbc/BbcPmtHitV1LinkDef.h diff --git a/offline/packages/bbc/BbcLinkDef.h b/offline/packages/bbc/BbcLinkDef.h deleted file mode 100644 index 725e3d9b89..0000000000 --- a/offline/packages/bbc/BbcLinkDef.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __CINT__ - -#pragma link off all classes; -#pragma link off all functions; -#pragma link off all globals; - -#pragma link C++ class BbcOut+; -#pragma link C++ class BbcOutV1+; -#pragma link C++ class BbcNorthSouth+; -#pragma link C++ class BbcNorthSouthV1+; -#pragma link C++ class BbcPmtContainer+; -#pragma link C++ class BbcPmtContainerV1+; -#pragma link C++ class BbcPmtHit+; -#pragma link C++ class BbcPmtHitV1+; - -#endif diff --git a/offline/packages/bbc/BbcNorthSouthLinkDef.h b/offline/packages/bbc/BbcNorthSouthLinkDef.h new file mode 100644 index 0000000000..6c1d5313a9 --- /dev/null +++ b/offline/packages/bbc/BbcNorthSouthLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcNorthSouth+; + +#endif diff --git a/offline/packages/bbc/BbcNorthSouthV1LinkDef.h b/offline/packages/bbc/BbcNorthSouthV1LinkDef.h new file mode 100644 index 0000000000..0a1f1bed31 --- /dev/null +++ b/offline/packages/bbc/BbcNorthSouthV1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcNorthSouthV1+; + +#endif diff --git a/offline/packages/bbc/BbcOutLinkDef.h b/offline/packages/bbc/BbcOutLinkDef.h new file mode 100644 index 0000000000..de1118c7b7 --- /dev/null +++ b/offline/packages/bbc/BbcOutLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcOut+; + +#endif diff --git a/offline/packages/bbc/BbcOutV1LinkDef.h b/offline/packages/bbc/BbcOutV1LinkDef.h new file mode 100644 index 0000000000..4c9fbe710b --- /dev/null +++ b/offline/packages/bbc/BbcOutV1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcOutV1+; + +#endif diff --git a/offline/packages/bbc/BbcPmtContainerLinkDef.h b/offline/packages/bbc/BbcPmtContainerLinkDef.h new file mode 100644 index 0000000000..14276d46a0 --- /dev/null +++ b/offline/packages/bbc/BbcPmtContainerLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcPmtContainer+; + +#endif diff --git a/offline/packages/bbc/BbcPmtContainerV1LinkDef.h b/offline/packages/bbc/BbcPmtContainerV1LinkDef.h new file mode 100644 index 0000000000..9a301f755b --- /dev/null +++ b/offline/packages/bbc/BbcPmtContainerV1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcPmtContainerV1+; + +#endif diff --git a/offline/packages/bbc/BbcPmtHitLinkDef.h b/offline/packages/bbc/BbcPmtHitLinkDef.h new file mode 100644 index 0000000000..70f1f299ef --- /dev/null +++ b/offline/packages/bbc/BbcPmtHitLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcPmtHit+; + +#endif diff --git a/offline/packages/bbc/BbcPmtHitV1LinkDef.h b/offline/packages/bbc/BbcPmtHitV1LinkDef.h new file mode 100644 index 0000000000..7e24d75b57 --- /dev/null +++ b/offline/packages/bbc/BbcPmtHitV1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcPmtHitV1+; + +#endif diff --git a/offline/packages/bbc/Makefile.am b/offline/packages/bbc/Makefile.am index 0ac4ddb820..847fbdf158 100644 --- a/offline/packages/bbc/Makefile.am +++ b/offline/packages/bbc/Makefile.am @@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS = foreign # List of shared libraries to produce lib_LTLIBRARIES = \ - libbbc.la + libbbc_io.la AM_CPPFLAGS = \ -I$(includedir) \ @@ -29,12 +29,31 @@ pkginclude_HEADERS = \ BbcPmtHitV1.h \ BbcReturnCodes.h +ROOTDICTS = \ + BbcOut_Dict.cc \ + BbcOutV1_Dict.cc \ + BbcNorthSouth_Dict.cc \ + BbcNorthSouthV1_Dict.cc \ + BbcPmtHit_Dict.cc \ + BbcPmtHitV1_Dict.cc \ + BbcPmtContainer_Dict.cc \ + BbcPmtContainerV1_Dict.cc + pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - Bbc_Dict_rdict.pcm -libbbc_la_SOURCES = \ - Bbc_Dict.cc \ +nobase_dist_pcm_DATA = \ + BbcOut_Dict_rdict.pcm \ + BbcOutV1_Dict_rdict.pcm \ + BbcNorthSouth_Dict_rdict.pcm \ + BbcNorthSouthV1_Dict_rdict.pcm \ + BbcPmtHit_Dict_rdict.pcm \ + BbcPmtHitV1_Dict_rdict.pcm \ + BbcPmtContainer_Dict_rdict.pcm \ + BbcPmtContainerV1_Dict_rdict.pcm + + +libbbc_io_la_SOURCES = \ + $(ROOTDICTS) \ BbcOut.cc \ BbcOutV1.cc \ BbcNorthSouth.cc \ @@ -44,15 +63,15 @@ libbbc_la_SOURCES = \ BbcPmtContainer.cc \ BbcPmtContainerV1.cc -libbbc_la_LIBADD = \ +libbbc_io_la_LIBADD = \ -lphool # Rule for generating table CINT dictionaries. -Bbc_Dict.cc: BbcOut.h BbcOutV1.h BbcNorthSouth.h BbcNorthSouthV1.h BbcPmtContainer.h BbcPmtContainerV1.h BbcPmtHit.h BbcPmtHitV1.h BbcLinkDef.h +%_Dict.cc: %.h %LinkDef.h rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ #just to get the dependency -Bbc_Dict_rdict.pcm: Bbc_Dict.cc ; +%_Dict_rdict.pcm: %_Dict.cc ; ################################################ @@ -62,10 +81,10 @@ BUILT_SOURCES = \ testexternals.cc noinst_PROGRAMS = \ - testexternals_bbc + testexternals -testexternals_bbc_SOURCES = testexternals.cc -testexternals_bbc_LDADD = libbbc.la +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libbbc_io.la testexternals.cc: echo "//*** this is a generated file. Do not commit, do not edit" > $@ From 8a553d22348df97950b34500f599d13a92322c11 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 16:25:46 -0400 Subject: [PATCH 075/468] add bbc_io lib to deps --- simulation/g4simulation/g4dst/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/simulation/g4simulation/g4dst/Makefile.am b/simulation/g4simulation/g4dst/Makefile.am index f888ee6dce..83fdaf4f30 100644 --- a/simulation/g4simulation/g4dst/Makefile.am +++ b/simulation/g4simulation/g4dst/Makefile.am @@ -11,6 +11,7 @@ lib_LTLIBRARIES = \ libg4dst_la_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ + -lbbc_io \ -lcalo_io \ -lcalotrigger_io \ -lcentrality_io \ From 1775f7eb750d46402933f0ab3ce211bbaa2ce294 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 16:26:09 -0400 Subject: [PATCH 076/468] quiet doen histo fit --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index 05429f6fa4..34a6e17f07 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -370,9 +370,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) // gaussian->SetParameter(1,hevt_bbct[iarm]->GetMean()); // gaussian->SetRange(6,hevt_bbct[iarm]->GetMean()+0.125); - hevt_bbct[iarm]->Fit(gaussian, "BLR"); - hevt_bbct[iarm]->Draw(); - + hevt_bbct[iarm]->Fit(gaussian, "BLRNQ"); if (f_bbcn[iarm] > 0) { // f_bbct[iarm] = f_bbct[iarm] / f_bbcn[iarm]; @@ -401,6 +399,8 @@ void BbcSimReco::CreateNodes(PHCompositeNode *topNode) if (!dstNode) { std::cout << PHWHERE << "DST Node missing doing nothing" << std::endl; + gSystem->Exit(1); + exit(1); } PHCompositeNode *bbcNode = dynamic_cast(iter.findFirst("PHCompositeNode", "BBC")); @@ -414,7 +414,6 @@ void BbcSimReco::CreateNodes(PHCompositeNode *topNode) _bbcout = findNode::getClass(bbcNode, "BbcOut"); if (!_bbcout) { - std::cout << "Creating BBCOUT" << std::endl; _bbcout = new BbcOutV1(); PHIODataNode *BbcOutNode = new PHIODataNode(_bbcout, "BbcOut", "PHObject"); bbcNode->addNode(BbcOutNode); From 5fa71fccaa767d4d57ec6d3cd8c4423dcc14b4ee Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 16:37:25 -0400 Subject: [PATCH 077/468] replace dep on libbbc by libbbc_io --- simulation/g4simulation/g4bbc/Makefile.am | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4bbc/Makefile.am b/simulation/g4simulation/g4bbc/Makefile.am index 448abd0730..2071b720b5 100644 --- a/simulation/g4simulation/g4bbc/Makefile.am +++ b/simulation/g4simulation/g4bbc/Makefile.am @@ -18,10 +18,9 @@ libg4bbc_io_la_LIBADD = \ libg4bbc_la_LIBADD = \ libg4bbc_io.la \ + -lbbc_io \ -lg4detectors \ - -lfun4all \ - -lSubsysReco \ - -lbbc + -lSubsysReco pkginclude_HEADERS = \ BbcVertex.h \ From 81d38d2327bf6725e2111c3429bdbb575812b83e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 17:58:58 -0400 Subject: [PATCH 078/468] add bbc object dumps --- offline/packages/NodeDump/DumpBbcOut.cc | 43 +++++++++++++++++++ offline/packages/NodeDump/DumpBbcOut.h | 22 ++++++++++ .../packages/NodeDump/DumpBbcPmtContainer.cc | 39 +++++++++++++++++ .../packages/NodeDump/DumpBbcPmtContainer.h | 22 ++++++++++ offline/packages/NodeDump/Makefile.am | 7 ++- offline/packages/NodeDump/PHNodeDump.cc | 12 +++++- 6 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 offline/packages/NodeDump/DumpBbcOut.cc create mode 100644 offline/packages/NodeDump/DumpBbcOut.h create mode 100644 offline/packages/NodeDump/DumpBbcPmtContainer.cc create mode 100644 offline/packages/NodeDump/DumpBbcPmtContainer.h diff --git a/offline/packages/NodeDump/DumpBbcOut.cc b/offline/packages/NodeDump/DumpBbcOut.cc new file mode 100644 index 0000000000..b68d2909c4 --- /dev/null +++ b/offline/packages/NodeDump/DumpBbcOut.cc @@ -0,0 +1,43 @@ +#include "DumpBbcOut.h" + + +#include + +#include + +#include +#include + + +typedef PHIODataNode MyNode_t; + +DumpBbcOut::DumpBbcOut(const std::string &NodeName): DumpObject(NodeName) +{ + return ; +} + +int DumpBbcOut::process_Node(PHNode *myNode) +{ + BbcOut *bbcout = nullptr; + MyNode_t *thisNode = static_cast (myNode); + if (thisNode) + { + bbcout = thisNode->getData(); + } + if (bbcout && bbcout->isValid()) + { + *fout << "BbcOut->get_VertexPoint: " << bbcout->get_VertexPoint() << std::endl; + *fout << "BbcOut->get_dVertexPoint: " << bbcout->get_dVertexPoint() << std::endl; + *fout << "BbcOut->get_TimeZero: " << bbcout->get_TimeZero() << std::endl; + *fout << "BbcOut->get_dTimeZero: " << bbcout->get_dTimeZero() << std::endl; + + for (int j = 0; j < 2; j++) + { + *fout << "BbcOut->get_nPMT(" << j <<"): " << bbcout->get_nPMT(j) << std::endl; + *fout << "BbcOut->get_nCharge(" << j << "): " << bbcout->get_nCharge(j) << std::endl; + *fout << "BbcOut->get_Timing(" << j << "): " << bbcout->get_Timing(j) << std::endl; + } + } + return 0; +} + diff --git a/offline/packages/NodeDump/DumpBbcOut.h b/offline/packages/NodeDump/DumpBbcOut.h new file mode 100644 index 0000000000..c30bf4780f --- /dev/null +++ b/offline/packages/NodeDump/DumpBbcOut.h @@ -0,0 +1,22 @@ +#ifndef NODEDUMP_DUMPBBCOUT_H +#define NODEDUMP_DUMPBBCOUT_H + + +#include "DumpObject.h" + +#include + +class PHNode; + +class DumpBbcOut : public DumpObject +{ + public: + DumpBbcOut(const std::string &NodeName); + virtual ~DumpBbcOut() {} + + protected: + int process_Node(PHNode *mynode); +}; + +#endif + diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.cc b/offline/packages/NodeDump/DumpBbcPmtContainer.cc new file mode 100644 index 0000000000..2ded99830e --- /dev/null +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.cc @@ -0,0 +1,39 @@ +#include "DumpBbcPmtContainer.h" + + +#include + +#include + +#include +#include + + +typedef PHIODataNode MyNode_t; + +DumpBbcPmtContainer::DumpBbcPmtContainer(const std::string &NodeName): DumpObject(NodeName) +{ + return ; +} + +int DumpBbcPmtContainer::process_Node(PHNode *myNode) +{ + BbcPmtContainer *bbcpmtcontainer = nullptr; + MyNode_t *thisNode = static_cast (myNode); + if (thisNode) + { + bbcpmtcontainer = thisNode->getData(); + } + if (bbcpmtcontainer && bbcpmtcontainer->isValid()) + { + *fout << "BbcPmtContainer->get_npmt: " << bbcpmtcontainer->get_npmt() << std::endl; + for (int j = 0; j < bbcpmtcontainer->get_npmt(); j++) + { + *fout << "BbcPmtContainer->get_adc(" << j <<"): " << bbcpmtcontainer->get_adc(j) << std::endl; + *fout << "BbcPmtContainer->get_tdc0(" << j << "): " << bbcpmtcontainer->get_tdc0(j) << std::endl; + *fout << "BbcPmtContainer->get_tdc1(" << j << "): " << bbcpmtcontainer->get_tdc1(j) << std::endl; + } + } + return 0; +} + diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.h b/offline/packages/NodeDump/DumpBbcPmtContainer.h new file mode 100644 index 0000000000..e50095e842 --- /dev/null +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.h @@ -0,0 +1,22 @@ +#ifndef NODEDUMP_DUMPBBCPMTCONTAINER_H +#define NODEDUMP_DUMPBBCPMTCONTAINER_H + + +#include "DumpObject.h" + +#include + +class PHNode; + +class DumpBbcPmtContainer : public DumpObject +{ + public: + DumpBbcPmtContainer(const std::string &NodeName); + virtual ~DumpBbcPmtContainer() {} + + protected: + int process_Node(PHNode *mynode); +}; + +#endif + diff --git a/offline/packages/NodeDump/Makefile.am b/offline/packages/NodeDump/Makefile.am index f5438f1971..f78f16f053 100644 --- a/offline/packages/NodeDump/Makefile.am +++ b/offline/packages/NodeDump/Makefile.am @@ -14,6 +14,8 @@ pkginclude_HEADERS = \ libphnodedump_la_SOURCES = \ Dumper.cc \ + DumpBbcOut.cc \ + DumpBbcPmtContainer.cc \ DumpBbcVertexMap.cc \ DumpCaloTriggerInfo.cc \ DumpCdbUrlSave.cc \ @@ -65,16 +67,17 @@ libphnodedump_la_SOURCES = \ AM_LDFLAGS = -L$(libdir) -L$(OFFLINE_MAIN)/lib libphnodedump_la_LIBADD = \ - -lg4bbc_io \ + -lbbc_io \ -lcalo_io \ -lcalotrigger_io \ -leventplane_io \ -lffaobjects \ -lg4detectors_io \ - -lphfield_io \ + -lg4bbc_io \ -lg4jets_io \ -lHepMC \ -lparticleflow_io \ + -lphfield_io \ -lphg4hit \ -lSubsysReco \ -ltrackbase_historic_io \ diff --git a/offline/packages/NodeDump/PHNodeDump.cc b/offline/packages/NodeDump/PHNodeDump.cc index a924a73a6d..b67b6f8dd8 100644 --- a/offline/packages/NodeDump/PHNodeDump.cc +++ b/offline/packages/NodeDump/PHNodeDump.cc @@ -1,6 +1,8 @@ #include "PHNodeDump.h" #include "DumpObject.h" +#include "DumpBbcOut.h" +#include "DumpBbcPmtContainer.h" #include "DumpBbcVertexMap.h" #include "DumpCaloTriggerInfo.h" #include "DumpCdbUrlSave.h" @@ -180,7 +182,15 @@ int PHNodeDump::AddDumpObject(const std::string &NodeName, PHNode *node) // need a static cast since only from DST these guys are of type PHIODataNode // when created they are normally PHIODataNode but can be anything else as well TObject *tmp = static_cast((static_cast *>(node))->getData()); - if (tmp->InheritsFrom("BbcVertexMap")) + if (tmp->InheritsFrom("BbcOut")) + { + newdump = new DumpBbcOut(NodeName); + } + else if (tmp->InheritsFrom("BbcPmtContainer")) + { + newdump = new DumpBbcPmtContainer(NodeName); + } + else if (tmp->InheritsFrom("BbcVertexMap")) { newdump = new DumpBbcVertexMap(NodeName); } From c29f2a9099641eef5c1f5810a0b1e644b880c560 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:00:48 -0400 Subject: [PATCH 079/468] rename include guards according to sphenix standards --- offline/packages/bbc/BbcNorthSouth.h | 6 ++++-- offline/packages/bbc/BbcNorthSouthV1.h | 6 ++++-- offline/packages/bbc/BbcOut.h | 8 +++++--- offline/packages/bbc/BbcOutV1.h | 7 ++++--- offline/packages/bbc/BbcPmtContainer.h | 6 ++++-- offline/packages/bbc/BbcPmtContainerV1.h | 6 ++++-- offline/packages/bbc/BbcPmtHit.h | 6 ++++-- offline/packages/bbc/BbcPmtHitV1.h | 6 ++++-- offline/packages/bbc/BbcReturnCodes.h | 6 ++++-- 9 files changed, 37 insertions(+), 20 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index 75fad2c887..d5665bcf8f 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -1,5 +1,7 @@ -#ifndef __BBCNORTHSOUTH_H__ -#define __BBCNORTHSOUTH_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCNORTHSOUTH_H +#define BBC_BBCNORTHSOUTH_H #include "phool/phool.h" #include diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 5ae8c60a20..398f408b60 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -1,5 +1,7 @@ -#ifndef __BBCNORTHSOUTHV1_H__ -#define __BBCNORTHSOUTHV1_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCNORTHSOUTHV1_H +#define BBC_BBCNORTHSOUTHV1_H #include "BbcNorthSouth.h" diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index b6a1f38d7e..75b81f41cb 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -1,7 +1,9 @@ -#ifndef __BBCOUT_H__ -#define __BBCOUT_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCOUT_H +#define BBC_BBCOUT_H -#include "phool/PHObject.h" +#include /// class BbcOut: public PHObject diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index b884b0de47..760ca95ac8 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -1,5 +1,7 @@ -#ifndef __BBCOUTV1_H -#define __BBCOUTV1_H +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCOUTV1_H +#define BBC_BBCOUTV1_H #include "BbcOut.h" class TClonesArray; @@ -89,7 +91,6 @@ class BbcOutV1: public BbcOut Float_t Bbc_dTimeZero; TClonesArray *BbcNS; -private: // so the ClassDef does not show up with doc++ ClassDefOverride(BbcOutV1,1) }; diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index ebca5ea07c..163cb70144 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -1,7 +1,9 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. // virtual Bbc PMT Container class -#ifndef __BBCPMTCONTAINER_H__ -#define __BBCPMTCONTAINER_H__ +#ifndef BBC_BBCPMTCONTAINER_H +#define BBC_BBCPMTCONTAINER_H #include "phool/PHObject.h" #include diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index 91e269ad27..a3627156f7 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -1,5 +1,7 @@ -#ifndef __BBCPMTCONTAINERV1_H__ -#define __BBCPMTCONTAINERV1_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCPMTCONTAINERV1_H +#define BBC_BBCPMTCONTAINERV1_H #include "BbcPmtContainer.h" diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 4187da217a..359c8bde91 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -1,5 +1,7 @@ -#ifndef __BBCPMTHIT_H__ -#define __BBCPMTHIT_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCPMTHIT_H +#define BBC_BBCPMTHIT_H #include #include diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 4221232105..316d9478a1 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -1,5 +1,7 @@ -#ifndef __BBCPMTHITV1_H__ -#define __BBCPMTHITV1_H__ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBC_BBCPMTHITV1_H +#define BBC_BBCPMTHITV1_H #include "BbcPmtHit.h" #include diff --git a/offline/packages/bbc/BbcReturnCodes.h b/offline/packages/bbc/BbcReturnCodes.h index 3d39b8500a..d9a713d189 100644 --- a/offline/packages/bbc/BbcReturnCodes.h +++ b/offline/packages/bbc/BbcReturnCodes.h @@ -1,9 +1,11 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. /* Return codes */ -#ifndef BBCRETURNCODE -#define BBCRETURNCODE +#ifndef BBC_BBCRETURNCODES_H +#define BBC_BBCRETURNCODES_H const short BBC_INVALID_SHORT = -9999; const int BBC_INVALID_INT = -9999; From d3c2a8dfb3a4d6322808af03b2658f23ddb7637e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:25:28 -0400 Subject: [PATCH 080/468] use std::numeric_limits for invalid returns --- offline/packages/bbc/BbcOut.cc | 2 +- offline/packages/bbc/BbcOutV1.cc | 12 ++++++------ offline/packages/bbc/BbcPmtContainer.cc | 8 ++++---- offline/packages/bbc/BbcPmtContainerV1.cc | 6 +++--- offline/packages/bbc/BbcPmtHitV1.cc | 11 +++++------ offline/packages/bbc/BbcReturnCodes.h | 16 +++++++++------- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index ebca871408..c8f0335add 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -80,7 +80,7 @@ void BbcOut::AddBbcNS(const int /*nBbc*/, const Short_t /*npmt*/, const Float_t Short_t BbcOut::get_nPMT(const int /*nBbc*/) const { virtual_warning("get_nPMT(const int nBbc)"); - return BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_SHORT; } Float_t BbcOut::get_nCharge(const int /*nBbc*/) const diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index 782fd21270..3c6a0f110c 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -92,22 +92,22 @@ void BbcOutV1::AddBbcNS(const int iBBC, const Short_t npmt, const Float_t energy Short_t BbcOutV1::get_nPMT(const int nBbc) const { BbcNorthSouthV1 *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BBC_INVALID_SHORT, else nPMT - return((bbcns) ? bbcns->get_nPMT() : BBC_INVALID_SHORT); + // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_SHORT, else nPMT + return((bbcns) ? bbcns->get_nPMT() : BbcReturnCodes::BBC_INVALID_SHORT); } //______________________________________ Float_t BbcOutV1::get_nCharge(const int nBbc) const { BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BBC_INVALID_FLOAT, else Energy - return((bbcns) ? bbcns->get_nCharge() : BBC_INVALID_FLOAT); + // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Energy + return((bbcns) ? bbcns->get_nCharge() : BbcReturnCodes::BBC_INVALID_FLOAT); } Float_t BbcOutV1::get_Timing(const int nBbc) const { BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BBC_INVALID_FLOAT, else Timing - return((bbcns) ? bbcns->get_MeanTime() : BBC_INVALID_FLOAT); + // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Timing + return((bbcns) ? bbcns->get_MeanTime() : BbcReturnCodes::BBC_INVALID_FLOAT); } diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index c9c3b79734..7c22172807 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -34,25 +34,25 @@ void BbcPmtContainer::set_npmt(const Short_t /*ival*/) short BbcPmtContainer::get_npmt() const { virtual_warning("get_npmt()"); - return BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_SHORT; } Float_t BbcPmtContainer::get_adc(const int /*iPmt*/) const { virtual_warning("get_Adc(const short iPmt)"); - return BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_SHORT; } Float_t BbcPmtContainer::get_tdc0(const int /*iPmt*/) const { virtual_warning("get_Tdc0(const short iPmt)"); - return BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_SHORT; } Float_t BbcPmtContainer::get_tdc1(const int /*iPmt*/) const { virtual_warning("get_Tdc1(const short iPmt)"); - return BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_SHORT; } void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const Float_t /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index b12e342bc3..d09a93959d 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -50,19 +50,19 @@ void BbcPmtContainerV1::AddBbcPmt(const Short_t pmt, const Float_t adc, const Fl Float_t BbcPmtContainerV1::get_adc(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_adc() : BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_SHORT); } Float_t BbcPmtContainerV1::get_tdc0(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_tdc0() : BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_SHORT); } Float_t BbcPmtContainerV1::get_tdc1(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_tdc1() : BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_SHORT); } void BbcPmtContainerV1::identify(ostream& out) const diff --git a/offline/packages/bbc/BbcPmtHitV1.cc b/offline/packages/bbc/BbcPmtHitV1.cc index d3c7c0401c..924ce78273 100644 --- a/offline/packages/bbc/BbcPmtHitV1.cc +++ b/offline/packages/bbc/BbcPmtHitV1.cc @@ -1,9 +1,6 @@ #include "BbcPmtHitV1.h" -#include - -ClassImp(BbcPmtHitV1) -using namespace std; +#include BbcPmtHitV1::BbcPmtHitV1(const Short_t ipmt, const Float_t iadc, const Float_t itdc0, const Float_t itdc1) : pmt(ipmt), @@ -14,7 +11,9 @@ BbcPmtHitV1::BbcPmtHitV1(const Short_t ipmt, const Float_t iadc, const Float_t i } -void BbcPmtHitV1::identify(ostream& out) const +void BbcPmtHitV1::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcPmtHitV1 object" << endl; + out << "identify yourself: I am a BbcPmtHitV1 object" << std::endl; + out << "Pmt: " << pmt << ", adc: " << adc << ", tdc0: " + << tdc0 << ", tdc1: " << tdc1 << std::endl; } diff --git a/offline/packages/bbc/BbcReturnCodes.h b/offline/packages/bbc/BbcReturnCodes.h index d9a713d189..b1194fdec8 100644 --- a/offline/packages/bbc/BbcReturnCodes.h +++ b/offline/packages/bbc/BbcReturnCodes.h @@ -1,15 +1,17 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -/* -Return codes -*/ + #ifndef BBC_BBCRETURNCODES_H #define BBC_BBCRETURNCODES_H -const short BBC_INVALID_SHORT = -9999; -const int BBC_INVALID_INT = -9999; -const long BBC_INVALID_LONG = -9999; -const float BBC_INVALID_FLOAT = -9999.9; +#include + +namespace BbcReturnCodes +{ + const short BBC_INVALID_SHORT = std::numeric_limits::min();//-9999; + const int BBC_INVALID_INT = std::numeric_limits::min();//-9999; + const float BBC_INVALID_FLOAT = std::numeric_limits::quiet_NaN(); +} #endif From cbaac2a61beb7586458d1ae710e84632a93f3a27 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:46:41 -0400 Subject: [PATCH 081/468] modernize --- offline/packages/bbc/BbcNorthSouth.cc | 8 ++--- offline/packages/bbc/BbcNorthSouth.h | 18 +++++------ offline/packages/bbc/BbcNorthSouthV1.cc | 14 +++------ offline/packages/bbc/BbcOut.cc | 6 ++-- offline/packages/bbc/BbcOut.h | 15 +++++---- offline/packages/bbc/BbcOutV1.cc | 17 +++------- offline/packages/bbc/BbcOutV1.h | 38 +++++++++++------------ offline/packages/bbc/BbcPmtContainer.cc | 16 +++++----- offline/packages/bbc/BbcPmtContainer.h | 6 ++-- offline/packages/bbc/BbcPmtContainerV1.cc | 16 +++------- offline/packages/bbc/BbcPmtContainerV1.h | 7 ++--- offline/packages/bbc/BbcPmtHit.cc | 9 ++---- offline/packages/bbc/BbcPmtHit.h | 8 +++-- offline/packages/bbc/BbcPmtHitV1.h | 4 +-- 14 files changed, 76 insertions(+), 106 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.cc b/offline/packages/bbc/BbcNorthSouth.cc index 496cbb3f1e..e391f26084 100644 --- a/offline/packages/bbc/BbcNorthSouth.cc +++ b/offline/packages/bbc/BbcNorthSouth.cc @@ -1,11 +1,7 @@ #include "BbcNorthSouth.h" -using namespace std; - -ClassImp(BbcNorthSouth) - -void BbcNorthSouth::identify(ostream& out) const +void BbcNorthSouth::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcNorthSouth object" << endl; + out << "identify yourself: I am a BbcNorthSouth object" << std::endl; } diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index d5665bcf8f..59f1ac20dc 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -3,26 +3,22 @@ #ifndef BBC_BBCNORTHSOUTH_H #define BBC_BBCNORTHSOUTH_H -#include "phool/phool.h" -#include +#include +#include -class BbcNorthSouth : public TObject +class BbcNorthSouth : public PHObject { public: - BbcNorthSouth() { } - BbcNorthSouth(const Short_t /*npmts*/, const Float_t /*ncharge*/, const Float_t /*meantime*/) {} - virtual ~BbcNorthSouth() { } - virtual void identify(std::ostream& os = std::cout) const; + BbcNorthSouth() = default; + + ~BbcNorthSouth() override = default; + virtual void identify(std::ostream& os = std::cout) const override; virtual Short_t get_nPMT() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual Float_t get_nCharge() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual Float_t get_MeanTime() const { PHOOL_VIRTUAL_WARNING; return -9999; } -protected: - - virtual void Clear(Option_t * /*option*/ = "") override { PHOOL_VIRTUAL_WARNING; } - private: ClassDefOverride(BbcNorthSouth,1) diff --git a/offline/packages/bbc/BbcNorthSouthV1.cc b/offline/packages/bbc/BbcNorthSouthV1.cc index 572b40efd4..2e2baaa6a2 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.cc +++ b/offline/packages/bbc/BbcNorthSouthV1.cc @@ -1,18 +1,14 @@ #include "BbcNorthSouthV1.h" -using namespace std; - -ClassImp(BbcNorthSouthV1) - BbcNorthSouthV1::BbcNorthSouthV1(const Short_t npmt, const Float_t ncharge, const Float_t meantime) + : nPmt(npmt) + , nCharge(ncharge) + , MeanTime(meantime) { - nPmt = npmt; - nCharge = ncharge; - MeanTime = meantime; } -void BbcNorthSouthV1::identify(ostream& out) const +void BbcNorthSouthV1::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcNorthSouthV1 object" << endl; + out << "identify yourself: I am a BbcNorthSouthV1 object" << std::endl; } diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index c8f0335add..d5bcf94ea5 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -4,11 +4,9 @@ #include #include -//ClassImp(BbcOut) - void BbcOut::identify(std::ostream& os) const { - os << "virtual BbcOut object"; + os << "virtual BbcOut object" << std::endl; return ; } @@ -95,7 +93,7 @@ Float_t BbcOut::get_Timing(const int /*nBbc*/) const return NAN; } -void BbcOut::virtual_warning(const char *funcsname) const +void BbcOut::virtual_warning(const std::string &funcsname) const { std::cout << "BbcOut::" << funcsname << " is virtual, doing nothing" << std::endl; return ; diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index 75b81f41cb..133883e058 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -5,23 +5,25 @@ #include +#include + /// class BbcOut: public PHObject { public: /// - virtual ~BbcOut() {} + ~BbcOut() override {} /** identify Function from PHObject @param os Output Stream */ - virtual void identify(std::ostream& os = std::cout) const override; + void identify(std::ostream& os = std::cout) const override; /// Clear Event - virtual void Reset() override; + void Reset() override; /// isValid returns non zero if object contains vailid data - virtual int isValid() const override; + int isValid() const override; /// get ZVertex determined by Bbc virtual Float_t get_VertexPoint() const; @@ -87,12 +89,9 @@ class BbcOut: public PHObject virtual void FillFromClass(const BbcOut& old); private: - void virtual_warning(const char *funcname) const; + void virtual_warning(const std::string &funcname) const; - /// Root Internal Version ClassDefOverride(BbcOut,1) - - }; #endif diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index 3c6a0f110c..1cf6b6ebcf 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -3,15 +3,11 @@ #include "BbcNorthSouthV1.h" #include + #include -//static const int NPMTBBCV1 = 128; static const int NBBC = 2; -using namespace std; - -ClassImp(BbcOutV1) - //______________________________________ BbcOutV1::BbcOutV1() { @@ -31,10 +27,7 @@ void BbcOutV1::Init() //______________________________________ BbcOutV1::~BbcOutV1() { - if (BbcNS) - { delete BbcNS; - } } //______________________________________ @@ -54,11 +47,11 @@ void BbcOutV1::Reset() } //______________________________________ -void BbcOutV1::identify(ostream& out) const +void BbcOutV1::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcOutV1 object" << endl; - out << "Vertex: " << Bbc_ZVertex << " Error: " << Bbc_dZVertex << endl; - out << "T0: " << Bbc_TimeZero << " Error: " << Bbc_dTimeZero << endl; + out << "identify yourself: I am a BbcOutV1 object" << std::endl; + out << "Vertex: " << Bbc_ZVertex << " Error: " << Bbc_dZVertex << std::endl; + out << "T0: " << Bbc_TimeZero << " Error: " << Bbc_dTimeZero << std::endl; } //______________________________________ diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index 760ca95ac8..cb5685f7b8 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -4,6 +4,7 @@ #define BBC_BBCOUTV1_H #include "BbcOut.h" + class TClonesArray; /// @@ -14,44 +15,44 @@ class BbcOutV1: public BbcOut /// BbcOutV1(); /// - virtual ~BbcOutV1(); + ~BbcOutV1() override; /// Clear Event from memory - virtual void Reset() override; + void Reset() override; /** identify Function from PHObject @param os Output Stream */ - virtual void identify(std::ostream& os = std::cout) const override; + void identify(std::ostream& os = std::cout) const override; /// isValid returns non zero if object contains vailid data - virtual int isValid() const override; + int isValid() const override; /// get ZVertex determined by Bbc - virtual Float_t get_VertexPoint() const override {return Bbc_ZVertex;} + Float_t get_VertexPoint() const override {return Bbc_ZVertex;} /// get Error on ZVertex determined by Bbc - virtual Float_t get_dVertexPoint() const override {return Bbc_dZVertex;} + Float_t get_dVertexPoint() const override {return Bbc_dZVertex;} /// get T0 determined by Bbc - virtual Float_t get_TimeZero() const override {return Bbc_TimeZero;} + Float_t get_TimeZero() const override {return Bbc_TimeZero;} /// get Error on T0 determined by Bbc - virtual Float_t get_dTimeZero() const override {return Bbc_dTimeZero;} + Float_t get_dTimeZero() const override {return Bbc_dTimeZero;} /** set T0 for Bbc @param t0 Bbc T0 @param t0err Bbc T0 error */ - virtual void set_TimeZero(const Float_t t0, const Float_t t0err = 0) override; + void set_TimeZero(const Float_t t0, const Float_t t0err = 0) override; //! set vertex - virtual void set_Vertex( const Float_t vtx, const Float_t vtxerr = 0) override; + void set_Vertex( const Float_t vtx, const Float_t vtxerr = 0) override; /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error */ - virtual void set_dZVertex(const Float_t vtxerr) override; + void set_dZVertex(const Float_t vtxerr) override; /** Add Bbc North/South object containing Number of pmt's, Energy and Timing @param npmt Number of PMT's fired @@ -59,32 +60,31 @@ class BbcOutV1: public BbcOut @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual void AddBbcNS(const int nBbc, const Short_t npmt, const Float_t chargesum, const Float_t timing) override; + void AddBbcNS(const int nBbc, const Short_t npmt, const Float_t chargesum, const Float_t timing) override; /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Short_t get_nPMT(const int nBbc) const override; + Short_t get_nPMT(const int nBbc) const override; /** get Number of Charged Particles into North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Float_t get_nCharge(const int nBbc) const override; + Float_t get_nCharge(const int nBbc) const override; /** get Timing of North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Float_t get_Timing(const int nBbc) const override; + Float_t get_Timing(const int nBbc) const override; -protected: - virtual void Init(); - - TClonesArray *GetBbcNS() const { return BbcNS; } private: + + TClonesArray *GetBbcNS() const { return BbcNS; } + Float_t Bbc_ZVertex; Float_t Bbc_dZVertex; Float_t Bbc_TimeZero; diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index 7c22172807..5cc1dcbfdb 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -1,21 +1,19 @@ -#include -#include "phool/phool.h" #include "BbcPmtContainer.h" #include "BbcReturnCodes.h" -using namespace std; +#include -//ClassImp(BbcPmtContainer) +#include -void BbcPmtContainer::identify(ostream& os) const +void BbcPmtContainer::identify(std::ostream& os) const { - os << "virtual BbcPmtContainer object"; + os << "virtual BbcPmtContainer object" << std::endl; return ; } void BbcPmtContainer::Reset() { - cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << endl; + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; return ; } @@ -61,9 +59,9 @@ void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const Float_t /*adc*/, c return ; } -void BbcPmtContainer::virtual_warning(const char *funcsname) const +void BbcPmtContainer::virtual_warning(const std::string &funcsname) const { - cout << "BbcPmtContainer::" << funcsname << " is virtual, doing nothing" << endl; + std::cout << "BbcPmtContainer::" << funcsname << " is virtual, doing nothing" << std::endl; return ; } diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index 163cb70144..3ec4c25e76 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -5,8 +5,10 @@ #ifndef BBC_BBCPMTCONTAINER_H #define BBC_BBCPMTCONTAINER_H -#include "phool/PHObject.h" +#include + #include +#include /// class BbcPmtContainer : public PHObject @@ -58,7 +60,7 @@ class BbcPmtContainer : public PHObject virtual void AddBbcPmt(const Short_t ipmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1); private: - void virtual_warning(const char *funcname) const; + void virtual_warning(const std::string &funcname) const; ClassDefOverride(BbcPmtContainer,1) }; diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index d09a93959d..63643a0ecc 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -1,29 +1,23 @@ #include "BbcPmtContainerV1.h" #include "BbcPmtHitV1.h" #include "BbcReturnCodes.h" + #include -#include -using namespace std; +#include static const int NPMTBBCV1 = 128; -ClassImp(BbcPmtContainerV1) - BbcPmtContainerV1::BbcPmtContainerV1() { // BbcPmtHit is class for single hit (members: pmt,adc,tdc0,tdc1), do not mix // with TClonesArray *BbcPmtHits BbcPmtHits = new TClonesArray("BbcPmtHitV1", NPMTBBCV1); - npmt = 0; } BbcPmtContainerV1::~BbcPmtContainerV1() { - if (BbcPmtHits) - { - delete BbcPmtHits; - } + delete BbcPmtHits; } int BbcPmtContainerV1::isValid() const @@ -65,7 +59,7 @@ Float_t BbcPmtContainerV1::get_tdc1(const int iPmt) const return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_SHORT); } -void BbcPmtContainerV1::identify(ostream& out) const +void BbcPmtContainerV1::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcPmtContainerV1 object" << endl; + out << "identify yourself: I am a BbcPmtContainerV1 object" << std::endl; } diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index a3627156f7..c5ecc84155 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -61,14 +61,13 @@ class BbcPmtContainerV1 : public BbcPmtContainer */ void AddBbcPmt(const Short_t ipmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1) override; -protected: +private: TClonesArray *GetBbcPmtHits() const {return BbcPmtHits;} - Short_t npmt; - TClonesArray *BbcPmtHits; + Short_t npmt = 0; + TClonesArray *BbcPmtHits = nullptr; -private: // so the ClassDef does not show up with doc++ ClassDefOverride(BbcPmtContainerV1,1) }; diff --git a/offline/packages/bbc/BbcPmtHit.cc b/offline/packages/bbc/BbcPmtHit.cc index c4f0d83782..6807d3bd7e 100644 --- a/offline/packages/bbc/BbcPmtHit.cc +++ b/offline/packages/bbc/BbcPmtHit.cc @@ -1,11 +1,8 @@ #include "BbcPmtHit.h" -#include - -ClassImp(BbcPmtHit) -using namespace std; +#include -void BbcPmtHit::identify(ostream& out) const +void BbcPmtHit::identify(std::ostream& out) const { - out << "identify yourself: I am a BbcPmtHit object" << endl; + out << "identify yourself: I am a BbcPmtHit object" << std::endl; } diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 359c8bde91..8959097c1a 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -4,10 +4,12 @@ #define BBC_BBCPMTHIT_H #include + +#include #include -#include -class BbcPmtHit : public TObject + +class BbcPmtHit : public PHObject { public: @@ -20,7 +22,7 @@ class BbcPmtHit : public TObject virtual Float_t get_tdc0() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual Float_t get_tdc1() const { PHOOL_VIRTUAL_WARNING; return -9999; } - void identify(std::ostream& os = std::cout) const; + void identify(std::ostream& os = std::cout) const override; private: ClassDefOverride(BbcPmtHit,1) diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 316d9478a1..442d195fe2 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -4,6 +4,7 @@ #define BBC_BBCPMTHITV1_H #include "BbcPmtHit.h" + #include class BbcPmtHitV1 : public BbcPmtHit @@ -21,13 +22,12 @@ class BbcPmtHitV1 : public BbcPmtHit void identify(std::ostream& os = std::cout) const; -protected: +private: Short_t pmt; Float_t adc; Float_t tdc0; Float_t tdc1; -private: ClassDefOverride(BbcPmtHitV1,1) }; From 5dafdf580a72e233f7149e6e635408878312860f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:55:42 -0400 Subject: [PATCH 082/468] fix invalid return codes to correct type --- offline/packages/bbc/BbcPmtContainer.cc | 12 +++++++++--- offline/packages/bbc/BbcPmtContainer.h | 5 +++++ offline/packages/bbc/BbcPmtContainerV1.cc | 12 +++++++++--- offline/packages/bbc/BbcPmtContainerV1.h | 5 +++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index 5cc1dcbfdb..ad451cceeb 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -35,22 +35,28 @@ short BbcPmtContainer::get_npmt() const return BbcReturnCodes::BBC_INVALID_SHORT; } +Short_t BbcPmtContainer::get_pmt(const int /*iPmt*/) const +{ + virtual_warning("get_pmt(const short iPmt)"); + return BbcReturnCodes::BBC_INVALID_SHORT; +} + Float_t BbcPmtContainer::get_adc(const int /*iPmt*/) const { virtual_warning("get_Adc(const short iPmt)"); - return BbcReturnCodes::BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_FLOAT; } Float_t BbcPmtContainer::get_tdc0(const int /*iPmt*/) const { virtual_warning("get_Tdc0(const short iPmt)"); - return BbcReturnCodes::BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_FLOAT; } Float_t BbcPmtContainer::get_tdc1(const int /*iPmt*/) const { virtual_warning("get_Tdc1(const short iPmt)"); - return BbcReturnCodes::BBC_INVALID_SHORT; + return BbcReturnCodes::BBC_INVALID_FLOAT; } void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const Float_t /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index 3ec4c25e76..922d358a4a 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -36,6 +36,11 @@ class BbcPmtContainer : public PHObject /// get Number of Bbc Pmt's virtual Short_t get_npmt() const; + /** get id of Pmt iPmt in TClonesArray + @param iPmt no of Pmt in TClonesArray + */ + virtual Short_t get_pmt(const int iPmt) const; + /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index 63643a0ecc..215f891f56 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -41,22 +41,28 @@ void BbcPmtContainerV1::AddBbcPmt(const Short_t pmt, const Float_t adc, const Fl new(Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); } +Short_t BbcPmtContainerV1::get_pmt(const int iPmt) const +{ + BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); + return ((Bbchit) ? Bbchit->get_pmt() : BbcReturnCodes::BBC_INVALID_SHORT); +} + Float_t BbcPmtContainerV1::get_adc(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_FLOAT); } Float_t BbcPmtContainerV1::get_tdc0(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_FLOAT); } Float_t BbcPmtContainerV1::get_tdc1(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); - return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_SHORT); + return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_FLOAT); } void BbcPmtContainerV1::identify(std::ostream& out) const diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index c5ecc84155..bd7ce5d401 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -37,6 +37,11 @@ class BbcPmtContainerV1 : public BbcPmtContainer /// get Number of Bbc Pmt's Short_t get_npmt() const override {return npmt;} + /** get id of Pmt iPmt in TClonesArray + @param iPmt no of Pmt in TClonesArray + */ + Short_t get_pmt(const int iPmt) const override; + /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ From 304a4b3710c148d6e1a07beaf91f759a8fb0ab29 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:56:09 -0400 Subject: [PATCH 083/468] add bbcpmtcontainer->get_pmt to NodeDump/DumpBbcPmtContainer.cc --- offline/packages/NodeDump/DumpBbcPmtContainer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.cc b/offline/packages/NodeDump/DumpBbcPmtContainer.cc index 2ded99830e..521b3a016d 100644 --- a/offline/packages/NodeDump/DumpBbcPmtContainer.cc +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.cc @@ -29,6 +29,7 @@ int DumpBbcPmtContainer::process_Node(PHNode *myNode) *fout << "BbcPmtContainer->get_npmt: " << bbcpmtcontainer->get_npmt() << std::endl; for (int j = 0; j < bbcpmtcontainer->get_npmt(); j++) { + *fout << "BbcPmtContainer->get_pmt(" << j <<"): " << bbcpmtcontainer->get_pmt(j) << std::endl; *fout << "BbcPmtContainer->get_adc(" << j <<"): " << bbcpmtcontainer->get_adc(j) << std::endl; *fout << "BbcPmtContainer->get_tdc0(" << j << "): " << bbcpmtcontainer->get_tdc0(j) << std::endl; *fout << "BbcPmtContainer->get_tdc1(" << j << "): " << bbcpmtcontainer->get_tdc1(j) << std::endl; From 954e0993eeb8efb69ad7c82c80ed5eeee2aaa103 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 18:58:43 -0400 Subject: [PATCH 084/468] add missing override --- offline/packages/bbc/BbcPmtHitV1.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 442d195fe2..84527cfb14 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -13,14 +13,14 @@ class BbcPmtHitV1 : public BbcPmtHit public: BbcPmtHitV1() { } BbcPmtHitV1(const Short_t pmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1); - virtual ~BbcPmtHitV1() { } + ~BbcPmtHitV1() override = default; Short_t get_pmt() const override {return pmt;} Float_t get_adc() const override {return adc;} Float_t get_tdc0() const override {return tdc0;} Float_t get_tdc1() const override {return tdc1;} - void identify(std::ostream& os = std::cout) const; + void identify(std::ostream& os = std::cout) const override; private: Short_t pmt; From 9b90d12263c7ccd27db4f266523204183e27dfd7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 19:00:05 -0400 Subject: [PATCH 085/468] replace Float_t by float --- offline/packages/bbc/BbcNorthSouth.h | 4 ++-- offline/packages/bbc/BbcNorthSouthV1.cc | 2 +- offline/packages/bbc/BbcNorthSouthV1.h | 10 ++++---- offline/packages/bbc/BbcOut.cc | 28 +++++++++++------------ offline/packages/bbc/BbcOut.h | 22 +++++++++--------- offline/packages/bbc/BbcOutV1.cc | 12 +++++----- offline/packages/bbc/BbcOutV1.h | 28 +++++++++++------------ offline/packages/bbc/BbcPmtContainer.cc | 10 ++++---- offline/packages/bbc/BbcPmtContainer.h | 8 +++---- offline/packages/bbc/BbcPmtContainerV1.cc | 8 +++---- offline/packages/bbc/BbcPmtContainerV1.h | 8 +++---- offline/packages/bbc/BbcPmtHit.h | 8 +++---- offline/packages/bbc/BbcPmtHitV1.cc | 2 +- offline/packages/bbc/BbcPmtHitV1.h | 14 ++++++------ 14 files changed, 82 insertions(+), 82 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index 59f1ac20dc..1d9a51fb54 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -16,8 +16,8 @@ class BbcNorthSouth : public PHObject virtual void identify(std::ostream& os = std::cout) const override; virtual Short_t get_nPMT() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual Float_t get_nCharge() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual Float_t get_MeanTime() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual float get_nCharge() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual float get_MeanTime() const { PHOOL_VIRTUAL_WARNING; return -9999; } private: diff --git a/offline/packages/bbc/BbcNorthSouthV1.cc b/offline/packages/bbc/BbcNorthSouthV1.cc index 2e2baaa6a2..9aeca95acc 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.cc +++ b/offline/packages/bbc/BbcNorthSouthV1.cc @@ -1,6 +1,6 @@ #include "BbcNorthSouthV1.h" -BbcNorthSouthV1::BbcNorthSouthV1(const Short_t npmt, const Float_t ncharge, const Float_t meantime) +BbcNorthSouthV1::BbcNorthSouthV1(const Short_t npmt, const float ncharge, const Float_t meantime) : nPmt(npmt) , nCharge(ncharge) , MeanTime(meantime) diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 398f408b60..68a53e1aa0 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -10,20 +10,20 @@ class BbcNorthSouthV1 : public BbcNorthSouth { public: BbcNorthSouthV1() { } - BbcNorthSouthV1(const Short_t npmt, const Float_t chargesum, const Float_t timing); + BbcNorthSouthV1(const Short_t npmt, const float chargesum, const Float_t timing); virtual ~BbcNorthSouthV1() { } void identify(std::ostream& os = std::cout) const override; Short_t get_nPMT() const override { return nPmt; } - Float_t get_nCharge() const override { return nCharge; } - Float_t get_MeanTime() const override { return MeanTime; } + float get_nCharge() const override { return nCharge; } + float get_MeanTime() const override { return MeanTime; } protected: virtual void Clear(Option_t * /*option*/ = "") override { } Short_t nPmt; - Float_t nCharge; - Float_t MeanTime; + float nCharge; + float MeanTime; private: ClassDefOverride(BbcNorthSouth,1) diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index d5bcf94ea5..0c6076a0f1 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -22,56 +22,56 @@ int BbcOut::isValid() const return 0; } -Float_t BbcOut::get_VertexPoint() const +float BbcOut::get_VertexPoint() const { virtual_warning("get_VertexPoint()"); return NAN; } -Float_t BbcOut::get_dVertexPoint() const +float BbcOut::get_dVertexPoint() const { virtual_warning("get_dVertexPoint()"); return NAN; } -Float_t BbcOut::get_TimeZero() const +float BbcOut::get_TimeZero() const { virtual_warning("get_TimeZero()"); return NAN; } //__________________________________________ -Float_t BbcOut::get_dTimeZero() const +float BbcOut::get_dTimeZero() const { virtual_warning("get_dTimeZero()"); return NAN; } //__________________________________________ -void BbcOut::set_TimeZero(const Float_t, const Float_t) +void BbcOut::set_TimeZero(const float, const Float_t) { - virtual_warning("set_TimeZero(const Float_t t0, const Float_t t0err)"); + virtual_warning("set_TimeZero(const float t0, const Float_t t0err)"); return ; } //__________________________________________ -void BbcOut::set_Vertex( const Float_t, const Float_t ) +void BbcOut::set_Vertex( const float, const Float_t ) { - virtual_warning("set_Vertex(const Float_t vtx, const Float_t vtxerr)"); + virtual_warning("set_Vertex(const float vtx, const Float_t vtxerr)"); return ; } //__________________________________________ -void BbcOut::set_dZVertex(const Float_t ) +void BbcOut::set_dZVertex(const float ) { - virtual_warning("set_dZVertex(const Float_t vtxerr)"); + virtual_warning("set_dZVertex(const float vtxerr)"); return ; } //________________________________________________________________ -void BbcOut::AddBbcNS(const int /*nBbc*/, const Short_t /*npmt*/, const Float_t /*energy*/, const Float_t /*timing*/) +void BbcOut::AddBbcNS(const int /*nBbc*/, const Short_t /*npmt*/, const float /*energy*/, const Float_t /*timing*/) { - virtual_warning("AddBbcNS(const int iBBC, const Short_t npmt, const Float_t energy, const Float_t timing)"); + virtual_warning("AddBbcNS(const int iBBC, const Short_t npmt, const float energy, const Float_t timing)"); return ; } @@ -81,13 +81,13 @@ Short_t BbcOut::get_nPMT(const int /*nBbc*/) const return BbcReturnCodes::BBC_INVALID_SHORT; } -Float_t BbcOut::get_nCharge(const int /*nBbc*/) const +float BbcOut::get_nCharge(const int /*nBbc*/) const { virtual_warning("get_nCharge(const int nBbc)"); return NAN; } -Float_t BbcOut::get_Timing(const int /*nBbc*/) const +float BbcOut::get_Timing(const int /*nBbc*/) const { virtual_warning("get_Timing(const int nBbc)"); return NAN; diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index 133883e058..a26bb1c2ce 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -26,16 +26,16 @@ class BbcOut: public PHObject int isValid() const override; /// get ZVertex determined by Bbc - virtual Float_t get_VertexPoint() const; + virtual float get_VertexPoint() const; /// get Error on ZVertex determined by Bbc - virtual Float_t get_dVertexPoint() const; + virtual float get_dVertexPoint() const; /// get T0 determined by Bbc - virtual Float_t get_TimeZero() const; + virtual float get_TimeZero() const; /// get Error on T0 determined by Bbc - virtual Float_t get_dTimeZero() const; + virtual float get_dTimeZero() const; /** set T0, Error on T0, ZVertex and Error on ZVertex @param t0 Bbc T0 @@ -43,7 +43,7 @@ class BbcOut: public PHObject @param vtx Bbc ZVertex @param vtxerr Bbc Error on ZVertex */ - virtual void set_TimeVertex(const Float_t t0, const Float_t t0err, const Float_t vtx, const Float_t vtxerr) + virtual void set_TimeVertex(const float t0, const Float_t t0err, const Float_t vtx, const Float_t vtxerr) { set_TimeZero( t0, t0err ); set_Vertex( vtx, vtxerr ); @@ -53,15 +53,15 @@ class BbcOut: public PHObject @param t0 Bbc T0 @param t0err Bbc T0 error */ - virtual void set_TimeZero(const Float_t t0, const Float_t t0err = 0); + virtual void set_TimeZero(const float t0, const Float_t t0err = 0); //! set vertex - virtual void set_Vertex( const Float_t vtx, const Float_t vtxerr); + virtual void set_Vertex( const float vtx, const Float_t vtxerr); /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error */ - virtual void set_dZVertex(const Float_t vtxerr); + virtual void set_dZVertex(const float vtxerr); /** Add Bbc North/South object containing Number of pmt's, Energy and Timing @param npmt Number of PMT's fired @@ -69,7 +69,7 @@ class BbcOut: public PHObject @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual void AddBbcNS(const int iBBC, const Short_t npmt, const Float_t ncharge, const Float_t timing); + virtual void AddBbcNS(const int iBBC, const Short_t npmt, const float ncharge, const Float_t timing); /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South @@ -79,12 +79,12 @@ class BbcOut: public PHObject /** get Number of Charged Particles into North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Float_t get_nCharge(const int iBBC) const; + virtual float get_nCharge(const int iBBC) const; /** get Timing of North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Float_t get_Timing(const int iBBC) const; + virtual float get_Timing(const int iBBC) const; virtual void FillFromClass(const BbcOut& old); diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index 1cf6b6ebcf..fd6619f638 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -55,27 +55,27 @@ void BbcOutV1::identify(std::ostream& out) const } //______________________________________ -void BbcOutV1::set_TimeZero(const Float_t t0, const Float_t t0err ) +void BbcOutV1::set_TimeZero(const float t0, const Float_t t0err ) { Bbc_TimeZero = t0; Bbc_dTimeZero = t0err; } //______________________________________ -void BbcOutV1::set_Vertex( const Float_t vtx, const Float_t vtxerr) +void BbcOutV1::set_Vertex( const float vtx, const Float_t vtxerr) { Bbc_ZVertex = vtx; Bbc_dZVertex = vtxerr; } //______________________________________ -void BbcOutV1::set_dZVertex( const Float_t vtxerr) +void BbcOutV1::set_dZVertex( const float vtxerr) { Bbc_dZVertex = vtxerr; } //______________________________________ -void BbcOutV1::AddBbcNS(const int iBBC, const Short_t npmt, const Float_t energy, const Float_t timing) +void BbcOutV1::AddBbcNS(const int iBBC, const Short_t npmt, const float energy, const Float_t timing) { TClonesArray &bbcns = *BbcNS; new(bbcns[iBBC]) BbcNorthSouthV1(npmt, energy,timing); @@ -90,14 +90,14 @@ Short_t BbcOutV1::get_nPMT(const int nBbc) const } //______________________________________ -Float_t BbcOutV1::get_nCharge(const int nBbc) const +float BbcOutV1::get_nCharge(const int nBbc) const { BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Energy return((bbcns) ? bbcns->get_nCharge() : BbcReturnCodes::BBC_INVALID_FLOAT); } -Float_t BbcOutV1::get_Timing(const int nBbc) const +float BbcOutV1::get_Timing(const int nBbc) const { BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Timing diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index cb5685f7b8..fa52bbf93d 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -29,30 +29,30 @@ class BbcOutV1: public BbcOut int isValid() const override; /// get ZVertex determined by Bbc - Float_t get_VertexPoint() const override {return Bbc_ZVertex;} + float get_VertexPoint() const override {return Bbc_ZVertex;} /// get Error on ZVertex determined by Bbc - Float_t get_dVertexPoint() const override {return Bbc_dZVertex;} + float get_dVertexPoint() const override {return Bbc_dZVertex;} /// get T0 determined by Bbc - Float_t get_TimeZero() const override {return Bbc_TimeZero;} + float get_TimeZero() const override {return Bbc_TimeZero;} /// get Error on T0 determined by Bbc - Float_t get_dTimeZero() const override {return Bbc_dTimeZero;} + float get_dTimeZero() const override {return Bbc_dTimeZero;} /** set T0 for Bbc @param t0 Bbc T0 @param t0err Bbc T0 error */ - void set_TimeZero(const Float_t t0, const Float_t t0err = 0) override; + void set_TimeZero(const float t0, const Float_t t0err = 0) override; //! set vertex - void set_Vertex( const Float_t vtx, const Float_t vtxerr = 0) override; + void set_Vertex( const float vtx, const Float_t vtxerr = 0) override; /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error */ - void set_dZVertex(const Float_t vtxerr) override; + void set_dZVertex(const float vtxerr) override; /** Add Bbc North/South object containing Number of pmt's, Energy and Timing @param npmt Number of PMT's fired @@ -60,7 +60,7 @@ class BbcOutV1: public BbcOut @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - void AddBbcNS(const int nBbc, const Short_t npmt, const Float_t chargesum, const Float_t timing) override; + void AddBbcNS(const int nBbc, const Short_t npmt, const float chargesum, const Float_t timing) override; /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South @@ -71,12 +71,12 @@ class BbcOutV1: public BbcOut /** get Number of Charged Particles into North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - Float_t get_nCharge(const int nBbc) const override; + float get_nCharge(const int nBbc) const override; /** get Timing of North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - Float_t get_Timing(const int nBbc) const override; + float get_Timing(const int nBbc) const override; virtual void Init(); @@ -85,10 +85,10 @@ class BbcOutV1: public BbcOut TClonesArray *GetBbcNS() const { return BbcNS; } - Float_t Bbc_ZVertex; - Float_t Bbc_dZVertex; - Float_t Bbc_TimeZero; - Float_t Bbc_dTimeZero; + float Bbc_ZVertex; + float Bbc_dZVertex; + float Bbc_TimeZero; + float Bbc_dTimeZero; TClonesArray *BbcNS; ClassDefOverride(BbcOutV1,1) diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index ad451cceeb..35f85d56dc 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -41,27 +41,27 @@ Short_t BbcPmtContainer::get_pmt(const int /*iPmt*/) const return BbcReturnCodes::BBC_INVALID_SHORT; } -Float_t BbcPmtContainer::get_adc(const int /*iPmt*/) const +float BbcPmtContainer::get_adc(const int /*iPmt*/) const { virtual_warning("get_Adc(const short iPmt)"); return BbcReturnCodes::BBC_INVALID_FLOAT; } -Float_t BbcPmtContainer::get_tdc0(const int /*iPmt*/) const +float BbcPmtContainer::get_tdc0(const int /*iPmt*/) const { virtual_warning("get_Tdc0(const short iPmt)"); return BbcReturnCodes::BBC_INVALID_FLOAT; } -Float_t BbcPmtContainer::get_tdc1(const int /*iPmt*/) const +float BbcPmtContainer::get_tdc1(const int /*iPmt*/) const { virtual_warning("get_Tdc1(const short iPmt)"); return BbcReturnCodes::BBC_INVALID_FLOAT; } -void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const Float_t /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) +void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) { - virtual_warning("AddBbcPmtHit(const Short_t ipmt, const Short_t adc, const Float_t tdc0, const Float_t tdc1)"); + virtual_warning("AddBbcPmtHit(const Short_t ipmt, const Short_t adc, const float tdc0, const Float_t tdc1)"); return ; } diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index 922d358a4a..96895b2930 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -44,17 +44,17 @@ class BbcPmtContainer : public PHObject /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - virtual Float_t get_adc(const int iPmt) const; + virtual float get_adc(const int iPmt) const; /** get Tdc0 of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - virtual Float_t get_tdc0(const int iPmt) const; + virtual float get_tdc0(const int iPmt) const; /** get Tdc1 of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - virtual Float_t get_tdc1(const int iPmt) const; + virtual float get_tdc1(const int iPmt) const; /** Add Bbc Raw hit object to TCLonesArray @param ipmt Pmt id @@ -62,7 +62,7 @@ class BbcPmtContainer : public PHObject @param tdc0 Tdc0 value @param tdc1 Tdc1 value */ - virtual void AddBbcPmt(const Short_t ipmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1); + virtual void AddBbcPmt(const Short_t ipmt, const float adc, const Float_t tdc0, const Float_t tdc1); private: void virtual_warning(const std::string &funcname) const; diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index 215f891f56..34085aa2c4 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -35,7 +35,7 @@ void BbcPmtContainerV1::Reset() npmt = 0; } -void BbcPmtContainerV1::AddBbcPmt(const Short_t pmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1) +void BbcPmtContainerV1::AddBbcPmt(const Short_t pmt, const float adc, const Float_t tdc0, const Float_t tdc1) { TClonesArray &Bbchits = *BbcPmtHits; new(Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); @@ -47,19 +47,19 @@ Short_t BbcPmtContainerV1::get_pmt(const int iPmt) const return ((Bbchit) ? Bbchit->get_pmt() : BbcReturnCodes::BBC_INVALID_SHORT); } -Float_t BbcPmtContainerV1::get_adc(const int iPmt) const +float BbcPmtContainerV1::get_adc(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_FLOAT); } -Float_t BbcPmtContainerV1::get_tdc0(const int iPmt) const +float BbcPmtContainerV1::get_tdc0(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_FLOAT); } -Float_t BbcPmtContainerV1::get_tdc1(const int iPmt) const +float BbcPmtContainerV1::get_tdc1(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_FLOAT); diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index bd7ce5d401..06c7730e3b 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -45,17 +45,17 @@ class BbcPmtContainerV1 : public BbcPmtContainer /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - Float_t get_adc(const int iPmt) const override; + float get_adc(const int iPmt) const override; /** get Tdc0 of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - Float_t get_tdc0(const int iPmt) const override; + float get_tdc0(const int iPmt) const override; /** get Tdc1 of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - Float_t get_tdc1(const int iPmt) const override; + float get_tdc1(const int iPmt) const override; /** Add Bbc Raw hit object to TCLonesArray @param pmt Pmt id @@ -64,7 +64,7 @@ class BbcPmtContainerV1 : public BbcPmtContainer @param tdc1 Tdc1 value @param ipmt no of pmt */ - void AddBbcPmt(const Short_t ipmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1) override; + void AddBbcPmt(const Short_t ipmt, const float adc, const Float_t tdc0, const Float_t tdc1) override; private: TClonesArray *GetBbcPmtHits() const {return BbcPmtHits;} diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 8959097c1a..8dd847a476 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -14,13 +14,13 @@ class BbcPmtHit : public PHObject public: BbcPmtHit() {} - BbcPmtHit(const Short_t /*pmt*/, const Float_t /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) {} + BbcPmtHit(const Short_t /*pmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) {} virtual ~BbcPmtHit() { } virtual Short_t get_pmt() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual Float_t get_adc() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual Float_t get_tdc0() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual Float_t get_tdc1() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual float get_adc() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual float get_tdc0() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual float get_tdc1() const { PHOOL_VIRTUAL_WARNING; return -9999; } void identify(std::ostream& os = std::cout) const override; diff --git a/offline/packages/bbc/BbcPmtHitV1.cc b/offline/packages/bbc/BbcPmtHitV1.cc index 924ce78273..d68522a788 100644 --- a/offline/packages/bbc/BbcPmtHitV1.cc +++ b/offline/packages/bbc/BbcPmtHitV1.cc @@ -2,7 +2,7 @@ #include -BbcPmtHitV1::BbcPmtHitV1(const Short_t ipmt, const Float_t iadc, const Float_t itdc0, const Float_t itdc1) : +BbcPmtHitV1::BbcPmtHitV1(const Short_t ipmt, const float iadc, const Float_t itdc0, const Float_t itdc1) : pmt(ipmt), adc(iadc), tdc0(itdc0), diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 84527cfb14..c29e4a765b 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -12,21 +12,21 @@ class BbcPmtHitV1 : public BbcPmtHit public: BbcPmtHitV1() { } - BbcPmtHitV1(const Short_t pmt, const Float_t adc, const Float_t tdc0, const Float_t tdc1); + BbcPmtHitV1(const Short_t pmt, const float adc, const Float_t tdc0, const Float_t tdc1); ~BbcPmtHitV1() override = default; Short_t get_pmt() const override {return pmt;} - Float_t get_adc() const override {return adc;} - Float_t get_tdc0() const override {return tdc0;} - Float_t get_tdc1() const override {return tdc1;} + float get_adc() const override {return adc;} + float get_tdc0() const override {return tdc0;} + float get_tdc1() const override {return tdc1;} void identify(std::ostream& os = std::cout) const override; private: Short_t pmt; - Float_t adc; - Float_t tdc0; - Float_t tdc1; + float adc; + float tdc0; + float tdc1; ClassDefOverride(BbcPmtHitV1,1) }; From dc4434c80b376bed53a8ee47aa3e1f98e32c5338 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 19:55:41 -0400 Subject: [PATCH 086/468] replace Short_t by short --- offline/packages/bbc/BbcNorthSouth.h | 2 +- offline/packages/bbc/BbcNorthSouthV1.cc | 2 +- offline/packages/bbc/BbcNorthSouthV1.h | 6 +++--- offline/packages/bbc/BbcOut.cc | 6 +++--- offline/packages/bbc/BbcOut.h | 4 ++-- offline/packages/bbc/BbcOutV1.cc | 4 ++-- offline/packages/bbc/BbcOutV1.h | 4 ++-- offline/packages/bbc/BbcPmtContainer.cc | 8 ++++---- offline/packages/bbc/BbcPmtContainer.h | 8 ++++---- offline/packages/bbc/BbcPmtContainerV1.cc | 4 ++-- offline/packages/bbc/BbcPmtContainerV1.h | 10 +++++----- offline/packages/bbc/BbcPmtHit.h | 4 ++-- offline/packages/bbc/BbcPmtHitV1.cc | 2 +- offline/packages/bbc/BbcPmtHitV1.h | 6 +++--- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index 1d9a51fb54..d233173be1 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -15,7 +15,7 @@ class BbcNorthSouth : public PHObject ~BbcNorthSouth() override = default; virtual void identify(std::ostream& os = std::cout) const override; - virtual Short_t get_nPMT() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual short get_nPMT() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual float get_nCharge() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual float get_MeanTime() const { PHOOL_VIRTUAL_WARNING; return -9999; } diff --git a/offline/packages/bbc/BbcNorthSouthV1.cc b/offline/packages/bbc/BbcNorthSouthV1.cc index 9aeca95acc..cf7d78a860 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.cc +++ b/offline/packages/bbc/BbcNorthSouthV1.cc @@ -1,6 +1,6 @@ #include "BbcNorthSouthV1.h" -BbcNorthSouthV1::BbcNorthSouthV1(const Short_t npmt, const float ncharge, const Float_t meantime) +BbcNorthSouthV1::BbcNorthSouthV1(const short npmt, const float ncharge, const Float_t meantime) : nPmt(npmt) , nCharge(ncharge) , MeanTime(meantime) diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 68a53e1aa0..28eac65e1d 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -10,18 +10,18 @@ class BbcNorthSouthV1 : public BbcNorthSouth { public: BbcNorthSouthV1() { } - BbcNorthSouthV1(const Short_t npmt, const float chargesum, const Float_t timing); + BbcNorthSouthV1(const short npmt, const float chargesum, const Float_t timing); virtual ~BbcNorthSouthV1() { } void identify(std::ostream& os = std::cout) const override; - Short_t get_nPMT() const override { return nPmt; } + short get_nPMT() const override { return nPmt; } float get_nCharge() const override { return nCharge; } float get_MeanTime() const override { return MeanTime; } protected: virtual void Clear(Option_t * /*option*/ = "") override { } - Short_t nPmt; + short nPmt; float nCharge; float MeanTime; diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index 0c6076a0f1..43e29ccffa 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -69,13 +69,13 @@ void BbcOut::set_dZVertex(const float ) } //________________________________________________________________ -void BbcOut::AddBbcNS(const int /*nBbc*/, const Short_t /*npmt*/, const float /*energy*/, const Float_t /*timing*/) +void BbcOut::AddBbcNS(const int /*nBbc*/, const short /*npmt*/, const float /*energy*/, const Float_t /*timing*/) { - virtual_warning("AddBbcNS(const int iBBC, const Short_t npmt, const float energy, const Float_t timing)"); + virtual_warning("AddBbcNS(const int iBBC, const short npmt, const float energy, const Float_t timing)"); return ; } -Short_t BbcOut::get_nPMT(const int /*nBbc*/) const +short BbcOut::get_nPMT(const int /*nBbc*/) const { virtual_warning("get_nPMT(const int nBbc)"); return BbcReturnCodes::BBC_INVALID_SHORT; diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index a26bb1c2ce..b05bb655a1 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -69,12 +69,12 @@ class BbcOut: public PHObject @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual void AddBbcNS(const int iBBC, const Short_t npmt, const float ncharge, const Float_t timing); + virtual void AddBbcNS(const int iBBC, const short npmt, const float ncharge, const Float_t timing); /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual Short_t get_nPMT(const int iBBC) const; + virtual short get_nPMT(const int iBBC) const; /** get Number of Charged Particles into North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index fd6619f638..a4c4804366 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -75,14 +75,14 @@ void BbcOutV1::set_dZVertex( const float vtxerr) } //______________________________________ -void BbcOutV1::AddBbcNS(const int iBBC, const Short_t npmt, const float energy, const Float_t timing) +void BbcOutV1::AddBbcNS(const int iBBC, const short npmt, const float energy, const Float_t timing) { TClonesArray &bbcns = *BbcNS; new(bbcns[iBBC]) BbcNorthSouthV1(npmt, energy,timing); } //______________________________________ -Short_t BbcOutV1::get_nPMT(const int nBbc) const +short BbcOutV1::get_nPMT(const int nBbc) const { BbcNorthSouthV1 *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_SHORT, else nPMT diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index fa52bbf93d..377a2be3b4 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -60,12 +60,12 @@ class BbcOutV1: public BbcOut @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - void AddBbcNS(const int nBbc, const Short_t npmt, const float chargesum, const Float_t timing) override; + void AddBbcNS(const int nBbc, const short npmt, const float chargesum, const Float_t timing) override; /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ - Short_t get_nPMT(const int nBbc) const override; + short get_nPMT(const int nBbc) const override; /** get Number of Charged Particles into North/South Bbc diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index 35f85d56dc..05c1ada0f3 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -23,7 +23,7 @@ int BbcPmtContainer::isValid() const return 0; } -void BbcPmtContainer::set_npmt(const Short_t /*ival*/) +void BbcPmtContainer::set_npmt(const short /*ival*/) { virtual_warning("set_npmt(const short ival)"); return ; @@ -35,7 +35,7 @@ short BbcPmtContainer::get_npmt() const return BbcReturnCodes::BBC_INVALID_SHORT; } -Short_t BbcPmtContainer::get_pmt(const int /*iPmt*/) const +short BbcPmtContainer::get_pmt(const int /*iPmt*/) const { virtual_warning("get_pmt(const short iPmt)"); return BbcReturnCodes::BBC_INVALID_SHORT; @@ -59,9 +59,9 @@ float BbcPmtContainer::get_tdc1(const int /*iPmt*/) const return BbcReturnCodes::BBC_INVALID_FLOAT; } -void BbcPmtContainer::AddBbcPmt(const Short_t /*ipmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) +void BbcPmtContainer::AddBbcPmt(const short /*ipmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) { - virtual_warning("AddBbcPmtHit(const Short_t ipmt, const Short_t adc, const float tdc0, const Float_t tdc1)"); + virtual_warning("AddBbcPmtHit(const short ipmt, const Short_t adc, const float tdc0, const Float_t tdc1)"); return ; } diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index 96895b2930..f0b7b3dd51 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -31,15 +31,15 @@ class BbcPmtContainer : public PHObject /** set number of PMTs for Bbc @param ival Number of Bbc Pmt's */ - virtual void set_npmt(const Short_t ival); + virtual void set_npmt(const short ival); /// get Number of Bbc Pmt's - virtual Short_t get_npmt() const; + virtual short get_npmt() const; /** get id of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - virtual Short_t get_pmt(const int iPmt) const; + virtual short get_pmt(const int iPmt) const; /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray @@ -62,7 +62,7 @@ class BbcPmtContainer : public PHObject @param tdc0 Tdc0 value @param tdc1 Tdc1 value */ - virtual void AddBbcPmt(const Short_t ipmt, const float adc, const Float_t tdc0, const Float_t tdc1); + virtual void AddBbcPmt(const short ipmt, const float adc, const Float_t tdc0, const Float_t tdc1); private: void virtual_warning(const std::string &funcname) const; diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index 34085aa2c4..1407e038ba 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -35,13 +35,13 @@ void BbcPmtContainerV1::Reset() npmt = 0; } -void BbcPmtContainerV1::AddBbcPmt(const Short_t pmt, const float adc, const Float_t tdc0, const Float_t tdc1) +void BbcPmtContainerV1::AddBbcPmt(const short pmt, const float adc, const Float_t tdc0, const Float_t tdc1) { TClonesArray &Bbchits = *BbcPmtHits; new(Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); } -Short_t BbcPmtContainerV1::get_pmt(const int iPmt) const +short BbcPmtContainerV1::get_pmt(const int iPmt) const { BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_pmt() : BbcReturnCodes::BBC_INVALID_SHORT); diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index 06c7730e3b..9e9b840ff6 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -32,15 +32,15 @@ class BbcPmtContainerV1 : public BbcPmtContainer /** set T0 for Bbc @param ival Number of Bbc Pmt's */ - void set_npmt(const Short_t ival) override {npmt=ival;return;} + void set_npmt(const short ival) override {npmt=ival;return;} /// get Number of Bbc Pmt's - Short_t get_npmt() const override {return npmt;} + short get_npmt() const override {return npmt;} /** get id of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray */ - Short_t get_pmt(const int iPmt) const override; + short get_pmt(const int iPmt) const override; /** get Adc of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray @@ -64,12 +64,12 @@ class BbcPmtContainerV1 : public BbcPmtContainer @param tdc1 Tdc1 value @param ipmt no of pmt */ - void AddBbcPmt(const Short_t ipmt, const float adc, const Float_t tdc0, const Float_t tdc1) override; + void AddBbcPmt(const short ipmt, const float adc, const Float_t tdc0, const Float_t tdc1) override; private: TClonesArray *GetBbcPmtHits() const {return BbcPmtHits;} - Short_t npmt = 0; + short npmt = 0; TClonesArray *BbcPmtHits = nullptr; diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 8dd847a476..9a5311b317 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -14,10 +14,10 @@ class BbcPmtHit : public PHObject public: BbcPmtHit() {} - BbcPmtHit(const Short_t /*pmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) {} + BbcPmtHit(const short /*pmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) {} virtual ~BbcPmtHit() { } - virtual Short_t get_pmt() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual short get_pmt() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual float get_adc() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual float get_tdc0() const { PHOOL_VIRTUAL_WARNING; return -9999; } virtual float get_tdc1() const { PHOOL_VIRTUAL_WARNING; return -9999; } diff --git a/offline/packages/bbc/BbcPmtHitV1.cc b/offline/packages/bbc/BbcPmtHitV1.cc index d68522a788..4ab7633e33 100644 --- a/offline/packages/bbc/BbcPmtHitV1.cc +++ b/offline/packages/bbc/BbcPmtHitV1.cc @@ -2,7 +2,7 @@ #include -BbcPmtHitV1::BbcPmtHitV1(const Short_t ipmt, const float iadc, const Float_t itdc0, const Float_t itdc1) : +BbcPmtHitV1::BbcPmtHitV1(const short ipmt, const float iadc, const Float_t itdc0, const Float_t itdc1) : pmt(ipmt), adc(iadc), tdc0(itdc0), diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index c29e4a765b..d1c00b5225 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -12,10 +12,10 @@ class BbcPmtHitV1 : public BbcPmtHit public: BbcPmtHitV1() { } - BbcPmtHitV1(const Short_t pmt, const float adc, const Float_t tdc0, const Float_t tdc1); + BbcPmtHitV1(const short pmt, const float adc, const Float_t tdc0, const Float_t tdc1); ~BbcPmtHitV1() override = default; - Short_t get_pmt() const override {return pmt;} + short get_pmt() const override {return pmt;} float get_adc() const override {return adc;} float get_tdc0() const override {return tdc0;} float get_tdc1() const override {return tdc1;} @@ -23,7 +23,7 @@ class BbcPmtHitV1 : public BbcPmtHit void identify(std::ostream& os = std::cout) const override; private: - Short_t pmt; + short pmt; float adc; float tdc0; float tdc1; From d7433e37e575bad2950e1900cb4b0144b0520f86 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 19:58:31 -0400 Subject: [PATCH 087/468] replace Short_t by short, Float_t by float --- offline/packages/bbc/BbcNorthSouthV1.cc | 2 +- offline/packages/bbc/BbcNorthSouthV1.h | 2 +- offline/packages/bbc/BbcOut.cc | 12 ++++++------ offline/packages/bbc/BbcOut.h | 8 ++++---- offline/packages/bbc/BbcOutV1.cc | 6 +++--- offline/packages/bbc/BbcOutV1.h | 6 +++--- offline/packages/bbc/BbcPmtContainer.cc | 4 ++-- offline/packages/bbc/BbcPmtContainer.h | 2 +- offline/packages/bbc/BbcPmtContainerV1.cc | 2 +- offline/packages/bbc/BbcPmtContainerV1.h | 2 +- offline/packages/bbc/BbcPmtHit.h | 2 +- offline/packages/bbc/BbcPmtHitV1.cc | 2 +- offline/packages/bbc/BbcPmtHitV1.h | 2 +- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouthV1.cc b/offline/packages/bbc/BbcNorthSouthV1.cc index cf7d78a860..b8831d6648 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.cc +++ b/offline/packages/bbc/BbcNorthSouthV1.cc @@ -1,6 +1,6 @@ #include "BbcNorthSouthV1.h" -BbcNorthSouthV1::BbcNorthSouthV1(const short npmt, const float ncharge, const Float_t meantime) +BbcNorthSouthV1::BbcNorthSouthV1(const short npmt, const float ncharge, const float meantime) : nPmt(npmt) , nCharge(ncharge) , MeanTime(meantime) diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 28eac65e1d..e82764b593 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -10,7 +10,7 @@ class BbcNorthSouthV1 : public BbcNorthSouth { public: BbcNorthSouthV1() { } - BbcNorthSouthV1(const short npmt, const float chargesum, const Float_t timing); + BbcNorthSouthV1(const short npmt, const float chargesum, const float timing); virtual ~BbcNorthSouthV1() { } void identify(std::ostream& os = std::cout) const override; diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index 43e29ccffa..5c2a69b95a 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -48,16 +48,16 @@ float BbcOut::get_dTimeZero() const } //__________________________________________ -void BbcOut::set_TimeZero(const float, const Float_t) +void BbcOut::set_TimeZero(const float, const float) { - virtual_warning("set_TimeZero(const float t0, const Float_t t0err)"); + virtual_warning("set_TimeZero(const float t0, const float t0err)"); return ; } //__________________________________________ -void BbcOut::set_Vertex( const float, const Float_t ) +void BbcOut::set_Vertex( const float, const float ) { - virtual_warning("set_Vertex(const float vtx, const Float_t vtxerr)"); + virtual_warning("set_Vertex(const float vtx, const float vtxerr)"); return ; } @@ -69,9 +69,9 @@ void BbcOut::set_dZVertex(const float ) } //________________________________________________________________ -void BbcOut::AddBbcNS(const int /*nBbc*/, const short /*npmt*/, const float /*energy*/, const Float_t /*timing*/) +void BbcOut::AddBbcNS(const int /*nBbc*/, const short /*npmt*/, const float /*energy*/, const float /*timing*/) { - virtual_warning("AddBbcNS(const int iBBC, const short npmt, const float energy, const Float_t timing)"); + virtual_warning("AddBbcNS(const int iBBC, const short npmt, const float energy, const float timing)"); return ; } diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index b05bb655a1..fc22580912 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -43,7 +43,7 @@ class BbcOut: public PHObject @param vtx Bbc ZVertex @param vtxerr Bbc Error on ZVertex */ - virtual void set_TimeVertex(const float t0, const Float_t t0err, const Float_t vtx, const Float_t vtxerr) + virtual void set_TimeVertex(const float t0, const float t0err, const float vtx, const float vtxerr) { set_TimeZero( t0, t0err ); set_Vertex( vtx, vtxerr ); @@ -53,10 +53,10 @@ class BbcOut: public PHObject @param t0 Bbc T0 @param t0err Bbc T0 error */ - virtual void set_TimeZero(const float t0, const Float_t t0err = 0); + virtual void set_TimeZero(const float t0, const float t0err = 0); //! set vertex - virtual void set_Vertex( const float vtx, const Float_t vtxerr); + virtual void set_Vertex( const float vtx, const float vtxerr); /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error @@ -69,7 +69,7 @@ class BbcOut: public PHObject @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - virtual void AddBbcNS(const int iBBC, const short npmt, const float ncharge, const Float_t timing); + virtual void AddBbcNS(const int iBBC, const short npmt, const float ncharge, const float timing); /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index a4c4804366..5229d21b55 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -55,14 +55,14 @@ void BbcOutV1::identify(std::ostream& out) const } //______________________________________ -void BbcOutV1::set_TimeZero(const float t0, const Float_t t0err ) +void BbcOutV1::set_TimeZero(const float t0, const float t0err ) { Bbc_TimeZero = t0; Bbc_dTimeZero = t0err; } //______________________________________ -void BbcOutV1::set_Vertex( const float vtx, const Float_t vtxerr) +void BbcOutV1::set_Vertex( const float vtx, const float vtxerr) { Bbc_ZVertex = vtx; Bbc_dZVertex = vtxerr; @@ -75,7 +75,7 @@ void BbcOutV1::set_dZVertex( const float vtxerr) } //______________________________________ -void BbcOutV1::AddBbcNS(const int iBBC, const short npmt, const float energy, const Float_t timing) +void BbcOutV1::AddBbcNS(const int iBBC, const short npmt, const float energy, const float timing) { TClonesArray &bbcns = *BbcNS; new(bbcns[iBBC]) BbcNorthSouthV1(npmt, energy,timing); diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index 377a2be3b4..ca7c9f38e3 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -44,10 +44,10 @@ class BbcOutV1: public BbcOut @param t0 Bbc T0 @param t0err Bbc T0 error */ - void set_TimeZero(const float t0, const Float_t t0err = 0) override; + void set_TimeZero(const float t0, const float t0err = 0) override; //! set vertex - void set_Vertex( const float vtx, const Float_t vtxerr = 0) override; + void set_Vertex( const float vtx, const float vtxerr = 0) override; /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error @@ -60,7 +60,7 @@ class BbcOutV1: public BbcOut @param timing Timing of North/South @param nBbc Arm, use Bbc::North and Bbc::South */ - void AddBbcNS(const int nBbc, const short npmt, const float chargesum, const Float_t timing) override; + void AddBbcNS(const int nBbc, const short npmt, const float chargesum, const float timing) override; /** get Number of PMT's fired in North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index 05c1ada0f3..eaa42f8b0b 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -59,9 +59,9 @@ float BbcPmtContainer::get_tdc1(const int /*iPmt*/) const return BbcReturnCodes::BBC_INVALID_FLOAT; } -void BbcPmtContainer::AddBbcPmt(const short /*ipmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) +void BbcPmtContainer::AddBbcPmt(const short /*ipmt*/, const float /*adc*/, const float /*tdc0*/, const float /*tdc1*/) { - virtual_warning("AddBbcPmtHit(const short ipmt, const Short_t adc, const float tdc0, const Float_t tdc1)"); + virtual_warning("AddBbcPmtHit(const short ipmt, const short adc, const float tdc0, const float tdc1)"); return ; } diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index f0b7b3dd51..86f1c9b395 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -62,7 +62,7 @@ class BbcPmtContainer : public PHObject @param tdc0 Tdc0 value @param tdc1 Tdc1 value */ - virtual void AddBbcPmt(const short ipmt, const float adc, const Float_t tdc0, const Float_t tdc1); + virtual void AddBbcPmt(const short ipmt, const float adc, const float tdc0, const float tdc1); private: void virtual_warning(const std::string &funcname) const; diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index 1407e038ba..f3cf30b8ad 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -35,7 +35,7 @@ void BbcPmtContainerV1::Reset() npmt = 0; } -void BbcPmtContainerV1::AddBbcPmt(const short pmt, const float adc, const Float_t tdc0, const Float_t tdc1) +void BbcPmtContainerV1::AddBbcPmt(const short pmt, const float adc, const float tdc0, const float tdc1) { TClonesArray &Bbchits = *BbcPmtHits; new(Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index 9e9b840ff6..823ae877b4 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -64,7 +64,7 @@ class BbcPmtContainerV1 : public BbcPmtContainer @param tdc1 Tdc1 value @param ipmt no of pmt */ - void AddBbcPmt(const short ipmt, const float adc, const Float_t tdc0, const Float_t tdc1) override; + void AddBbcPmt(const short ipmt, const float adc, const float tdc0, const float tdc1) override; private: TClonesArray *GetBbcPmtHits() const {return BbcPmtHits;} diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 9a5311b317..cd9a1c9de8 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -14,7 +14,7 @@ class BbcPmtHit : public PHObject public: BbcPmtHit() {} - BbcPmtHit(const short /*pmt*/, const float /*adc*/, const Float_t /*tdc0*/, const Float_t /*tdc1*/) {} + BbcPmtHit(const short /*pmt*/, const float /*adc*/, const float /*tdc0*/, const float /*tdc1*/) {} virtual ~BbcPmtHit() { } virtual short get_pmt() const { PHOOL_VIRTUAL_WARNING; return -9999; } diff --git a/offline/packages/bbc/BbcPmtHitV1.cc b/offline/packages/bbc/BbcPmtHitV1.cc index 4ab7633e33..16cbaee3c6 100644 --- a/offline/packages/bbc/BbcPmtHitV1.cc +++ b/offline/packages/bbc/BbcPmtHitV1.cc @@ -2,7 +2,7 @@ #include -BbcPmtHitV1::BbcPmtHitV1(const short ipmt, const float iadc, const Float_t itdc0, const Float_t itdc1) : +BbcPmtHitV1::BbcPmtHitV1(const short ipmt, const float iadc, const float itdc0, const float itdc1) : pmt(ipmt), adc(iadc), tdc0(itdc0), diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index d1c00b5225..65140563b4 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -12,7 +12,7 @@ class BbcPmtHitV1 : public BbcPmtHit public: BbcPmtHitV1() { } - BbcPmtHitV1(const short pmt, const float adc, const Float_t tdc0, const Float_t tdc1); + BbcPmtHitV1(const short pmt, const float adc, const float tdc0, const float tdc1); ~BbcPmtHitV1() override = default; short get_pmt() const override {return pmt;} From 581ecbcc0c54ed21a69786102a2b4c626760624e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 20:08:19 -0400 Subject: [PATCH 088/468] clang-format --- offline/packages/bbc/BbcNorthSouth.cc | 1 - offline/packages/bbc/BbcNorthSouth.h | 31 ++++++++----- offline/packages/bbc/BbcNorthSouthLinkDef.h | 2 +- offline/packages/bbc/BbcNorthSouthV1.cc | 1 - offline/packages/bbc/BbcNorthSouthV1.h | 15 +++---- offline/packages/bbc/BbcNorthSouthV1LinkDef.h | 2 +- offline/packages/bbc/BbcOut.cc | 31 +++++++------ offline/packages/bbc/BbcOut.h | 33 +++++++------- offline/packages/bbc/BbcOutLinkDef.h | 2 +- offline/packages/bbc/BbcOutV1.cc | 45 +++++++++---------- offline/packages/bbc/BbcOutV1.h | 37 +++++++-------- offline/packages/bbc/BbcOutV1LinkDef.h | 2 +- offline/packages/bbc/BbcPmtContainer.cc | 13 +++--- offline/packages/bbc/BbcPmtContainer.h | 6 +-- offline/packages/bbc/BbcPmtContainerLinkDef.h | 2 +- offline/packages/bbc/BbcPmtContainerV1.cc | 18 ++++---- offline/packages/bbc/BbcPmtContainerV1.h | 26 +++++------ .../packages/bbc/BbcPmtContainerV1LinkDef.h | 2 +- offline/packages/bbc/BbcPmtHit.h | 36 ++++++++++----- offline/packages/bbc/BbcPmtHitLinkDef.h | 2 +- offline/packages/bbc/BbcPmtHitV1.cc | 11 +++-- offline/packages/bbc/BbcPmtHitV1.h | 17 ++++--- offline/packages/bbc/BbcPmtHitV1LinkDef.h | 2 +- offline/packages/bbc/BbcReturnCodes.h | 7 ++- 24 files changed, 176 insertions(+), 168 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.cc b/offline/packages/bbc/BbcNorthSouth.cc index e391f26084..102ca87a3c 100644 --- a/offline/packages/bbc/BbcNorthSouth.cc +++ b/offline/packages/bbc/BbcNorthSouth.cc @@ -4,4 +4,3 @@ void BbcNorthSouth::identify(std::ostream& out) const { out << "identify yourself: I am a BbcNorthSouth object" << std::endl; } - diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index d233173be1..a0b8a486ea 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -3,26 +3,35 @@ #ifndef BBC_BBCNORTHSOUTH_H #define BBC_BBCNORTHSOUTH_H -#include #include - +#include class BbcNorthSouth : public PHObject { -public: + public: BbcNorthSouth() = default; ~BbcNorthSouth() override = default; virtual void identify(std::ostream& os = std::cout) const override; - virtual short get_nPMT() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual float get_nCharge() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual float get_MeanTime() const { PHOOL_VIRTUAL_WARNING; return -9999; } - -private: - - ClassDefOverride(BbcNorthSouth,1) - + virtual short get_nPMT() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + virtual float get_nCharge() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + virtual float get_MeanTime() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + + private: + ClassDefOverride(BbcNorthSouth, 1) }; #endif diff --git a/offline/packages/bbc/BbcNorthSouthLinkDef.h b/offline/packages/bbc/BbcNorthSouthLinkDef.h index 6c1d5313a9..4201bdb864 100644 --- a/offline/packages/bbc/BbcNorthSouthLinkDef.h +++ b/offline/packages/bbc/BbcNorthSouthLinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcNorthSouth+; +#pragma link C++ class BbcNorthSouth + ; #endif diff --git a/offline/packages/bbc/BbcNorthSouthV1.cc b/offline/packages/bbc/BbcNorthSouthV1.cc index b8831d6648..0b1b933d9f 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.cc +++ b/offline/packages/bbc/BbcNorthSouthV1.cc @@ -7,7 +7,6 @@ BbcNorthSouthV1::BbcNorthSouthV1(const short npmt, const float ncharge, const fl { } - void BbcNorthSouthV1::identify(std::ostream& out) const { out << "identify yourself: I am a BbcNorthSouthV1 object" << std::endl; diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index e82764b593..e8ef959614 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -5,28 +5,27 @@ #include "BbcNorthSouth.h" - class BbcNorthSouthV1 : public BbcNorthSouth { -public: - BbcNorthSouthV1() { } + public: + BbcNorthSouthV1() {} BbcNorthSouthV1(const short npmt, const float chargesum, const float timing); - virtual ~BbcNorthSouthV1() { } + virtual ~BbcNorthSouthV1() {} void identify(std::ostream& os = std::cout) const override; short get_nPMT() const override { return nPmt; } float get_nCharge() const override { return nCharge; } float get_MeanTime() const override { return MeanTime; } -protected: - virtual void Clear(Option_t * /*option*/ = "") override { } + protected: + virtual void Clear(Option_t* /*option*/ = "") override {} short nPmt; float nCharge; float MeanTime; -private: - ClassDefOverride(BbcNorthSouth,1) + private: + ClassDefOverride(BbcNorthSouth, 1) }; #endif diff --git a/offline/packages/bbc/BbcNorthSouthV1LinkDef.h b/offline/packages/bbc/BbcNorthSouthV1LinkDef.h index 0a1f1bed31..2f53ca3dbd 100644 --- a/offline/packages/bbc/BbcNorthSouthV1LinkDef.h +++ b/offline/packages/bbc/BbcNorthSouthV1LinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcNorthSouthV1+; +#pragma link C++ class BbcNorthSouthV1 + ; #endif diff --git a/offline/packages/bbc/BbcOut.cc b/offline/packages/bbc/BbcOut.cc index 5c2a69b95a..0d69e446da 100644 --- a/offline/packages/bbc/BbcOut.cc +++ b/offline/packages/bbc/BbcOut.cc @@ -1,5 +1,5 @@ -#include "BbcReturnCodes.h" #include "BbcOut.h" +#include "BbcReturnCodes.h" #include #include @@ -7,13 +7,13 @@ void BbcOut::identify(std::ostream& os) const { os << "virtual BbcOut object" << std::endl; - return ; + return; } void BbcOut::Reset() { std::cout << "ERROR BbcOut: Reset() not implemented by daughter class" << std::endl; - return ; + return; } int BbcOut::isValid() const @@ -48,31 +48,31 @@ float BbcOut::get_dTimeZero() const } //__________________________________________ -void BbcOut::set_TimeZero(const float, const float) +void BbcOut::set_TimeZero(const float /*unused*/, const float /*unused*/) { virtual_warning("set_TimeZero(const float t0, const float t0err)"); - return ; + return; } //__________________________________________ -void BbcOut::set_Vertex( const float, const float ) +void BbcOut::set_Vertex(const float /*unused*/, const float /*unused*/) { virtual_warning("set_Vertex(const float vtx, const float vtxerr)"); - return ; + return; } //__________________________________________ -void BbcOut::set_dZVertex(const float ) +void BbcOut::set_dZVertex(const float /*unused*/) { virtual_warning("set_dZVertex(const float vtxerr)"); - return ; + return; } //________________________________________________________________ void BbcOut::AddBbcNS(const int /*nBbc*/, const short /*npmt*/, const float /*energy*/, const float /*timing*/) { virtual_warning("AddBbcNS(const int iBBC, const short npmt, const float energy, const float timing)"); - return ; + return; } short BbcOut::get_nPMT(const int /*nBbc*/) const @@ -93,19 +93,18 @@ float BbcOut::get_Timing(const int /*nBbc*/) const return NAN; } -void BbcOut::virtual_warning(const std::string &funcsname) const +void BbcOut::virtual_warning(const std::string& funcsname) const { std::cout << "BbcOut::" << funcsname << " is virtual, doing nothing" << std::endl; - return ; + return; } void BbcOut::FillFromClass(const BbcOut& old) { - for(int iarm = 0; iarm < 2; iarm++) + for (int iarm = 0; iarm < 2; iarm++) { - AddBbcNS( iarm, old.get_nPMT(iarm), old.get_nCharge(iarm), old.get_Timing(iarm) ); + AddBbcNS(iarm, old.get_nPMT(iarm), old.get_nCharge(iarm), old.get_Timing(iarm)); } - set_TimeVertex( old.get_TimeZero(), old.get_dTimeZero(), old.get_VertexPoint(), old.get_dVertexPoint() ); - + set_TimeVertex(old.get_TimeZero(), old.get_dTimeZero(), old.get_VertexPoint(), old.get_dVertexPoint()); } diff --git a/offline/packages/bbc/BbcOut.h b/offline/packages/bbc/BbcOut.h index fc22580912..9a68c0d709 100644 --- a/offline/packages/bbc/BbcOut.h +++ b/offline/packages/bbc/BbcOut.h @@ -8,16 +8,16 @@ #include /// -class BbcOut: public PHObject +class BbcOut : public PHObject { -public: + public: /// ~BbcOut() override {} - + /** identify Function from PHObject - @param os Output Stream + @param os Output Stream */ - void identify(std::ostream& os = std::cout) const override; + void identify(std::ostream& os = std::cout) const override; /// Clear Event void Reset() override; @@ -40,13 +40,13 @@ class BbcOut: public PHObject /** set T0, Error on T0, ZVertex and Error on ZVertex @param t0 Bbc T0 @param t0err Bbc Error on T0 - @param vtx Bbc ZVertex + @param vtx Bbc ZVertex @param vtxerr Bbc Error on ZVertex */ virtual void set_TimeVertex(const float t0, const float t0err, const float vtx, const float vtxerr) - { - set_TimeZero( t0, t0err ); - set_Vertex( vtx, vtxerr ); + { + set_TimeZero(t0, t0err); + set_Vertex(vtx, vtxerr); } /** set T0 for Bbc @@ -56,13 +56,13 @@ class BbcOut: public PHObject virtual void set_TimeZero(const float t0, const float t0err = 0); //! set vertex - virtual void set_Vertex( const float vtx, const float vtxerr); - + virtual void set_Vertex(const float vtx, const float vtxerr); + /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error */ virtual void set_dZVertex(const float vtxerr); - + /** Add Bbc North/South object containing Number of pmt's, Energy and Timing @param npmt Number of PMT's fired @param ncharge Number of Charged Particles into North/South @@ -87,12 +87,11 @@ class BbcOut: public PHObject virtual float get_Timing(const int iBBC) const; virtual void FillFromClass(const BbcOut& old); - -private: - void virtual_warning(const std::string &funcname) const; - ClassDefOverride(BbcOut,1) + private: + void virtual_warning(const std::string& funcname) const; + + ClassDefOverride(BbcOut, 1) }; #endif - diff --git a/offline/packages/bbc/BbcOutLinkDef.h b/offline/packages/bbc/BbcOutLinkDef.h index de1118c7b7..2fa23e8cab 100644 --- a/offline/packages/bbc/BbcOutLinkDef.h +++ b/offline/packages/bbc/BbcOutLinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcOut+; +#pragma link C++ class BbcOut + ; #endif diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index 5229d21b55..bce2187a64 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -1,6 +1,6 @@ -#include "BbcReturnCodes.h" #include "BbcOutV1.h" #include "BbcNorthSouthV1.h" +#include "BbcReturnCodes.h" #include @@ -12,28 +12,28 @@ static const int NBBC = 2; BbcOutV1::BbcOutV1() { Init(); - BbcNS = new TClonesArray("BbcNorthSouthV1",NBBC); + BbcNS = new TClonesArray("BbcNorthSouthV1", NBBC); } //______________________________________ void BbcOutV1::Init() { - Bbc_ZVertex = -99999.9; - Bbc_dZVertex = -99999.9; - Bbc_TimeZero = -99999.9; + Bbc_ZVertex = -99999.9; + Bbc_dZVertex = -99999.9; + Bbc_TimeZero = -99999.9; Bbc_dTimeZero = -99999.9; } //______________________________________ BbcOutV1::~BbcOutV1() -{ - delete BbcNS; +{ + delete BbcNS; } //______________________________________ int BbcOutV1::isValid() const { - return((Bbc_TimeZero >-9999.) ? 1 : 0); + return ((Bbc_TimeZero > -9999.) ? 1 : 0); } //______________________________________ @@ -47,7 +47,7 @@ void BbcOutV1::Reset() } //______________________________________ -void BbcOutV1::identify(std::ostream& out) const +void BbcOutV1::identify(std::ostream &out) const { out << "identify yourself: I am a BbcOutV1 object" << std::endl; out << "Vertex: " << Bbc_ZVertex << " Error: " << Bbc_dZVertex << std::endl; @@ -55,21 +55,21 @@ void BbcOutV1::identify(std::ostream& out) const } //______________________________________ -void BbcOutV1::set_TimeZero(const float t0, const float t0err ) +void BbcOutV1::set_TimeZero(const float t0, const float t0err) { - Bbc_TimeZero = t0; + Bbc_TimeZero = t0; Bbc_dTimeZero = t0err; } //______________________________________ -void BbcOutV1::set_Vertex( const float vtx, const float vtxerr) +void BbcOutV1::set_Vertex(const float vtx, const float vtxerr) { - Bbc_ZVertex = vtx; - Bbc_dZVertex = vtxerr; + Bbc_ZVertex = vtx; + Bbc_dZVertex = vtxerr; } //______________________________________ -void BbcOutV1::set_dZVertex( const float vtxerr) +void BbcOutV1::set_dZVertex(const float vtxerr) { Bbc_dZVertex = vtxerr; } @@ -78,29 +78,28 @@ void BbcOutV1::set_dZVertex( const float vtxerr) void BbcOutV1::AddBbcNS(const int iBBC, const short npmt, const float energy, const float timing) { TClonesArray &bbcns = *BbcNS; - new(bbcns[iBBC]) BbcNorthSouthV1(npmt, energy,timing); + new (bbcns[iBBC]) BbcNorthSouthV1(npmt, energy, timing); } //______________________________________ short BbcOutV1::get_nPMT(const int nBbc) const { - BbcNorthSouthV1 *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); + BbcNorthSouthV1 *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_SHORT, else nPMT - return((bbcns) ? bbcns->get_nPMT() : BbcReturnCodes::BBC_INVALID_SHORT); + return ((bbcns) ? bbcns->get_nPMT() : BbcReturnCodes::BBC_INVALID_SHORT); } //______________________________________ float BbcOutV1::get_nCharge(const int nBbc) const { - BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); + BbcNorthSouth *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Energy - return((bbcns) ? bbcns->get_nCharge() : BbcReturnCodes::BBC_INVALID_FLOAT); + return ((bbcns) ? bbcns->get_nCharge() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcOutV1::get_Timing(const int nBbc) const { - BbcNorthSouth *bbcns = (BbcNorthSouthV1*) GetBbcNS()->UncheckedAt(nBbc); + BbcNorthSouth *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Timing - return((bbcns) ? bbcns->get_MeanTime() : BbcReturnCodes::BBC_INVALID_FLOAT); + return ((bbcns) ? bbcns->get_MeanTime() : BbcReturnCodes::BBC_INVALID_FLOAT); } - diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index ca7c9f38e3..8c155437d6 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -8,10 +8,9 @@ class TClonesArray; /// -class BbcOutV1: public BbcOut +class BbcOutV1 : public BbcOut { -public: - + public: /// BbcOutV1(); /// @@ -21,24 +20,24 @@ class BbcOutV1: public BbcOut void Reset() override; /** identify Function from PHObject - @param os Output Stream + @param os Output Stream */ - void identify(std::ostream& os = std::cout) const override; + void identify(std::ostream &os = std::cout) const override; /// isValid returns non zero if object contains vailid data int isValid() const override; /// get ZVertex determined by Bbc - float get_VertexPoint() const override {return Bbc_ZVertex;} + float get_VertexPoint() const override { return Bbc_ZVertex; } /// get Error on ZVertex determined by Bbc - float get_dVertexPoint() const override {return Bbc_dZVertex;} + float get_dVertexPoint() const override { return Bbc_dZVertex; } /// get T0 determined by Bbc - float get_TimeZero() const override {return Bbc_TimeZero;} + float get_TimeZero() const override { return Bbc_TimeZero; } /// get Error on T0 determined by Bbc - float get_dTimeZero() const override {return Bbc_dTimeZero;} + float get_dTimeZero() const override { return Bbc_dTimeZero; } /** set T0 for Bbc @param t0 Bbc T0 @@ -47,8 +46,8 @@ class BbcOutV1: public BbcOut void set_TimeZero(const float t0, const float t0err = 0) override; //! set vertex - void set_Vertex( const float vtx, const float vtxerr = 0) override; - + void set_Vertex(const float vtx, const float vtxerr = 0) override; + /** set Vtx Error for Bbc @param vtxerr Bbc Vtx Error */ @@ -67,7 +66,6 @@ class BbcOutV1: public BbcOut */ short get_nPMT(const int nBbc) const override; - /** get Number of Charged Particles into North/South Bbc @param nBbc Arm, use Bbc::North and Bbc::South */ @@ -80,19 +78,16 @@ class BbcOutV1: public BbcOut virtual void Init(); -private: - - + private: TClonesArray *GetBbcNS() const { return BbcNS; } - float Bbc_ZVertex; - float Bbc_dZVertex; - float Bbc_TimeZero; - float Bbc_dTimeZero; + float Bbc_ZVertex{}; + float Bbc_dZVertex{}; + float Bbc_TimeZero{}; + float Bbc_dTimeZero{}; TClonesArray *BbcNS; - ClassDefOverride(BbcOutV1,1) - + ClassDefOverride(BbcOutV1, 1) }; #endif diff --git a/offline/packages/bbc/BbcOutV1LinkDef.h b/offline/packages/bbc/BbcOutV1LinkDef.h index 4c9fbe710b..d06f7dabab 100644 --- a/offline/packages/bbc/BbcOutV1LinkDef.h +++ b/offline/packages/bbc/BbcOutV1LinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcOutV1+; +#pragma link C++ class BbcOutV1 + ; #endif diff --git a/offline/packages/bbc/BbcPmtContainer.cc b/offline/packages/bbc/BbcPmtContainer.cc index eaa42f8b0b..163200103b 100644 --- a/offline/packages/bbc/BbcPmtContainer.cc +++ b/offline/packages/bbc/BbcPmtContainer.cc @@ -8,13 +8,13 @@ void BbcPmtContainer::identify(std::ostream& os) const { os << "virtual BbcPmtContainer object" << std::endl; - return ; + return; } void BbcPmtContainer::Reset() { std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; - return ; + return; } int BbcPmtContainer::isValid() const @@ -26,7 +26,7 @@ int BbcPmtContainer::isValid() const void BbcPmtContainer::set_npmt(const short /*ival*/) { virtual_warning("set_npmt(const short ival)"); - return ; + return; } short BbcPmtContainer::get_npmt() const @@ -62,12 +62,11 @@ float BbcPmtContainer::get_tdc1(const int /*iPmt*/) const void BbcPmtContainer::AddBbcPmt(const short /*ipmt*/, const float /*adc*/, const float /*tdc0*/, const float /*tdc1*/) { virtual_warning("AddBbcPmtHit(const short ipmt, const short adc, const float tdc0, const float tdc1)"); - return ; + return; } -void BbcPmtContainer::virtual_warning(const std::string &funcsname) const +void BbcPmtContainer::virtual_warning(const std::string& funcsname) const { std::cout << "BbcPmtContainer::" << funcsname << " is virtual, doing nothing" << std::endl; - return ; + return; } - diff --git a/offline/packages/bbc/BbcPmtContainer.h b/offline/packages/bbc/BbcPmtContainer.h index 86f1c9b395..b4e40b0434 100644 --- a/offline/packages/bbc/BbcPmtContainer.h +++ b/offline/packages/bbc/BbcPmtContainer.h @@ -18,7 +18,7 @@ class BbcPmtContainer : public PHObject virtual ~BbcPmtContainer() {} /** identify Function from PHObject - @param os Output Stream + @param os Output Stream */ virtual void identify(std::ostream& os = std::cout) const override; @@ -65,9 +65,9 @@ class BbcPmtContainer : public PHObject virtual void AddBbcPmt(const short ipmt, const float adc, const float tdc0, const float tdc1); private: - void virtual_warning(const std::string &funcname) const; + void virtual_warning(const std::string& funcname) const; - ClassDefOverride(BbcPmtContainer,1) + ClassDefOverride(BbcPmtContainer, 1) }; #endif diff --git a/offline/packages/bbc/BbcPmtContainerLinkDef.h b/offline/packages/bbc/BbcPmtContainerLinkDef.h index 14276d46a0..25ae7d422d 100644 --- a/offline/packages/bbc/BbcPmtContainerLinkDef.h +++ b/offline/packages/bbc/BbcPmtContainerLinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcPmtContainer+; +#pragma link C++ class BbcPmtContainer + ; #endif diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index f3cf30b8ad..622777c149 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -23,9 +23,9 @@ BbcPmtContainerV1::~BbcPmtContainerV1() int BbcPmtContainerV1::isValid() const { if (npmt <= 0) - { - return 0; - } + { + return 0; + } return 1; } @@ -38,34 +38,34 @@ void BbcPmtContainerV1::Reset() void BbcPmtContainerV1::AddBbcPmt(const short pmt, const float adc, const float tdc0, const float tdc1) { TClonesArray &Bbchits = *BbcPmtHits; - new(Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); + new (Bbchits[npmt++]) BbcPmtHitV1(pmt, adc, tdc0, tdc1); } short BbcPmtContainerV1::get_pmt(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_pmt() : BbcReturnCodes::BBC_INVALID_SHORT); } float BbcPmtContainerV1::get_adc(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcPmtContainerV1::get_tdc0(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcPmtContainerV1::get_tdc1(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit*) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_FLOAT); } -void BbcPmtContainerV1::identify(std::ostream& out) const +void BbcPmtContainerV1::identify(std::ostream &out) const { out << "identify yourself: I am a BbcPmtContainerV1 object" << std::endl; } diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index 823ae877b4..10c47200be 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -10,7 +10,7 @@ class TClonesArray; /// class BbcPmtContainerV1 : public BbcPmtContainer { -public: + public: /// ctor BbcPmtContainerV1(); @@ -21,21 +21,24 @@ class BbcPmtContainerV1 : public BbcPmtContainer void Reset() override; /** identify Function from PHObject - @param os Output Stream + @param os Output Stream */ - void identify(std::ostream& os = std::cout) const override; + void identify(std::ostream &os = std::cout) const override; /// isValid returns non zero if object contains vailid data int isValid() const override; - /** set T0 for Bbc @param ival Number of Bbc Pmt's */ - void set_npmt(const short ival) override {npmt=ival;return;} + void set_npmt(const short ival) override + { + npmt = ival; + return; + } /// get Number of Bbc Pmt's - short get_npmt() const override {return npmt;} + short get_npmt() const override { return npmt; } /** get id of Pmt iPmt in TClonesArray @param iPmt no of Pmt in TClonesArray @@ -64,18 +67,15 @@ class BbcPmtContainerV1 : public BbcPmtContainer @param tdc1 Tdc1 value @param ipmt no of pmt */ - void AddBbcPmt(const short ipmt, const float adc, const float tdc0, const float tdc1) override; + void AddBbcPmt(const short ipmt, const float adc, const float tdc0, const float tdc1) override; -private: - TClonesArray *GetBbcPmtHits() const {return BbcPmtHits;} + private: + TClonesArray *GetBbcPmtHits() const { return BbcPmtHits; } short npmt = 0; TClonesArray *BbcPmtHits = nullptr; - - ClassDefOverride(BbcPmtContainerV1,1) + ClassDefOverride(BbcPmtContainerV1, 1) }; #endif - - diff --git a/offline/packages/bbc/BbcPmtContainerV1LinkDef.h b/offline/packages/bbc/BbcPmtContainerV1LinkDef.h index 9a301f755b..37bc20a340 100644 --- a/offline/packages/bbc/BbcPmtContainerV1LinkDef.h +++ b/offline/packages/bbc/BbcPmtContainerV1LinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcPmtContainerV1+; +#pragma link C++ class BbcPmtContainerV1 + ; #endif diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index cd9a1c9de8..3e7d08672d 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -8,24 +8,38 @@ #include #include - class BbcPmtHit : public PHObject { -public: - + public: BbcPmtHit() {} BbcPmtHit(const short /*pmt*/, const float /*adc*/, const float /*tdc0*/, const float /*tdc1*/) {} - virtual ~BbcPmtHit() { } - - virtual short get_pmt() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual float get_adc() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual float get_tdc0() const { PHOOL_VIRTUAL_WARNING; return -9999; } - virtual float get_tdc1() const { PHOOL_VIRTUAL_WARNING; return -9999; } + virtual ~BbcPmtHit() {} + + virtual short get_pmt() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + virtual float get_adc() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + virtual float get_tdc0() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } + virtual float get_tdc1() const + { + PHOOL_VIRTUAL_WARNING; + return -9999; + } void identify(std::ostream& os = std::cout) const override; -private: - ClassDefOverride(BbcPmtHit,1) + private: + ClassDefOverride(BbcPmtHit, 1) }; #endif diff --git a/offline/packages/bbc/BbcPmtHitLinkDef.h b/offline/packages/bbc/BbcPmtHitLinkDef.h index 70f1f299ef..19dc7717c7 100644 --- a/offline/packages/bbc/BbcPmtHitLinkDef.h +++ b/offline/packages/bbc/BbcPmtHitLinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcPmtHit+; +#pragma link C++ class BbcPmtHit + ; #endif diff --git a/offline/packages/bbc/BbcPmtHitV1.cc b/offline/packages/bbc/BbcPmtHitV1.cc index 16cbaee3c6..52e10189af 100644 --- a/offline/packages/bbc/BbcPmtHitV1.cc +++ b/offline/packages/bbc/BbcPmtHitV1.cc @@ -2,15 +2,14 @@ #include -BbcPmtHitV1::BbcPmtHitV1(const short ipmt, const float iadc, const float itdc0, const float itdc1) : - pmt(ipmt), - adc(iadc), - tdc0(itdc0), - tdc1(itdc1) +BbcPmtHitV1::BbcPmtHitV1(const short ipmt, const float iadc, const float itdc0, const float itdc1) + : pmt(ipmt) + , adc(iadc) + , tdc0(itdc0) + , tdc1(itdc1) { } - void BbcPmtHitV1::identify(std::ostream& out) const { out << "identify yourself: I am a BbcPmtHitV1 object" << std::endl; diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 65140563b4..6161db13b4 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -9,26 +9,25 @@ class BbcPmtHitV1 : public BbcPmtHit { - -public: - BbcPmtHitV1() { } + public: + BbcPmtHitV1() {} BbcPmtHitV1(const short pmt, const float adc, const float tdc0, const float tdc1); ~BbcPmtHitV1() override = default; - short get_pmt() const override {return pmt;} - float get_adc() const override {return adc;} - float get_tdc0() const override {return tdc0;} - float get_tdc1() const override {return tdc1;} + short get_pmt() const override { return pmt; } + float get_adc() const override { return adc; } + float get_tdc0() const override { return tdc0; } + float get_tdc1() const override { return tdc1; } void identify(std::ostream& os = std::cout) const override; -private: + private: short pmt; float adc; float tdc0; float tdc1; - ClassDefOverride(BbcPmtHitV1,1) + ClassDefOverride(BbcPmtHitV1, 1) }; #endif diff --git a/offline/packages/bbc/BbcPmtHitV1LinkDef.h b/offline/packages/bbc/BbcPmtHitV1LinkDef.h index 7e24d75b57..b696f7427a 100644 --- a/offline/packages/bbc/BbcPmtHitV1LinkDef.h +++ b/offline/packages/bbc/BbcPmtHitV1LinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class BbcPmtHitV1+; +#pragma link C++ class BbcPmtHitV1 + ; #endif diff --git a/offline/packages/bbc/BbcReturnCodes.h b/offline/packages/bbc/BbcReturnCodes.h index b1194fdec8..44787bd4c1 100644 --- a/offline/packages/bbc/BbcReturnCodes.h +++ b/offline/packages/bbc/BbcReturnCodes.h @@ -1,7 +1,6 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. - #ifndef BBC_BBCRETURNCODES_H #define BBC_BBCRETURNCODES_H @@ -9,9 +8,9 @@ namespace BbcReturnCodes { - const short BBC_INVALID_SHORT = std::numeric_limits::min();//-9999; - const int BBC_INVALID_INT = std::numeric_limits::min();//-9999; + const short BBC_INVALID_SHORT = std::numeric_limits::min(); //-9999; + const int BBC_INVALID_INT = std::numeric_limits::min(); //-9999; const float BBC_INVALID_FLOAT = std::numeric_limits::quiet_NaN(); -} +} // namespace BbcReturnCodes #endif From 960480e4fedae9625bf95a849dab5e7455f18324 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 20:14:36 -0400 Subject: [PATCH 089/468] fix cppcheck warnings --- offline/packages/bbc/BbcOutV1.cc | 12 ++++++------ offline/packages/bbc/BbcOutV1.h | 3 ++- offline/packages/bbc/BbcPmtContainerV1.cc | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index bce2187a64..d64a745508 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -84,22 +84,22 @@ void BbcOutV1::AddBbcNS(const int iBBC, const short npmt, const float energy, co //______________________________________ short BbcOutV1::get_nPMT(const int nBbc) const { - BbcNorthSouthV1 *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_SHORT, else nPMT + BbcNorthSouthV1 *bbcns = static_cast (GetBbcNS()->UncheckedAt(nBbc)); + // if bbcns=null (does not exist) return BbcReturnCodes::BBC_INVALID_SHORT, else nPMT return ((bbcns) ? bbcns->get_nPMT() : BbcReturnCodes::BBC_INVALID_SHORT); } //______________________________________ float BbcOutV1::get_nCharge(const int nBbc) const { - BbcNorthSouth *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Energy + BbcNorthSouth *bbcns = static_cast (GetBbcNS()->UncheckedAt(nBbc)); + // if bbcns=null (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Energy return ((bbcns) ? bbcns->get_nCharge() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcOutV1::get_Timing(const int nBbc) const { - BbcNorthSouth *bbcns = (BbcNorthSouthV1 *) GetBbcNS()->UncheckedAt(nBbc); - // if bbcns=nil (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Timing + BbcNorthSouth *bbcns = static_cast (GetBbcNS()->UncheckedAt(nBbc)); + // if bbcns=null (does not exist) return BbcReturnCodes::BBC_INVALID_FLOAT, else Timing return ((bbcns) ? bbcns->get_MeanTime() : BbcReturnCodes::BBC_INVALID_FLOAT); } diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index 8c155437d6..d4c8d3c1d3 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -76,10 +76,11 @@ class BbcOutV1 : public BbcOut */ float get_Timing(const int nBbc) const override; - virtual void Init(); private: + TClonesArray *GetBbcNS() const { return BbcNS; } + void Init(); float Bbc_ZVertex{}; float Bbc_dZVertex{}; diff --git a/offline/packages/bbc/BbcPmtContainerV1.cc b/offline/packages/bbc/BbcPmtContainerV1.cc index 622777c149..a8e6baa9fe 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.cc +++ b/offline/packages/bbc/BbcPmtContainerV1.cc @@ -43,25 +43,25 @@ void BbcPmtContainerV1::AddBbcPmt(const short pmt, const float adc, const float short BbcPmtContainerV1::get_pmt(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = static_cast (GetBbcPmtHits()->UncheckedAt(iPmt)); return ((Bbchit) ? Bbchit->get_pmt() : BbcReturnCodes::BBC_INVALID_SHORT); } float BbcPmtContainerV1::get_adc(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = static_cast (GetBbcPmtHits()->UncheckedAt(iPmt)); return ((Bbchit) ? Bbchit->get_adc() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcPmtContainerV1::get_tdc0(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = static_cast (GetBbcPmtHits()->UncheckedAt(iPmt)); return ((Bbchit) ? Bbchit->get_tdc0() : BbcReturnCodes::BBC_INVALID_FLOAT); } float BbcPmtContainerV1::get_tdc1(const int iPmt) const { - BbcPmtHit *Bbchit = (BbcPmtHit *) GetBbcPmtHits()->UncheckedAt(iPmt); + BbcPmtHit *Bbchit = static_cast (GetBbcPmtHits()->UncheckedAt(iPmt)); return ((Bbchit) ? Bbchit->get_tdc1() : BbcReturnCodes::BBC_INVALID_FLOAT); } From 859a1dc6054209d887b878f7e7a31b0b33e9d205 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 20:22:04 -0400 Subject: [PATCH 090/468] iwyu --- offline/packages/bbc/BbcNorthSouth.h | 2 ++ offline/packages/bbc/BbcNorthSouthV1.h | 2 ++ offline/packages/bbc/BbcOutV1.h | 2 ++ offline/packages/bbc/BbcPmtContainerV1.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index a0b8a486ea..a2ea742e1d 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -6,6 +6,8 @@ #include #include +#include + class BbcNorthSouth : public PHObject { public: diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index e8ef959614..3a30e12632 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -5,6 +5,8 @@ #include "BbcNorthSouth.h" +#include + class BbcNorthSouthV1 : public BbcNorthSouth { public: diff --git a/offline/packages/bbc/BbcOutV1.h b/offline/packages/bbc/BbcOutV1.h index d4c8d3c1d3..53e07fbeda 100644 --- a/offline/packages/bbc/BbcOutV1.h +++ b/offline/packages/bbc/BbcOutV1.h @@ -5,6 +5,8 @@ #include "BbcOut.h" +#include + class TClonesArray; /// diff --git a/offline/packages/bbc/BbcPmtContainerV1.h b/offline/packages/bbc/BbcPmtContainerV1.h index 10c47200be..f7d5e3364a 100644 --- a/offline/packages/bbc/BbcPmtContainerV1.h +++ b/offline/packages/bbc/BbcPmtContainerV1.h @@ -5,6 +5,8 @@ #include "BbcPmtContainer.h" +#include + class TClonesArray; /// From a5e9dd38fdd337f14de01b9cc57153cb89948240 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 31 Mar 2023 21:26:54 -0400 Subject: [PATCH 091/468] delete unusable default ctors --- offline/packages/bbc/BbcNorthSouthV1.h | 2 +- offline/packages/bbc/BbcPmtHitV1.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 3a30e12632..98a3fa4a06 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -10,7 +10,7 @@ class BbcNorthSouthV1 : public BbcNorthSouth { public: - BbcNorthSouthV1() {} + BbcNorthSouthV1() = delete; BbcNorthSouthV1(const short npmt, const float chargesum, const float timing); virtual ~BbcNorthSouthV1() {} void identify(std::ostream& os = std::cout) const override; diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 6161db13b4..013833a853 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -10,7 +10,7 @@ class BbcPmtHitV1 : public BbcPmtHit { public: - BbcPmtHitV1() {} + BbcPmtHitV1() = delete; BbcPmtHitV1(const short pmt, const float adc, const float tdc0, const float tdc1); ~BbcPmtHitV1() override = default; From 3660efb447a38e93ca91374f9f797914fcb24031 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 1 Apr 2023 10:23:35 -0400 Subject: [PATCH 092/468] Updates for Jenkins --- .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 2 - .../g4mvtx/PHG4MvtxTruthClusterizer.cc | 40 ++++++++++--------- .../g4mvtx/PHG4MvtxTruthClusterizer.h | 5 ++- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 8346921967..09a152c70e 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -1,8 +1,6 @@ #ifndef G4MVTX_PHG4MVTXHITRECO_H #define G4MVTX_PHG4MVTXHITRECO_H -#include "TruthMvtxClusterBuilder.h" - #include #include diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc index c5daae393d..5585d4723d 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -540,7 +539,9 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli << " local x " << locclusx << " local y " << locclusz << endl; - if (m_cluster_version==4){ + // ok force it use use cluster version v4 for now (Valgrind is not happy with application of v5) + /* if (m_cluster_version==4){ */ + if (m_cluster_version == 4) { auto clus = std::make_unique(); clus->setAdc(nhits); clus->setLocalX(locclusx); @@ -556,25 +557,26 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli clus->identify(); m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - }else if(m_cluster_version==5){ - auto clus = std::make_unique(); - clus->setAdc(nhits); - clus->setMaxAdc(1); - clus->setLocalX(locclusx); - clus->setLocalY(locclusz); - clus->setPhiError(phierror); - clus->setZError(zerror); - clus->setPhiSize(phibins.size()); - clus->setZSize(zbins.size()); - // All silicon surfaces have a 1-1 map to hitsetkey. - // So set subsurface key to 0 - clus->setSubSurfKey(0); + } + /* }else if(m_cluster_version==5){ */ + /* auto clus = std::make_unique(); */ + /* clus->setAdc(nhits); */ + /* clus->setMaxAdc(1); */ + /* clus->setLocalX(locclusx); */ + /* clus->setLocalY(locclusz); */ + /* clus->setPhiError(phierror); */ + /* clus->setZError(zerror); */ + /* clus->setPhiSize(phibins.size()); */ + /* clus->setZSize(zbins.size()); */ + /* // All silicon surfaces have a 1-1 map to hitsetkey. */ + /* // So set subsurface key to 0 */ + /* clus->setSubSurfKey(0); */ - if (Verbosity() > 2) - clus->identify(); + /* if (Verbosity() > 2) */ + /* clus->identify(); */ - m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - } + /* m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); */ + /* } */ } // clusitr loop } // loop over hitsets diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h index c2e8ff42c4..9ae4cba250 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h @@ -62,7 +62,10 @@ class PHG4MvtxTruthClusterizer : public TruthClusterizerBase { bool _C__are_adjacent(const std::pair &lhs, const std::pair &rhs); public: - void set_cluster_version(int value) { m_cluster_version = value; } + void set_cluster_version(int /*value*/) { + std::cout << "None-implemented function in PHG4MvtxTruthClusterizer. " << std::endl + << "Only TrkrClusterv4 currently implemented." << std::endl; + }; void _C__ClusterMvtx(TrkrClusterContainer* clusters); bool GetZClustering() const { return m_makeZClustering; }; void SetZClustering(const bool make_z_clustering) { m_makeZClustering = make_z_clustering; }; From 4c0c23973baf3698e57dbc0deb74a6fca9a055c4 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 1 Apr 2023 22:42:54 -0400 Subject: [PATCH 093/468] second degree fixes for Jenkins --- .../g4mvtx/PHG4MvtxTruthClusterizer.cc | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc index 5585d4723d..c40e8bf7b1 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc @@ -500,7 +500,7 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli const double phisize = phibins.size() * pitch; const double zsize = zbins.size() * length; - static const double invsqrt12 = 1./std::sqrt(12); + /* static const double invsqrt12 = 1./std::sqrt(12); */ // scale factors (phi direction) /* @@ -509,16 +509,16 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli These scale factors are applied to produce cluster pulls with width unity */ - double phierror = pitch * invsqrt12; + /* double phierror = pitch * invsqrt12; */ - static constexpr std::array scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }}; - if ( phibins.size() == 1 && zbins.size() == 1 ) phierror*=scalefactors_phi[0]; - else if( phibins.size() == 2 && zbins.size() == 1 ) phierror*=scalefactors_phi[1]; - else if( phibins.size() == 1 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; - else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0]; - else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1]; - else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; - else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3]; + /* static constexpr std::array scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }}; */ + /* if ( phibins.size() == 1 && zbins.size() == 1 ) phierror*=scalefactors_phi[0]; */ + /* else if( phibins.size() == 2 && zbins.size() == 1 ) phierror*=scalefactors_phi[1]; */ + /* else if( phibins.size() == 1 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; */ + /* else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0]; */ + /* else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1]; */ + /* else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; */ + /* else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3]; */ // scale factors (z direction) @@ -526,12 +526,12 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z and phi other clusters, which are very few and pathological, get a scale factor of 1 */ - static constexpr std::array scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }}; - double zerror = length*invsqrt12; - if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0]; - else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1]; - else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2]; - else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3]; + /* static constexpr std::array scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }}; */ + /* double zerror = length*invsqrt12; */ + /* if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0]; */ + /* else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1]; */ + /* else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2]; */ + /* else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3]; */ if(Verbosity() > 0) cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize From bb69ebe784185d2fb57cad1a9b00475ace354176 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Mon, 3 Apr 2023 11:33:10 -0400 Subject: [PATCH 094/468] remove debugging function --- simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h index 4176825939..b9c5859c31 100644 --- a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h +++ b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h @@ -31,7 +31,6 @@ class PHG4InttTruthClusterizer : public TruthClusterizerBase { // note that no noise is added during the digitization // --------------------------------------- public: - void say_hi() { std::cout << " BANANA hello world " << std::endl; }; void set_adc_scale(const int &layer, const std::vector &userrange); void _D__DigitizeLadderCells(PHCompositeNode *topNode); private: From 34cb8b6cbb601f81314334d7cd5e5540ac9e909f Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 3 Apr 2023 11:33:38 -0400 Subject: [PATCH 095/468] Added ntuple for debugging CM cluster matching --- .../PHTpcCentralMembraneClusterizer.cc | 52 +++++++++++++------ .../tpccalib/PHTpcCentralMembraneMatcher.cc | 40 +++++++++++--- .../tpccalib/PHTpcCentralMembraneMatcher.h | 4 +- 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index f201c1906f..d604e1650d 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -292,34 +292,39 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) int layerMatch = -1; + int nRowsMatch = 2; + + if(layer[i] >= 39) nRowsMatch = 4; + else if(layer[i] >= 23) nRowsMatch = 3; + if( pos[i].Z() >= 0 ){ if(layer[i] == 7){ - if(nPairAbove_pos[layer[i]-7] >= 3) layerMatch = layer[i]+1; + if(nPairAbove_pos[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; }else if(layer[i] == 54){ - if(nPairAbove_pos[layer[i]-8] >= 3) layerMatch = layer[i]-1; + if(nPairAbove_pos[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; }else{ - if(nPairAbove_pos[layer[i]-7] >=3 && nPairAbove_pos[layer[i]-8] >=3){ + if(nPairAbove_pos[layer[i]-7] >= nRowsMatch && nPairAbove_pos[layer[i]-8] >= nRowsMatch){ if(pairAboveContent_pos[layer[i]-7]/nPairAbove_pos[layer[i]-7] > pairAboveContent_pos[layer[i]-8]/nPairAbove_pos[layer[i]-8]) layerMatch = layer[i]+1; else layerMatch = layer[i]-1; - }else if(nPairAbove_pos[layer[i]-7] >=3) layerMatch = layer[i]+1; - else if(nPairAbove_pos[layer[i]-8] >=3) layerMatch = layer[i]-1; + }else if(nPairAbove_pos[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; + else if(nPairAbove_pos[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; } }else{ if(layer[i] == 7){ - if(nPairAbove_neg[layer[i]-7] >= 3) layerMatch = layer[i]+1; + if(nPairAbove_neg[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; }else if(layer[i] == 54){ - if(nPairAbove_neg[layer[i]-8] >= 3) layerMatch = layer[i]-1; + if(nPairAbove_neg[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; }else{ - if(nPairAbove_neg[layer[i]-7] >=3 && nPairAbove_neg[layer[i]-8] >=3){ + if(nPairAbove_neg[layer[i]-7] >= nRowsMatch && nPairAbove_neg[layer[i]-8] >= nRowsMatch){ if(pairAboveContent_neg[layer[i]-7]/nPairAbove_neg[layer[i]-7] > pairAboveContent_neg[layer[i]-8]/nPairAbove_neg[layer[i]-8]) layerMatch = layer[i]+1; else layerMatch = layer[i]-1; - }else if(nPairAbove_neg[layer[i]-7] >=3) layerMatch = layer[i]+1; - else if(nPairAbove_neg[layer[i]-8] >=3) layerMatch = layer[i]-1; + }else if(nPairAbove_neg[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; + else if(nPairAbove_neg[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; } } - if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39) ) isAcrossGap[i] = true; + if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39 || layer[i] == 7) ) isAcrossGap[i] = true; float bestphidist=maxphidist; for (int j=0;jget_radius(); PHG4TpcCylinderGeom *layergeom2 = _geom_container->GetLayerCellGeom(layer[i_pair[i]]); double rad2 = layergeom2->get_radius(); - PHG4TpcCylinderGeom *layergeom0; - double layer_dr; + // PHG4TpcCylinderGeom *layergeom0; + double layer_dr = std::abs(rad1 - rad2); + /* if(layer[i] != 7 && layer[i] != 23 && layer[i] != 39) { layergeom0 = _geom_container->GetLayerCellGeom(layer[i]-1); @@ -447,7 +453,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) { layergeom0 = _geom_container->GetLayerCellGeom(layer[i]+1); layer_dr = layergeom0->get_radius() - rad1; - } + }*/ double rad_lyr_boundary = rad1 + layer_dr / 2.0; @@ -456,11 +462,22 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if( _dcc) dist_pos = _distortionCorrection.get_corrected_position( dist_pos, _dcc ); double dist_r = sqrt(dist_pos[0]*dist_pos[0] + dist_pos[1] * dist_pos[1]); double cmclus_dr = _cmclus_dr_outer; - if(dist_r < 41.0) + /* + if(dist_r < 41.0) cmclus_dr = _cmclus_dr_inner; else if(dist_r >= 41.0 && rad2 < 58.0) cmclus_dr = _cmclus_dr_mid; - // Use radial width of stripe and efrac to determine where radius at center of distribution must be + */ + + if(dist_r < 41.0){ + if(rad2 >= 41.0) cmclus_dr = 0.5*(_cmclus_dr_inner + _cmclus_dr_mid); + else cmclus_dr = _cmclus_dr_inner; + }else if(dist_r >= 41.0 && dist_r < 58.0){ + if(rad2 >= 58.0) cmclus_dr = 0.5*(_cmclus_dr_mid + _cmclus_dr_outer); + else cmclus_dr = _cmclus_dr_mid; + } + + // Use radial width of stripe and efrac to determine where radius at center of distribution must be double aveR = rad_lyr_boundary - efrac * cmclus_dr + cmclus_dr/2.0; if(Verbosity() > 0) @@ -481,8 +498,11 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) << std::endl; } } else { + + std::cout << "singleton layer: " << layer[i] << " radius: " << pos[i].Perp() << " isAcrossGap? " << isAcrossGap[i] << std::endl; if(_histos) hClustE[2]->Fill(energy[i]); // These single cluster cases have good phi, but do not have a good radius centroid estimate - may want to skip them, record nclusters + if(layer[i] == 7) isAcrossGap[i] = true; aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); nclusters.push_back(1); diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 934f836024..686f279700 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -285,12 +285,23 @@ std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ int PHTpcCentralMembraneMatcher::getClusterRMatch( std::vector hitMatches, std::vector clusterPeaks, double clusterR){ - int closest_clusterR = -1; - - for(int i=0; i<(int)hitMatches.size(); i++){ - - double lowGap = 0.0; - double highGap = 0.0; + // int closest_clusterR = -1; + + /* for(int i=0; i<(int)hitMatches.size(); i++){ + + double lowGap = 0.5; + double highGap = 0.5; + */ + double closestDist = 100.; + int closestPeak = -1; + for(int j=0; j<(int)clusterPeaks.size(); j++){ + if(std::abs(clusterR - clusterPeaks[j]) < closestDist){ + closestDist = std::abs(clusterR - clusterPeaks[j]); + closestPeak = j; + } + } + + /* if(hitMatches[i] <= 14){ lowGap = 0.565985; @@ -315,13 +326,20 @@ int PHTpcCentralMembraneMatcher::getClusterRMatch( std::vector hitMatches, highGap = 1.09705; } + if( clusterR > (clusterPeaks[i] - lowGap) && clusterR <= (clusterPeaks[i] + highGap) ){ closest_clusterR = hitMatches[i]; break; } - } + */ + // } - return closest_clusterR; + + + // return closest_clusterR; + + if(closestPeak != -1) return hitMatches[closestPeak]; + else return -1; } @@ -373,6 +391,8 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + reco_ntup = new TNtuple("reco_ntuple","","hitR:hitPhi:hitZ:recoR:recoPhi:recoZ"); + std::vector hitR; std::vector hitPhi; @@ -904,6 +924,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) cmdiff->setNclusters(nclus); m_cm_flash_diffs->addDifferenceSpecifyKey(key, cmdiff); + + reco_ntup->Fill(m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),m_truth_pos[p.first].Z(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z()); // store cluster position const double clus_r = reco_pos[p.second].Perp(); @@ -1020,6 +1042,8 @@ int PHTpcCentralMembraneMatcher::End(PHCompositeNode * /*topNode*/ ) clust_r_phi_gr2_pos->Write("clust_r_phi_gr2_pos"); clust_r_phi_gr2_neg->Write("clust_r_phi_gr2_neg"); + reco_ntup->Write(); + fout2->Close(); // write evaluation histograms diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index caf764e3cb..3d109de757 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -134,7 +134,9 @@ class PHTpcCentralMembraneMatcher : public SubsysReco TGraph *clust_r_phi_gr2_pos; TGraph *clust_r_phi_gr2_neg; - + TNtuple *reco_ntup = nullptr; + + std::string m_outputfile2 = "CM_r_phi_maps.root"; std::unique_ptr fout2; From 987a8b8984904c7e26c661cd1b31286a73ac7dab Mon Sep 17 00:00:00 2001 From: adamquarker Date: Mon, 3 Apr 2023 15:37:08 -0400 Subject: [PATCH 096/468] changing nSteps --- calibrations/tpc/generator/AnnularFieldSim.cc | 4 ++-- calibrations/tpc/generator/AnnularFieldSim.h | 2 +- calibrations/tpc/generator/generate_distortion_map.C | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/calibrations/tpc/generator/AnnularFieldSim.cc b/calibrations/tpc/generator/AnnularFieldSim.cc index d36ce0dbb0..4f11c14f9a 100644 --- a/calibrations/tpc/generator/AnnularFieldSim.cc +++ b/calibrations/tpc/generator/AnnularFieldSim.cc @@ -2597,7 +2597,7 @@ void AnnularFieldSim::PlotFieldSlices(const char *filebase, TVector3 pos, char w return; } -void AnnularFieldSim::GenerateSeparateDistortionMaps(const char *filebase, int r_subsamples, int p_subsamples, int z_subsamples, int /*z_substeps*/, bool andCartesian) +void AnnularFieldSim::GenerateSeparateDistortionMaps(const char *filebase, int nSteps, int r_subsamples, int p_subsamples, int z_subsamples, int /*z_substeps*/, bool andCartesian) { //generates the distortion map for one or both sides of the detector, separating them so //they do not try to interpolate across the CM. @@ -2609,7 +2609,7 @@ void AnnularFieldSim::GenerateSeparateDistortionMaps(const char *filebase, int r float deltap = s.Phi(); //(pf-pi)/np; float deltaz = s.Z(); //(zf-zi)/nz; TVector3 stepzvec(0, 0, deltaz); - int nSteps = 500; //how many steps to take in the particle path. hardcoded for now. Think about this later. + //int nSteps = 500; //how many steps to take in the particle path. hardcoded for now. Think about this later. int nSides = 1; if (hasTwin) nSides = 2; diff --git a/calibrations/tpc/generator/AnnularFieldSim.h b/calibrations/tpc/generator/AnnularFieldSim.h index a8665dfb9c..1938736a6b 100644 --- a/calibrations/tpc/generator/AnnularFieldSim.h +++ b/calibrations/tpc/generator/AnnularFieldSim.h @@ -236,7 +236,7 @@ class AnnularFieldSim //file-writing functions for complex mapping questions: void GenerateDistortionMaps(const char *filebase, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false); - void GenerateSeparateDistortionMaps(const char *filebase, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false); + void GenerateSeparateDistortionMaps(const char *filebase, int nSteps = 500, int r_subsamples = 1, int p_subsamples = 1, int z_subsamples = 1, int z_substeps = 1, bool andCartesian = false); void PlotFieldSlices(const char *filebase, TVector3 pos, char which = 'E'); void load_spacecharge(const std::string &filename, const std::string &histname, float zoffset = 0, float chargescale = 1, float cmscale = 1, bool isChargeDensity = true); diff --git a/calibrations/tpc/generator/generate_distortion_map.C b/calibrations/tpc/generator/generate_distortion_map.C index 77c5a50c93..6a082d4337 100644 --- a/calibrations/tpc/generator/generate_distortion_map.C +++ b/calibrations/tpc/generator/generate_distortion_map.C @@ -16,7 +16,7 @@ void SurveyFiles(TFileCollection* filelist); -void generate_distortion_map(const char *inputname, const char* gainName, const char *outputname, const char *ibfName, const char *primName, bool hasSpacecharge=true, bool isAdc=false){ +void generate_distortion_map(const char *inputname, const char* gainName, const char *outputname, const char *ibfName, const char *primName, bool hasSpacecharge=true, bool isAdc=false, int nSteps=500){ printf("generating single distortion map. Caution: This is vastly less efficient than re-using the tpc model once it is set up\n"); bool hasTwin=true; //this flag prompts the code to build both a positive-half and a negative-half for the TPC, reusing as much of the calculations as possible. It is more efficient to 'twin' one half of the TPC than to recalculate/store the greens functions for both. @@ -206,7 +206,7 @@ void generate_distortion_map(const char * inputpattern="./evgeny_apr/Smooth*.roo //TestSpotDistortion(tpc); //tpc->GenerateDistortionMaps(outputfilename,2,2,2,1,true); - tpc->GenerateSeparateDistortionMaps(outputfilename,2,2,2,1,true); + tpc->GenerateSeparateDistortionMaps(outputfilename,500,2,2,2,1,true); printf("distortions mapped.\n"); tpc->PlotFieldSlices(outputfilename.Data(),pos); tpc->PlotFieldSlices(outputfilename.Data(),pos,'B'); From ce959a37e1f7c317bcb7a9c759b52a1852f8f4a2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 3 Apr 2023 19:56:40 -0400 Subject: [PATCH 097/468] fix signed/unsigned comparison --- offline/packages/CaloBase/TowerInfoDefs.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoDefs.h b/offline/packages/CaloBase/TowerInfoDefs.h index 0a80adf756..1f3505f4aa 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.h +++ b/offline/packages/CaloBase/TowerInfoDefs.h @@ -163,12 +163,12 @@ namespace TowerInfoDefs unsigned int key; if(towerIndex==0) key = 0; - if(towerIndex==1) key = 1; - if(towerIndex==2) key = 2; + else if(towerIndex==1) key = 1; + else if(towerIndex==2) key = 2; //negative side - if(towerIndex==3) {key = 1 << 2; key += 0;} - if(towerIndex==4) {key = 1 << 2; key += 1;} - if(towerIndex==5) {key = 1 << 2; key += 2;} + else if(towerIndex==3) {key = 1 << 2; key += 0;} + else if(towerIndex==4) {key = 1 << 2; key += 1;} + else if(towerIndex==5) {key = 1 << 2; key += 2;} return key; } @@ -182,10 +182,10 @@ namespace TowerInfoDefs std::cout << "Attempting to access smd channel with invalid number " << towerIndex << std::endl; exit(1); } - int Xpos[2] = {0,6}; - int Ypos[2] = {7,14}; - int Xneg[2] = {15,23}; - int Yneg[2] = {22,29}; + unsigned int Xpos[2] = {0,6}; + unsigned int Ypos[2] = {7,14}; + unsigned int Xneg[2] = {15,23}; + unsigned int Yneg[2] = {22,29}; unsigned int xyBit = 0; unsigned int fingerIndex; unsigned int sideBit = 0; From 001c6c9d4485a9959383bae55c4a9e129e20c17a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 4 Apr 2023 08:30:05 -0400 Subject: [PATCH 098/468] add surface helper function --- offline/packages/trackreco/ActsPropagator.cc | 10 ++++++++++ offline/packages/trackreco/ActsPropagator.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index b5273dfd64..670d3b4898 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -8,12 +8,22 @@ #include #include #include +#include #include #include #include #include +ActsPropagator::SurfacePtr +ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) +{ + return Acts::Surface::makeShared( + Acts::Vector3(vertex->get_x() * Acts::UnitConstants::cm, + vertex->get_y() * Acts::UnitConstants::cm, + vertex->get_z() * Acts::UnitConstants::cm)); +} + ActsPropagator::BoundTrackParam ActsPropagator::makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap) diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index 97a1a15f9e..b6b54d9b9b 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -23,6 +23,7 @@ #include class SvtxTrack; +class SvtxVertex; class SvtxVertexMap; class ActsPropagator @@ -43,6 +44,7 @@ class ActsPropagator } ~ActsPropagator() {} + SurfacePtr makeVertexSurface(const SvtxVertex* vertex); BoundTrackParam makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap); BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters& params, From 41656f2a685579ad46212c433302a7ac4c8a97c9 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Tue, 4 Apr 2023 08:31:48 -0400 Subject: [PATCH 099/468] KFP: Cleaning and bug fix --- .../packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 4 ++-- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h | 4 ++-- .../packages/KFParticle_sPHENIX/KFParticle_nTuple.cc | 9 +++++++++ .../packages/KFParticle_sPHENIX/KFParticle_nTuple.h | 1 + .../packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 4 ++-- .../packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h | 10 +++++++--- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 7feb1e2077..237c259e82 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -111,7 +111,7 @@ KFParticle KFParticle_Tools::makeVertex(PHCompositeNode * /*topNode*/) return kfp_vertex; } -std::vector KFParticle_Tools::makeAllPrimaryVertices(PHCompositeNode *topNode, std::string vertexMapName) +std::vector KFParticle_Tools::makeAllPrimaryVertices(PHCompositeNode *topNode, std::string &vertexMapName) { std::string vtxMN; if (vertexMapName.empty()) @@ -211,7 +211,7 @@ std::vector KFParticle_Tools::makeAllDaughterParticles(PHCompositeNo return daughterParticles; } -int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, KFParticle vertex, std::string vertexMapName) +int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, KFParticle vertex, std::string &vertexMapName) { std::string vtxMN; if (vertexMapName.empty()) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 6d60915024..056388c893 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -48,13 +48,13 @@ class KFParticle_Tools : protected KFParticle_MVA KFParticle makeVertex(PHCompositeNode *topNode); - std::vector makeAllPrimaryVertices(PHCompositeNode *topNode, std::string vertexMapName); + std::vector makeAllPrimaryVertices(PHCompositeNode *topNode, std::string &vertexMapName); KFParticle makeParticle(PHCompositeNode *topNode); std::vector makeAllDaughterParticles(PHCompositeNode *topNode); - int getTracksFromVertex(PHCompositeNode *topNode, KFParticle vertex, std::string vertexMapName); + int getTracksFromVertex(PHCompositeNode *topNode, KFParticle vertex, std::string &vertexMapName); /*const*/ bool isGoodTrack(KFParticle particle, const std::vector &primaryVertices); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 694aae38a0..1114eb5f85 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -27,6 +27,7 @@ KFParticle_Tools kfpTupleTools; KFParticle_nTuple::KFParticle_nTuple() : m_has_intermediates_nTuple(false) + , m_extrapolateTracksToSV_nTuple(true) , m_constrain_to_vertex_nTuple(false) , m_get_all_PVs(false) , m_truth_matching(false) @@ -348,6 +349,14 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, } } + if (m_extrapolateTracksToSV_nTuple) + { + for (unsigned int i = 0; i < daughters.size(); ++i) + { + daughterArray[i].SetProductionVertex(motherParticle); + } + } + if (m_constrain_to_vertex_nTuple) { m_calculated_mother_dira = kfpTupleTools.eventDIRA(motherParticle, vertex); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index 133aa48a3f..9e7738a584 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -38,6 +38,7 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools protected: bool m_has_intermediates_nTuple; + bool m_extrapolateTracksToSV_nTuple; bool m_constrain_to_vertex_nTuple; bool m_get_all_PVs; //int m_num_intermediate_states_nTuple; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index ee78c0e0d3..73ec502580 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -165,8 +165,8 @@ int KFParticle_sPHENIX::End(PHCompositeNode * /*topNode*/) return 0; } -void KFParticle_sPHENIX::printParticles(const KFParticle motherParticle, - const KFParticle chosenVertex, +void KFParticle_sPHENIX::printParticles(const KFParticle &motherParticle, + const KFParticle &chosenVertex, const std::vector &daughterParticles, const std::vector &intermediateParticles, const int numPVs, const int numTracks) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 78d4d050de..6c24b5f48b 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -68,8 +68,8 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K * masses, momenta and positions for mothers, intermediates and final state tracks, * PV position, number of vertices and number of tracks in the event (multiplicity) */ - void printParticles(const KFParticle motherParticle, - const KFParticle chosenVertex, + void printParticles(const KFParticle &motherParticle, + const KFParticle &chosenVertex, const std::vector &daughterParticles, const std::vector &intermediateParticles, const int numPVs, const int numTracks); @@ -199,7 +199,11 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void allowZeroMassTracks(bool allow) { m_allowZeroMassTracks = allow; } - void extraolateTracksToSV(bool extrapolate) { m_extrapolateTracksToSV = extrapolate; } + void extraolateTracksToSV(bool extrapolate) + { + m_extrapolateTracksToSV = extrapolate; + m_extrapolateTracksToSV_nTuple = extrapolate; + } void constrainIntermediateMasses(bool constrain_int_mass) { m_constrain_int_mass = constrain_int_mass; } From 693ae1b6d674218fada6f06ca887e341bbc061cf Mon Sep 17 00:00:00 2001 From: E Shulga Date: Tue, 4 Apr 2023 09:41:54 -0400 Subject: [PATCH 100/468] latest changes --- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 18 ++++++++++++++++++ .../g4tpc/PHG4TpcPadPlaneReadout.h | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index d0a7721330..d11d2b92bb 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -26,6 +26,7 @@ #include // for PHWHERE #include +#include #include #include // for gsl_rng_alloc @@ -34,6 +35,7 @@ #include #include // for _Rb_tree_cons... #include // for pair +#include // for getenv class PHCompositeNode; class TrkrHitTruthAssoc; @@ -60,6 +62,14 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) : PHG4TpcPadPlane(name) { InitializeParameters(); + // Reading TPC Gain Maps from the file + std::cout<<"PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout :::"<Get("RadPhiPlot0")->Clone(); + h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); + h_gain[0]->SetDirectory(0); + h_gain[1]->SetDirectory(0); + fileGain->Close(); RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion @@ -278,6 +288,14 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( //=============================== double nelec = getSingleEGEMAmplification(); + // Applying weight with respect to the rad_gem and phi after electrons are redistributed + double phi_gain = phi; + if(phi<0)phi_gain += 2*M_PI; + double gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm + //std::cout<Get("RadPhiPlot0")->Clone(); - h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); - h_gain[0]->SetDirectory(0); - h_gain[1]->SetDirectory(0); - fileGain->Close(); - + if(_flagToUseGain==1){ + std::cout<<"PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout :::"<Get("RadPhiPlot0")->Clone(); + h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); + h_gain[0]->SetDirectory(0); + h_gain[1]->SetDirectory(0); + fileGain->Close(); + } RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion @@ -291,8 +292,9 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( // Applying weight with respect to the rad_gem and phi after electrons are redistributed double phi_gain = phi; if(phi<0)phi_gain += 2*M_PI; - double gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm - //std::cout<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - reco_ntup = new TNtuple("reco_ntuple","","hitR:hitPhi:hitZ:recoR:recoPhi:recoZ"); + reco_ntup = new TNtuple("reco_ntuple","","hitR:hitPhi:hitZ:recoR:recoPhi:recoZ:nClus"); std::vector hitR; std::vector hitPhi; @@ -489,6 +489,10 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) } hit_r_phi_gr = new TGraph((int)hitR.size(), &hitPhi[0], &hitR[0]); + hit_r_phi_gr->SetMarkerStyle(20); + hit_r_phi_gr->SetMarkerSize(0.5); + hit_r_phi_gr->GetXaxis()->SetTitle("#phi"); + hit_r_phi_gr->GetYaxis()->SetTitle("R (cm)"); int ret = GetNodes(topNode); return ret; @@ -623,18 +627,52 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) clust_r_phi_gr = new TGraph((int)clustR.size(), &clustPhi[0], &clustR[0]); + clust_r_phi_gr->SetMarkerStyle(20); + clust_r_phi_gr->SetMarkerSize(0.5); + clust_r_phi_gr->SetMarkerColor(kMagenta); + clust_r_phi_gr_pos = new TGraph((int)clustR_pos.size(), &clustPhi_pos[0], &clustR_pos[0]); + clust_r_phi_gr_pos->SetMarkerStyle(20); + clust_r_phi_gr_pos->SetMarkerSize(0.5); + clust_r_phi_gr_pos->SetMarkerColor(kMagenta); + clust_r_phi_gr_neg = new TGraph((int)clustR_neg.size(), &clustPhi_neg[0], &clustR_neg[0]); + clust_r_phi_gr_neg->SetMarkerStyle(20); + clust_r_phi_gr_neg->SetMarkerSize(0.5); + clust_r_phi_gr_neg->SetMarkerColor(kMagenta); clust_r_phi_gr1 = new TGraph((int)clustR1.size(), &clustPhi1[0], &clustR1[0]); + clust_r_phi_gr1->SetMarkerStyle(20); + clust_r_phi_gr1->SetMarkerSize(0.5); + clust_r_phi_gr1->SetMarkerColor(kBlue); + clust_r_phi_gr1_pos = new TGraph((int)clustR_pos1.size(), &clustPhi_pos1[0], &clustR_pos1[0]); + clust_r_phi_gr1_pos->SetMarkerStyle(20); + clust_r_phi_gr1_pos->SetMarkerSize(0.5); + clust_r_phi_gr1_pos->SetMarkerColor(kBlue); + clust_r_phi_gr1_neg = new TGraph((int)clustR_neg1.size(), &clustPhi_neg1[0], &clustR_neg1[0]); + clust_r_phi_gr1_neg->SetMarkerStyle(20); + clust_r_phi_gr1_neg->SetMarkerSize(0.5); + clust_r_phi_gr1_neg->SetMarkerColor(kBlue); clust_r_phi_gr2 = new TGraph((int)clustR2.size(), &clustPhi2[0], &clustR2[0]); + clust_r_phi_gr2->SetMarkerStyle(20); + clust_r_phi_gr2->SetMarkerSize(0.5); + clust_r_phi_gr2->SetMarkerColor(kGreen+2); + clust_r_phi_gr2_pos = new TGraph((int)clustR_pos2.size(), &clustPhi_pos2[0], &clustR_pos2[0]); + clust_r_phi_gr2_pos->SetMarkerStyle(20); + clust_r_phi_gr2_pos->SetMarkerSize(0.5); + clust_r_phi_gr2_pos->SetMarkerColor(kGreen+2); + clust_r_phi_gr2_neg = new TGraph((int)clustR_neg2.size(), &clustPhi_neg2[0], &clustR_neg2[0]); + clust_r_phi_gr2_neg->SetMarkerStyle(20); + clust_r_phi_gr2_neg->SetMarkerSize(0.5); + clust_r_phi_gr2_neg->SetMarkerColor(kGreen+2); + std::vector> hit_phiGaps = getPhiGaps(hit_r_phi); std::vector> clust_phiGaps = getPhiGaps(clust_r_phi); @@ -925,7 +963,7 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) m_cm_flash_diffs->addDifferenceSpecifyKey(key, cmdiff); - reco_ntup->Fill(m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),m_truth_pos[p.first].Z(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z()); + reco_ntup->Fill(m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),m_truth_pos[p.first].Z(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z(),nclus); // store cluster position const double clus_r = reco_pos[p.second].Perp(); From e7807ed6f88f04cb231d58f318adf1b516f43cd5 Mon Sep 17 00:00:00 2001 From: Joe Osborn <53052717+osbornjd@users.noreply.github.com> Date: Tue, 4 Apr 2023 12:52:51 -0400 Subject: [PATCH 104/468] Revert "Silicon+TPOT fit update" --- offline/packages/trackreco/PHActsTrkFitter.cc | 212 +++++++++++++----- offline/packages/trackreco/PHActsTrkFitter.h | 18 +- 2 files changed, 166 insertions(+), 64 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 614c5e5e6e..4ffa111543 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -193,6 +193,7 @@ int PHActsTrkFitter::process_event(PHCompositeNode */*topNode*/) { std::cout << " SvtxTrackMap size is now " << m_trackMap->size() << std::endl; + } return Fun4AllReturnCodes::EVENT_OK; @@ -286,7 +287,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(!tpcseed) { std::cout << "no tpc seed"< 1) + if(Verbosity() > 0) { if(siseed) std::cout << " silicon seed position is (x,y,z) = " << siseed->get_x() << " " << siseed->get_y() << " " << siseed->get_z() << std::endl; std::cout << " tpc seed position is (x,y,z) = " << tpcseed->get_x() << " " << tpcseed->get_y() << " " << tpcseed->get_z() << std::endl; @@ -302,15 +303,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) const auto tpcSourceLinks = getSourceLinks(tpcseed, measurements, crossing); sourceLinks.insert( sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end() ); - if(m_fitSiliconMMs) - { - if(!checkMM(sourceLinks) or !siseed) - { - if(Verbosity() > 3) std::cout << "no silicon+tpot measurements, skipping" << std::endl; - continue; - } - } - // position comes from the silicon seed, unless there is no silicon seed Acts::Vector3 position(0,0,0); if(siseed) @@ -329,6 +321,22 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(sourceLinks.empty()) { continue; } + /// If using directed navigation, collect surface list to navigate + SurfacePtrVec surfaces; + if(m_fitSiliconMMs) + { + sourceLinks = getSurfaceVector(sourceLinks, surfaces); + + // skip if there is no surfaces + if( surfaces.empty() ) continue; + + // make sure micromegas are in the tracks, if required + if( m_useMicromegas && + std::none_of( surfaces.begin(), surfaces.end(), [this]( const auto& surface ) + { return m_tGeometry->maps().isMicromegasSurface( surface ); } ) ) + { continue; } + } + Acts::Vector3 momentum( tpcseed->get_px(m_clusterContainer, m_tGeometry), tpcseed->get_py(m_clusterContainer, m_tGeometry), @@ -389,7 +397,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) fitTimer.stop(); fitTimer.restart(); auto mtj = std::make_shared(); - auto result = fitTrack(wrappedSls, seed, kfOptions, mtj); + auto result = fitTrack(wrappedSls, seed, kfOptions, surfaces,mtj); fitTimer.stop(); auto fitTime = fitTimer.get_accumulated_time(); @@ -415,11 +423,12 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if(m_fitSiliconMMs) { - unsigned int trid = m_silmmTrackMap->size(); + + unsigned int trid = m_directedTrackMap->size(); newTrack.set_id(trid); if( getTrackFitResult(fitOutput, &newTrack) ) - { m_silmmTrackMap->insertWithKey(&newTrack, trid); } + { m_directedTrackMap->insertWithKey(&newTrack, trid); } } else { @@ -456,26 +465,10 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } -bool PHActsTrkFitter::checkMM(SourceLinkVec& sls) -{ - bool tpot = false; - for(auto& sl : sls) - { - auto key = sl.cluskey(); - if(TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::micromegasId) - { - tpot = true; - } - } - - return tpot; -} - //___________________________________________________________________________________ -SourceLinkVec PHActsTrkFitter::getSourceLinks( - TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - short int crossing ) +SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + short int crossing ) { SourceLinkVec sourcelinks; @@ -502,7 +495,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( if(!cluster) { if(Verbosity() > 0) std::cout << "Failed to get cluster with key " << key << " for track " << m_seedMap->find(track) << std::endl; - else std::cout<< "PHActsTrkFitter :: Key: "<< key << " for track " << m_seedMap->find(track) <find(track) < 0) + { + std::cout << " zinit " << global[2] << " xinit " << global[0] << " yinit " << global[1] << " side " << side << " crossing " << crossing + << " cluskey " << key << " subsurfkey " << subsurfkey << std::endl; + } + // add the global positions to a vector to give to the cluster mover global_raw.push_back(std::make_pair(key, global)); @@ -628,9 +627,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( TrkrDefs::cluskey cluskey = global_moved[i].first; Acts::Vector3 global = global_moved[i].second; - if(m_ignoreLayer.find(TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end() - or - (m_fitSiliconMMs && TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId)) + if(m_ignoreLayer.find(TrkrDefs::getLayer(cluskey)) != m_ignoreLayer.end()) { if(Verbosity() > 3) { @@ -675,7 +672,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( localPos(1) = loct(1); } - if(Verbosity() > 1) + if(Verbosity() > 0) { std::cout << " cluster global after mover: " << global << std::endl; std::cout << " cluster local X " << cluster->getLocalX() << " cluster local Y " << cluster->getLocalY() << std::endl; @@ -734,10 +731,9 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks( << std::endl; } - - sourcelinks.push_back(sl); - measurements.push_back(meas); - + sourcelinks.push_back(sl); + measurements.push_back(meas); + } SLTrackTimer.stop(); @@ -825,10 +821,108 @@ bool PHActsTrkFitter::getTrackFitResult(const FitResult &fitOutput, SvtxTrack* t ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( const std::vector>& sourceLinks, const ActsTrackFittingAlgorithm::TrackParameters& seed, - const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, + const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, + const SurfacePtrVec& surfSequence, std::shared_ptr& mtj) { - return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, mtj); + if(m_fitSiliconMMs) + { + return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, mtj); + } else { + return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, mtj); + } +} + +SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, + SurfacePtrVec& surfaces) const +{ + SourceLinkVec siliconMMSls; + +// if(Verbosity() > 1) +// std::cout << "Sorting " << sourceLinks.size() << " SLs" << std::endl; + + for(const auto& sl : sourceLinks) + { + if(Verbosity() > 1) + { std::cout << "SL available on : " << sl.geometryId() << std::endl; } + + const auto surf = m_tGeometry->geometry().tGeometry->findSurface(sl.geometryId()); + // skip TPC surfaces + if( m_tGeometry->maps().isTpcSurface( surf ) ) continue; + + // also skip micromegas surfaces if not used + if( m_tGeometry->maps().isMicromegasSurface( surf ) && !m_useMicromegas ) continue; + + // update vectors + siliconMMSls.push_back(sl); + surfaces.push_back(surf); + } + + /// Surfaces need to be sorted in order, i.e. from smallest to + /// largest radius extending from target surface + /// Add a check to ensure this + if(!surfaces.empty()) + { checkSurfaceVec(surfaces); } + + if(Verbosity() > 1) + { + for(const auto& surf : surfaces) + { + std::cout << "Surface vector : " << surf->geometryId() << std::endl; + } + } + + return siliconMMSls; +} + +void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec &surfaces) const +{ + for(int i = 0; i < surfaces.size() - 1; i++) + { + const auto& surface = surfaces.at(i); + const auto thisVolume = surface->geometryId().volume(); + const auto thisLayer = surface->geometryId().layer(); + + const auto nextSurface = surfaces.at(i+1); + const auto nextVolume = nextSurface->geometryId().volume(); + const auto nextLayer = nextSurface->geometryId().layer(); + + /// Implement a check to ensure surfaces are sorted + if(nextVolume == thisVolume) + { + if(nextLayer < thisLayer) + { + std::cout + << "PHActsTrkFitter::checkSurfaceVec - " + << "Surface not in order... removing surface" + << surface->geometryId() << std::endl; + + surfaces.erase(surfaces.begin() + i); + + /// Subtract one so we don't skip a surface + --i; + continue; + } + + } else { + + if(nextVolume < thisVolume) + { + std::cout + << "PHActsTrkFitter::checkSurfaceVec - " + << "Volume not in order... removing surface" + << surface->geometryId() << std::endl; + + surfaces.erase(surfaces.begin() + i); + + /// Subtract one so we don't skip a surface + --i; + continue; + + } + } + } + } void PHActsTrkFitter::updateSvtxTrack(Trajectory traj, SvtxTrack* track) @@ -1009,6 +1103,20 @@ int PHActsTrkFitter::createNodes(PHCompositeNode* topNode) dstNode->addNode(svtxNode); } + if(m_fitSiliconMMs) + { + m_directedTrackMap = findNode::getClass(topNode, + "SvtxSiliconMMTrackMap"); + if(!m_directedTrackMap) + { + /// Copy this trackmap, then use it for the rest of processing + m_directedTrackMap = new SvtxTrackMap_v2; + + PHIODataNode *trackNode = + new PHIODataNode(m_directedTrackMap,"SvtxSiliconMMTrackMap","PHObject"); + svtxNode->addNode(trackNode); + } + } m_trajectories = findNode::getClass>(topNode, "ActsTrajectories"); if(!m_trajectories) @@ -1037,24 +1145,6 @@ int PHActsTrkFitter::createNodes(PHCompositeNode* topNode) svtxNode->addNode(node); } - if(m_fitSiliconMMs) - { - m_silmmTrackMap = findNode::getClass(topNode, - "SvtxSiliconMMTrackMap"); - - if(!m_silmmTrackMap) - { - /// Copy this trackmap, then use it for the rest of processing - m_silmmTrackMap = new SvtxTrackMap_v2; - - PHIODataNode *trackNode = - new PHIODataNode(m_silmmTrackMap, - "SvtxSiliconMMTrackMap", - "PHObject"); - svtxNode->addNode(trackNode); - } - } - if(m_actsEvaluator) { m_seedTracks = findNode::getClass(topNode,_seed_track_map_name); diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 2360253243..6d97e75c02 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -80,6 +80,10 @@ class PHActsTrkFitter : public SubsysReco void fitSiliconMMs(bool fitSiliconMMs) {m_fitSiliconMMs = fitSiliconMMs;} + /// require micromegas in SiliconMM fits + void setUseMicromegas( bool value ) + { m_useMicromegas = value; } + void setUpdateSvtxTrackStates(bool fillSvtxTrackStates) { m_fillSvtxTrackStates = fillSvtxTrackStates; } @@ -130,15 +134,20 @@ class PHActsTrkFitter : public SubsysReco const ActsTrackFittingAlgorithm::TrackParameters& seed, const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, + const SurfacePtrVec& surfSequence, std::shared_ptr& mtj); + /// Functions to get list of sorted surfaces for direct navigation, if + /// applicable + SourceLinkVec getSurfaceVector(const SourceLinkVec& sourceLinks, + SurfacePtrVec& surfaces) const; + void checkSurfaceVec(SurfacePtrVec& surfaces) const; + bool getTrackFitResult(const FitResult& fitOutput, SvtxTrack* track); Acts::BoundSymMatrix setDefaultCovariance() const; void printTrackSeed(const ActsTrackFittingAlgorithm::TrackParameters& seed) const; - bool checkMM(SourceLinkVec& sls); - /// Event counter int m_event = 0; @@ -151,7 +160,7 @@ class PHActsTrkFitter : public SubsysReco /// TrackMap containing SvtxTracks alignmentTransformationContainer *m_alignmentTransformationMap = nullptr; // added for testing purposes SvtxTrackMap *m_trackMap = nullptr; - SvtxTrackMap *m_silmmTrackMap = nullptr; + SvtxTrackMap *m_directedTrackMap = nullptr; TrkrClusterContainer *m_clusterContainer = nullptr; TrackSeedContainer *m_seedMap = nullptr; TrackSeedContainer *m_tpcSeeds = nullptr; @@ -164,6 +173,9 @@ class PHActsTrkFitter : public SubsysReco /// Acts::DirectedNavigator with a list of sorted silicon+MM surfaces bool m_fitSiliconMMs = false; + /// requires micromegas present when fitting silicon-MM surfaces + bool m_useMicromegas = true; + /// A bool to update the SvtxTrackState information (or not) bool m_fillSvtxTrackStates = true; From fd0579ba65a7be9ea7fe7975b178902502d96430 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 4 Apr 2023 15:29:28 -0400 Subject: [PATCH 105/468] clang-format --- .../g4simulation/g4tpc/PHG4TpcDigitizer.cc | 677 +++++++++--------- 1 file changed, 337 insertions(+), 340 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index 007b182fc9..c8b242fc88 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,7 @@ int PHG4TpcDigitizer::InitRun(PHCompositeNode *topNode) // The noise is by definition the RMS noise width voltage divided by ChargeToPeakVolts ADCNoiseConversionGain = ChargeToPeakVolts * 1.60e-04; // 20 (or 30) mV/fC * fC/electron - ADCThreshold_mV = ADCThreshold * ADCNoiseConversionGain; + ADCThreshold_mV = ADCThreshold * ADCNoiseConversionGain; //------------- // Add Hit Node @@ -170,28 +171,28 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // Thus a MIP produces a charge value out of the GEM stack of 64000/6.242x10^18 = 10.2 fC // SAMPA: - // See https://indico.cern.ch/event/489996/timetable/#all.detailed + // See https://indico.cern.ch/event/489996/timetable/#all.detailed // "SAMPA Chip: the New ASIC for the ALICE Tpc and MCH Upgrades", M Bregant // The SAMPA has a maximum output voltage of 2200 mV (but the pedestal is about 200 mV) // The SAMPA shaper is set to 80 ns peaking time // The ADC Digitizes the SAMPA shaper output into 1024 channels - // Conversion gains of 20 mV/fC or 30 mV/fC are possible - 1 fC charge input produces a peak voltage out of + // Conversion gains of 20 mV/fC or 30 mV/fC are possible - 1 fC charge input produces a peak voltage out of // the shaper of 20 or 30 mV // At 30 mV/fC, the input signal saturates at 2.2 V / 30 mV/fC = 73 fC (say 67 with pedestal not at zero) // At 20 mV/fC, the input signal saturates at 2.2 V / 20 mV/fC = 110 fC (say 100 fC with pedestal not at zero) - assume 20 mV/fC // The equivalent noise charge RMS at 20 mV/fC was measured (w/o detector capacitance) at 490 electrons - // - note: this appears to be just the pedestal RMS voltage spread divided by the conversion gain, so it is a bit of a + // - note: this appears to be just the pedestal RMS voltage spread divided by the conversion gain, so it is a bit of a // funny number (see below) // - it is better to think of noise and signal in terms of voltage at the input of the ADC // Bregant's slides say 670 electrons ENC for the full chip with 18 pf detector, as in ALICE - should use that number // Signal: - // To normalize the signal in each cell, take the entire charge on the pad and multiply by 20 mV/fC to get the adc + // To normalize the signal in each cell, take the entire charge on the pad and multiply by 20 mV/fC to get the adc // input AT THE PEAK of the shaper // The cell contents should thus be multipied by the normalization given by: // V_peak = Q_pad (electrons) * 1.6e-04 fC/electron * 20 mV/fC // From the sims, for 80 ns and 18.8 MHz, if we take the input charge and spread it a across the shaping time (which is how it has always been done, and is - // not the best way to think about it, because the ADC does not see charge it sees voltage out of a charge integrating + // not the best way to think about it, because the ADC does not see charge it sees voltage out of a charge integrating // preamp followed by a shaper), to get // the voltage at the ADC input right, then the values of Q_(pad,z) have to be scaled up by 2.4 // V_(pad,z) = 2.4 * Q_(pad,z) (electrons) * 1.6e-04 fC/electron * 20 mV/fC = Q_(pad,z) * 7.68e-03 (in mV) @@ -199,17 +200,17 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // Remember that Q_(pad,z) is the GEM output charge // Noise: - // The ENC is defined as the RMS spread of the ADC pedestal distribution coming out from the SAMPA + // The ENC is defined as the RMS spread of the ADC pedestal distribution coming out from the SAMPA // divided by the corresponding conversion gain. // The full range of the ADC input is 2.2V (which will become 1024 adc counts, i.e. 1024 ADU's). // If you see the RMS of the pedestal in adc counts as 1 at the gain of 20mV/fC, the ENC would be defined by: // (2200 [mV]) * (1/1024) / (20[mV/fC]) / (1.6*10^-4 [fC]) = 671 [electrons] - // The RMS noise voltage would be: + // The RMS noise voltage would be: // V_RMS = ENC (electrons) *1.6e-04 fC/electron * 20 mV/fC = ENC (electrons) * 3.2e-03 (in mV) // The ADC readout would be: ADU = V_RMS * (1024 ADU / 2200 mV) = V_RMS * 0.465 // The cells that we need to digitize here contain as the energy "edep", which is the number of electrons out of the GEM stack - // distributed over the pads and ADC time bins according to the output time distribution of the SAMPA shaper + // distributed over the pads and ADC time bins according to the output time distribution of the SAMPA shaper // - not what really happens, see above // We convert to volts at the input to the ADC and add noise generated with the RMS value of the noise voltage at the ADC input // We assume the pedestal is zero, for simplicity, so the noise fluctuates above and below zero @@ -243,352 +244,348 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) exit(1); } - //------------- // Digitization //------------- - // Loop over all TPC layers - for(unsigned int layer = TpcMinLayer; layer < TpcMinLayer+TpcNLayers; ++layer) + // Loop over all TPC layers + for (unsigned int layer = TpcMinLayer; layer < TpcMinLayer + TpcNLayers; ++layer) + { + // we need the geometry object for this layer + PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); + if (!layergeom) exit(1); + + int nphibins = layergeom->get_phibins(); + if (Verbosity() > 1) + std::cout << " nphibins " << nphibins << std::endl; + + for (unsigned int side = 0; side < 2; ++side) { - // we need the geometry object for this layer - PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); - if (!layergeom) exit(1); - - int nphibins = layergeom->get_phibins(); - if(Verbosity() > 1) - std::cout << " nphibins " << nphibins << std::endl; - - for(unsigned int side = 0; side < 2; ++side) - { - - if(Verbosity() > 1) - std::cout << "TPC layer " << layer << " side " << side << std::endl; - - // for this layer and side, use a vector of a vector of cells for each phibin - phi_sorted_hits.clear(); - for (int iphi = 0; iphi < nphibins; iphi++) - { - phi_sorted_hits.push_back(std::vector()); - } - - // TODO: edit with new hit container - // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin - TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId, layer); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; - hitset_iter != hitset_range.second; - ++hitset_iter) - { - - // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer - // get the hitset key - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - unsigned int this_side = TpcDefs::getSide(hitsetkey); - // skip this hitset if it is not on this side - if(this_side != side) continue; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "new: PHG4TpcDigitizer: processing signal hits for layer " << layer - << " hitsetkey " << hitsetkey << " side " << side << std::endl; - - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - // Fill the vector of signal hits for each phibin - unsigned int phibin = TpcDefs::getPad(hit_iter->first); - phi_sorted_hits[phibin].push_back(hit_iter); - } - // For this hitset we now have the signal hits sorted into vectors for each phi - } - - // Process one phi bin at a time - if(Verbosity() > 1) std::cout << " phi_sorted_hits size " << phi_sorted_hits.size() << std::endl; - for (unsigned int iphi = 0; iphi < phi_sorted_hits.size(); iphi++) - { - // Make a fixed length vector to indicate whether each time bin is signal or noise - int ntbins = layergeom->get_zbins(); - is_populated.clear(); - is_populated.assign(ntbins, 2); // mark all as noise only, for now - - // add an empty vector of hits for each t bin - t_sorted_hits.clear(); - for (int it = 0; it < ntbins; it++) - { - t_sorted_hits.push_back(std::vector()); - } - - // add a signal hit from phi_sorted_hits for each t bin that has one - for (unsigned int it = 0; it < phi_sorted_hits[iphi].size(); it++) - { - int tbin = TpcDefs::getTBin(phi_sorted_hits[iphi][it]->first); - is_populated[tbin] = 1; // this bin is a associated with a hit - t_sorted_hits[tbin].push_back(phi_sorted_hits[iphi][it]); - - if (Verbosity() > 2) - if (layer == print_layer) - { - TrkrDefs::hitkey hitkey = phi_sorted_hits[iphi][it]->first; - std::cout << "iphi " << iphi << " adding existing signal hit to t vector for layer " << layer - << " side " << side - << " tbin " << tbin << " hitkey " << hitkey - << " pad " << TpcDefs::getPad(hitkey) - << " t bin " << TpcDefs::getTBin(hitkey) - << " energy " << (phi_sorted_hits[iphi][it]->second)->getEnergy() - << std::endl; - } - } - - adc_input.clear(); - adc_hitid.clear(); - // initialize entries to zero for each t bin - adc_input.assign(ntbins, 0.0); - adc_hitid.assign(ntbins, 0); - - // Now for this phibin we process all bins ordered by t into hits with noise - //====================================================== - // For this step we take the edep value and convert it to mV at the ADC input - // See comments above for how to do this for signal and noise - - for (int it = 0; it < ntbins; it++) - { - if (is_populated[it] == 1) - { - // This tbin has a hit, add noise - float signal_with_noise = add_noise_to_bin( (t_sorted_hits[it][0]->second)->getEnergy()) ; - adc_input[it] = signal_with_noise ; - adc_hitid[it] = t_sorted_hits[it][0]->first; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "existing signal hit: layer " << layer << " iphi " << iphi << " it " << it - << " edep " << (t_sorted_hits[it][0]->second)->getEnergy() - << " adc gain " << ADCSignalConversionGain - << " signal with noise " << signal_with_noise - << " adc_input " << adc_input[it] << std::endl; - } - else if (is_populated[it] == 2) - { - if(!skip_noise) - { - // This t bin does not have a filled cell, add noise - float noise = add_noise_to_bin(0.0); - adc_input[it]= noise; - adc_hitid[it] = 0; // there is no hit, just add a placeholder in the vector for now, replace it later - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "noise hit: layer " << layer << " side " << side << " iphi " << iphi << " it " << it - << " adc gain " << ADCSignalConversionGain - << " noise " << noise - << " adc_input " << adc_input[it] << std::endl; - } - } - else - { - // Cannot happen - std::cout << "Impossible value of is_populated, it = " << it - << " is_populated = " << is_populated[it] << std::endl; - exit(-1); - } - } - - // Now we can digitize the entire stream of t bins for this phi bin - int binpointer = 0; - - // Since we now store the local z of the hit as time of arrival at the readout plane, - // there is no difference between north and south - // The first to arrive is always bin 0 - - for (int it = 0; it < ntbins; it++) - { - if (it < binpointer) continue; - - // optionally do not trigger on bins with no signal - if( (is_populated[it] == 2) && skip_noise) - { - binpointer++; - continue; - } - - // convert threshold in "equivalent electrons" to mV - if (adc_input[it] > ADCThreshold_mV) - { - // digitize this bin and the following 4 bins - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << std::endl - << "Hit above threshold of " - << ADCThreshold * ADCNoiseConversionGain << " for phibin " << iphi - << " it " << it << " with adc_input " << adc_input[it] - << " digitize this and 4 following bins: " << std::endl; - - for (int itup = 0; itup < 5; itup++) - { - if (it + itup < ntbins && it + itup >= 0) // stay within the bin limits - { - float input = 0; - if( (is_populated[it+itup] == 2) && skip_noise) - { - input = add_noise_to_bin(0.0); // no noise added to this bin previously because skip_noise is true - } - else - { - input = adc_input[it + itup]; - } - // input voltage x 1024 channels over 2200 mV max range - unsigned int adc_output = (unsigned int) (input * 1024.0 / 2200.0); - - if (input < 0) adc_output = 0; - if (input > 1023) adc_output = 1023; - - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it + itup); - TrkrHit *hit = nullptr; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << " Digitizing: iphi " << iphi << " it+itup " << it + itup - << " adc_hitid " << adc_hitid[it + itup] - << " is_populated " << is_populated[it + itup] - << " adc_input " << adc_input[it + itup] - << " ADCThreshold " << ADCThreshold * ADCNoiseConversionGain - << " adc_output " << adc_output - << " hitkey " << hitkey - << " side " << side - << " binpointer " << binpointer - << std::endl; - - if (is_populated[it+itup] == 1) - { - // this is a signal hit, it already exists - hit = t_sorted_hits[it+itup][0]->second; // pointer valid only for signal hits - } - else - { - // Hit does not exist yet, have to make one - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto hitset_iter = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); - - hit = new TrkrHitv2(); - hitset_iter->second->addHitSpecificKey(hitkey, hit); - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << " adding noise TrkrHit for iphi " << iphi - << " tbin " << it + itup - << " side " << side - << " created new hit with hitkey " << hitkey - << " energy " << adc_input[it + itup] << " adc " << adc_output - << " binpointer " << binpointer - << std::endl; - - } - - hit->setAdc(adc_output); - - } // end boundary check - binpointer++; // skip this bin in future - } // end itup loop - - } // adc threshold if - else - { - // set adc value to zero if there is a hit - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto hitset = trkrhitsetcontainer->findHitSet(hitsetkey); - if(hitset) - { - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); - TrkrHit *hit = nullptr; - hit = hitset->getHit(hitkey); - if (hit) - { - hit->setAdc(0); - } - } - // bin below threshold, move on - binpointer++; - } // end adc threshold if/else - } // end time bin loop - } // end phibins loop - } // end loop over sides - } // end loop over TPC layers - + if (Verbosity() > 1) + std::cout << "TPC layer " << layer << " side " << side << std::endl; + + // for this layer and side, use a vector of a vector of cells for each phibin + phi_sorted_hits.clear(); + for (int iphi = 0; iphi < nphibins; iphi++) + { + phi_sorted_hits.push_back(std::vector()); + } + + // TODO: edit with new hit container + // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin + TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId, layer); + for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; + hitset_iter != hitset_range.second; + ++hitset_iter) + { + // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer + // get the hitset key + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; + unsigned int this_side = TpcDefs::getSide(hitsetkey); + // skip this hitset if it is not on this side + if (this_side != side) continue; + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << "new: PHG4TpcDigitizer: processing signal hits for layer " << layer + << " hitsetkey " << hitsetkey << " side " << side << std::endl; + + // get all of the hits from this hitset + TrkrHitSetTpc *hitset = dynamic_cast( hitset_iter->second ); + TrkrHitSet::ConstRange hit_range = hitset->getHits(); + for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; + hit_iter != hit_range.second; + ++hit_iter) + { + // Fill the vector of signal hits for each phibin + unsigned int phibin = TpcDefs::getPad(hit_iter->first); + phi_sorted_hits[phibin].push_back(hit_iter); + } + // For this hitset we now have the signal hits sorted into vectors for each phi + } + + // Process one phi bin at a time + if (Verbosity() > 1) std::cout << " phi_sorted_hits size " << phi_sorted_hits.size() << std::endl; + for (unsigned int iphi = 0; iphi < phi_sorted_hits.size(); iphi++) + { + // Make a fixed length vector to indicate whether each time bin is signal or noise + int ntbins = layergeom->get_zbins(); + is_populated.clear(); + is_populated.assign(ntbins, 2); // mark all as noise only, for now + + // add an empty vector of hits for each t bin + t_sorted_hits.clear(); + for (int it = 0; it < ntbins; it++) + { + t_sorted_hits.push_back(std::vector()); + } + + // add a signal hit from phi_sorted_hits for each t bin that has one + for (unsigned int it = 0; it < phi_sorted_hits[iphi].size(); it++) + { + int tbin = TpcDefs::getTBin(phi_sorted_hits[iphi][it]->first); + is_populated[tbin] = 1; // this bin is a associated with a hit + t_sorted_hits[tbin].push_back(phi_sorted_hits[iphi][it]); + + if (Verbosity() > 2) + if (layer == print_layer) + { + TrkrDefs::hitkey hitkey = phi_sorted_hits[iphi][it]->first; + std::cout << "iphi " << iphi << " adding existing signal hit to t vector for layer " << layer + << " side " << side + << " tbin " << tbin << " hitkey " << hitkey + << " pad " << TpcDefs::getPad(hitkey) + << " t bin " << TpcDefs::getTBin(hitkey) + << " energy " << (phi_sorted_hits[iphi][it]->second)->getEnergy() + << std::endl; + } + } + + adc_input.clear(); + adc_hitid.clear(); + // initialize entries to zero for each t bin + adc_input.assign(ntbins, 0.0); + adc_hitid.assign(ntbins, 0); + + // Now for this phibin we process all bins ordered by t into hits with noise + //====================================================== + // For this step we take the edep value and convert it to mV at the ADC input + // See comments above for how to do this for signal and noise + + for (int it = 0; it < ntbins; it++) + { + if (is_populated[it] == 1) + { + // This tbin has a hit, add noise + float signal_with_noise = add_noise_to_bin((t_sorted_hits[it][0]->second)->getEnergy()); + adc_input[it] = signal_with_noise; + adc_hitid[it] = t_sorted_hits[it][0]->first; + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << "existing signal hit: layer " << layer << " iphi " << iphi << " it " << it + << " edep " << (t_sorted_hits[it][0]->second)->getEnergy() + << " adc gain " << ADCSignalConversionGain + << " signal with noise " << signal_with_noise + << " adc_input " << adc_input[it] << std::endl; + } + else if (is_populated[it] == 2) + { + if (!skip_noise) + { + // This t bin does not have a filled cell, add noise + float noise = add_noise_to_bin(0.0); + adc_input[it] = noise; + adc_hitid[it] = 0; // there is no hit, just add a placeholder in the vector for now, replace it later + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << "noise hit: layer " << layer << " side " << side << " iphi " << iphi << " it " << it + << " adc gain " << ADCSignalConversionGain + << " noise " << noise + << " adc_input " << adc_input[it] << std::endl; + } + } + else + { + // Cannot happen + std::cout << "Impossible value of is_populated, it = " << it + << " is_populated = " << is_populated[it] << std::endl; + exit(-1); + } + } + + // Now we can digitize the entire stream of t bins for this phi bin + int binpointer = 0; + + // Since we now store the local z of the hit as time of arrival at the readout plane, + // there is no difference between north and south + // The first to arrive is always bin 0 + + for (int it = 0; it < ntbins; it++) + { + if (it < binpointer) continue; + + // optionally do not trigger on bins with no signal + if ((is_populated[it] == 2) && skip_noise) + { + binpointer++; + continue; + } + + // convert threshold in "equivalent electrons" to mV + if (adc_input[it] > ADCThreshold_mV) + { + // digitize this bin and the following 4 bins + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << std::endl + << "Hit above threshold of " + << ADCThreshold * ADCNoiseConversionGain << " for phibin " << iphi + << " it " << it << " with adc_input " << adc_input[it] + << " digitize this and 4 following bins: " << std::endl; + + for (int itup = 0; itup < 5; itup++) + { + if (it + itup < ntbins && it + itup >= 0) // stay within the bin limits + { + float input = 0; + if ((is_populated[it + itup] == 2) && skip_noise) + { + input = add_noise_to_bin(0.0); // no noise added to this bin previously because skip_noise is true + } + else + { + input = adc_input[it + itup]; + } + // input voltage x 1024 channels over 2200 mV max range + unsigned int adc_output = (unsigned int) (input * 1024.0 / 2200.0); + + if (input < 0) adc_output = 0; + if (input > 1023) adc_output = 1023; + + // Get the hitkey + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it + itup); + TrkrHit *hit = nullptr; + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << " Digitizing: iphi " << iphi << " it+itup " << it + itup + << " adc_hitid " << adc_hitid[it + itup] + << " is_populated " << is_populated[it + itup] + << " adc_input " << adc_input[it + itup] + << " ADCThreshold " << ADCThreshold * ADCNoiseConversionGain + << " adc_output " << adc_output + << " hitkey " << hitkey + << " side " << side + << " binpointer " << binpointer + << std::endl; + + if (is_populated[it + itup] == 1) + { + // this is a signal hit, it already exists + hit = t_sorted_hits[it + itup][0]->second; // pointer valid only for signal hits + } + else + { + // Hit does not exist yet, have to make one + // we need the hitset key, requires (layer, sector, side) + unsigned int sector = 12 * iphi / nphibins; + TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); + auto hitset_iter = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); + + hit = new TrkrHitv2(); + hitset_iter->second->addHitSpecificKey(hitkey, hit); + + if (Verbosity() > 2) + if (layer == print_layer) + std::cout << " adding noise TrkrHit for iphi " << iphi + << " tbin " << it + itup + << " side " << side + << " created new hit with hitkey " << hitkey + << " energy " << adc_input[it + itup] << " adc " << adc_output + << " binpointer " << binpointer + << std::endl; + } + + hit->setAdc(adc_output); + + } // end boundary check + binpointer++; // skip this bin in future + } // end itup loop + + } // adc threshold if + else + { + // set adc value to zero if there is a hit + // we need the hitset key, requires (layer, sector, side) + unsigned int sector = 12 * iphi / nphibins; + TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); + auto hitset = trkrhitsetcontainer->findHitSet(hitsetkey); + if (hitset) + { + // Get the hitkey + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); + TrkrHit *hit = nullptr; + hit = hitset->getHit(hitkey); + if (hit) + { + hit->setAdc(0); + } + } + // bin below threshold, move on + binpointer++; + } // end adc threshold if/else + } // end time bin loop + } // end phibins loop + } // end loop over sides + } // end loop over TPC layers + //====================================================== if (Verbosity() > 5) - { - std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end before cleaning:" << std::endl; - } + { + std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end before cleaning:" << std::endl; + } std::vector> delete_hitkey_list; - + // Clean up undigitized hits - we want all hitsets for the Tpc // This loop is pretty efficient because the remove methods all take a specified hitset as input TrkrHitSetContainer::ConstRange hitset_range_now = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range_now.first; hitset_iter != hitset_range_now.second; ++hitset_iter) + { + // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; + const unsigned int layer = TrkrDefs::getLayer(hitsetkey); + const int sector = TpcDefs::getSectorId(hitsetkey); + const int side = TpcDefs::getSide(hitsetkey); + if (Verbosity() > 5) + std::cout << "PHG4TpcDigitizer: hitset with key: " << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; + + // get all of the hits from this hitset + TrkrHitSet *hitset = hitset_iter->second; + TrkrHitSet::ConstRange hit_range = hitset->getHits(); + for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; + hit_iter != hit_range.second; + ++hit_iter) { - // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - const unsigned int layer = TrkrDefs::getLayer(hitsetkey); - const int sector = TpcDefs::getSectorId(hitsetkey); - const int side = TpcDefs::getSide(hitsetkey); + TrkrDefs::hitkey hitkey = hit_iter->first; + TrkrHit *tpchit = hit_iter->second; + if (Verbosity() > 5) - std::cout << "PHG4TpcDigitizer: hitset with key: " << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; - - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - TrkrDefs::hitkey hitkey = hit_iter->first; - TrkrHit *tpchit = hit_iter->second; - - if (Verbosity() > 5) - std::cout << " layer " << layer << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) - << " t bin " << TpcDefs::getTBin(hitkey) - << " adc " << tpchit->getAdc() << std::endl; - - if (tpchit->getAdc() == 0) - { - if (Verbosity() > 20) - { - std::cout << " -- this hit not digitized - delete it" << std::endl; - } - // screws up the iterator to delete it here, store the hitkey for later deletion - delete_hitkey_list.push_back(std::make_pair(hitsetkey, hitkey)); - } - } + std::cout << " layer " << layer << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) + << " t bin " << TpcDefs::getTBin(hitkey) + << " adc " << tpchit->getAdc() << std::endl; + + if (tpchit->getAdc() == 0) + { + if (Verbosity() > 20) + { + std::cout << " -- this hit not digitized - delete it" << std::endl; + } + // screws up the iterator to delete it here, store the hitkey for later deletion + delete_hitkey_list.push_back(std::make_pair(hitsetkey, hitkey)); + } } - + } + // delete all undigitized hits for (unsigned int i = 0; i < delete_hitkey_list.size(); i++) - { - TrkrHitSet *hitset = trkrhitsetcontainer->findHitSet(delete_hitkey_list[i].first); - const unsigned int layer = TrkrDefs::getLayer(delete_hitkey_list[i].first); - hitset->removeHit(delete_hitkey_list[i].second); - if (Verbosity() > 20) - if (layer == print_layer) - std::cout << "removed hit with hitsetkey " << delete_hitkey_list[i].first - << " and hitkey " << delete_hitkey_list[i].second << std::endl; - - // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map - //hittruthassoc->removeAssoc(delete_hitkey_list[i].first, delete_hitkey_list[i].second); // Slow! Commented out by ADF 9/6/2022 - } - + { + TrkrHitSet *hitset = trkrhitsetcontainer->findHitSet(delete_hitkey_list[i].first); + const unsigned int layer = TrkrDefs::getLayer(delete_hitkey_list[i].first); + hitset->removeHit(delete_hitkey_list[i].second); + if (Verbosity() > 20) + if (layer == print_layer) + std::cout << "removed hit with hitsetkey " << delete_hitkey_list[i].first + << " and hitkey " << delete_hitkey_list[i].second << std::endl; + + // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map + // hittruthassoc->removeAssoc(delete_hitkey_list[i].first, delete_hitkey_list[i].second); // Slow! Commented out by ADF 9/6/2022 + } + // Final hitset dump if (Verbosity() > 5) std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end after cleaning:" << std::endl; @@ -627,7 +624,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } - //hittruthassoc->identify(); + // hittruthassoc->identify(); return; } @@ -635,10 +632,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) float PHG4TpcDigitizer::add_noise_to_bin(float signal) { // add noise to the signal and return adc input voltage - float adc_input_voltage = signal * ADCSignalConversionGain; // mV, see comments above - float noise_voltage = ( Pedestal + added_noise() ) * ADCNoiseConversionGain; // mV - from definition of noise charge and pedestal charge + float adc_input_voltage = signal * ADCSignalConversionGain; // mV, see comments above + float noise_voltage = (Pedestal + added_noise()) * ADCNoiseConversionGain; // mV - from definition of noise charge and pedestal charge adc_input_voltage += noise_voltage; - + return adc_input_voltage; } From 4118c50f09242cca8fad3a7cf3088f2f4588eb20 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Tue, 4 Apr 2023 16:27:28 -0400 Subject: [PATCH 106/468] updated the tower info defs class to include EPD --- offline/packages/CaloBase/Makefile.am | 1 + offline/packages/CaloBase/TowerInfoDefs.cc | 524 +++++++++++++++++++++ offline/packages/CaloBase/TowerInfoDefs.h | 436 ++--------------- 3 files changed, 553 insertions(+), 408 deletions(-) create mode 100644 offline/packages/CaloBase/TowerInfoDefs.cc diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 42db43b099..5b5fe55826 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -113,6 +113,7 @@ libcalo_io_la_SOURCES = \ RawTowerGeomContainerv1.cc \ RawTowerGeomContainer_Cylinderv1.cc \ TowerInfov1.cc \ + TowerInfoDefs.cc \ TowerInfoContainerv1.cc # Rule for generating table CINT dictionaries. diff --git a/offline/packages/CaloBase/TowerInfoDefs.cc b/offline/packages/CaloBase/TowerInfoDefs.cc new file mode 100644 index 0000000000..e0edc6062c --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoDefs.cc @@ -0,0 +1,524 @@ +#include "TowerInfoDefs.h" +#include "RawTowerDefs.h" +#include +#include +#include +#include +#include +#include + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static const int emcadc[8][8] = { + {62, 60, 46, 44, 30, 28, 14, 12}, + {63, 61, 47, 45, 31, 29, 15, 13}, + {58, 56, 42, 40, 26, 24, 10, 8}, + {59, 57, 43, 41, 27, 25, 11, 9}, + {54, 52, 38, 36, 22, 20, 6, 4}, + {55, 53, 39, 37, 23, 21, 7, 5}, + {50, 48, 34, 32, 18, 16, 2, 0}, + {51, 49, 35, 33, 19, 17, 3, 1}}; + +static const int hcaladc[8][2] = { + {0, 1}, + {2, 3}, + {4, 5}, + {6, 7}, + {8, 9}, + {10, 11}, + {12, 13}, + {14, 15}}; +static const int epdchnlmap[16][2] = { + {0, 0}, + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, + {9, 10}, + {11, 12}, + {13, 14}, + {15, 16}, + {17, 18}, + {19, 20}, + {21, 22}, + {23, 24}, + {25, 26}, + {27, 28}, + {29, 30}}; + +static const int epd_phimap[31]={0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}; +static const int epd_rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + + +unsigned int TowerInfoDefs::encode_emcal(const unsigned int towerIndex) + { + + static int phimap[64]; + static int etamap[64]; + static int etabinoffset[4]; + static int ifirst = 1; + if (ifirst == 1) + { + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < 8; k++) + { + etamap[emcadc[j][k]] = j; + phimap[emcadc[j][k]] = k; + } + } + etabinoffset[0] = 24; + etabinoffset[1] = 0; + etabinoffset[2] = 48; + etabinoffset[3] = 72; + ifirst = 0; + } + const int channels_per_sector = 64; + const int supersector = 64 * 12; + const int nchannelsperpacket = 64 * 3; + const int maxphibin = 7; + const int maxetabin = 23; + int supersectornumber = towerIndex / supersector; + int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| + if (packet < 0 || packet > 3 ) + { + std::cout << "Attempting to access channel with invalid value in EMCal " << packet << std::endl; + exit(1); + } + int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; + int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; + int localphibin = phimap[interfaceboard_channel]; + if (packet == 0 || packet == 1) + { + localphibin = maxphibin - localphibin; + } + int localetabin = etamap[interfaceboard_channel]; + int packet_etabin = localetabin + 8 * interfaceboard; + if (packet == 0 || packet == 1) + { + packet_etabin = maxetabin - packet_etabin; + } + unsigned int globaletabin = packet_etabin + etabinoffset[packet]; + unsigned int globalphibin = localphibin + supersectornumber * 8; + unsigned int key = globalphibin + (globaletabin << 16U); + return key; + } + +unsigned int TowerInfoDefs::encode_emcal (const unsigned int etabin, const unsigned int phibin) + { + unsigned int key = phibin + (etabin << 16U); + return key; + } + + +unsigned int TowerInfoDefs::decode_emcal(const unsigned int tower_key) + { + const int etabinoffset[4] = {24,0,48,72}; + const int etabinmap[4] = {1,0,2,3}; + const int channels_per_sector = 64; + const int supersector = 64 * 12; + const int nchannelsperpacket = 64 * 3; + const int maxphibin = 7; + const int maxetabin = 23; + + unsigned int etabin = tower_key >> 16U; + unsigned int phibin = tower_key - (etabin << 16U); + int packet = etabinmap[(int) etabin / 24]; + int localetabin = etabin - etabinoffset[packet]; + int localphibin = phibin % 8; + int supersectornumber = phibin / 8; + int ib = 0; + if (packet == 0 || packet == 1) + { + localetabin = maxetabin - localetabin; + } + ib = localetabin / 8; + unsigned int index = 0; + if (packet == 0 || packet == 1) + { + localphibin = maxphibin - localphibin; + } + localetabin = localetabin % 8; + unsigned int localindex = emcadc[localetabin][localphibin]; + index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + return index; + } + + + + + + + + +unsigned int TowerInfoDefs::encode_hcal(const unsigned int towerIndex) + { + static int phimap[64]; + static int etamap[64]; + static int etabinoffset[4]; + static int phibinoffset[4]; + static int ifirst = 1; + if (ifirst == 1) + { + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < 2; k++) + { + etamap[hcaladc[j][k]] = j; + phimap[hcaladc[j][k]] = k; + + } + } + etabinoffset[0] = 0; + etabinoffset[1] = 8; + etabinoffset[2] = 16; + etabinoffset[3] = 0; + + + phibinoffset[0] = 0; + phibinoffset[1] = 8; + phibinoffset[2] = 16; + phibinoffset[3] = 0; + ifirst = 0; + } + + const int channels_per_sector = 16; + const int supersector = 16 * 4 * 3; + const int nchannelsperpacket = channels_per_sector * 4; + // const int etabinoffset[4] = {0,8,16,0}; + // const int phibinoffset[4] = {0,2,4,6}; + int supersectornumber = towerIndex / supersector; + int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| + if (packet < 0 || packet > 3 ) + { + std::cout << "Attempting to access channel with invalid value ih HCAL " << packet << std::endl; + exit(1); + } + int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; + int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; + int localphibin = phimap[interfaceboard_channel] + phibinoffset[interfaceboard]; + int localetabin = etamap[interfaceboard_channel]; + int packet_etabin = localetabin; + unsigned int globaletabin = packet_etabin + etabinoffset[packet]; + unsigned int globalphibin = localphibin + supersectornumber * 8; + unsigned int key = globalphibin + (globaletabin << 16U); + return key; + } + + // convert from etabin-phibin to key +unsigned int TowerInfoDefs::encode_hcal (const unsigned int etabin, const unsigned int phibin) + { + unsigned int key = phibin + (etabin << 16U); + return key; + } + + + +unsigned int TowerInfoDefs::decode_hcal(const unsigned int tower_key) + { + int channels_per_sector = 16; + int supersector = 16 * 4 * 3; + int nchannelsperpacket = channels_per_sector * 4; + int etabinoffset[3] = {0,8,16}; + int phibinoffset[4] = {0,2,4,6}; + unsigned int etabin = tower_key >> 16U; + unsigned int phibin = tower_key - (etabin << 16U); + int packet = etabin / 8; + int localetabin = etabin - etabinoffset[packet]; + int localphibin = phibin % 8; + int supersectornumber = phibin / 8; + int ib = localphibin / 2; + unsigned int index = 0; + localphibin = localphibin - phibinoffset[ib]; + unsigned int localindex = hcaladc[localetabin][localphibin]; + index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + return index; + } + + + // convert from calorimeter key to phi bin +unsigned int TowerInfoDefs::getCaloTowerPhiBin(const unsigned int key) + { + unsigned int etabin = key >> 16U; + unsigned int phibin = key - (etabin << 16U); + return phibin; + } + + // convert from calorimeter key to eta bin + unsigned int TowerInfoDefs::getCaloTowerEtaBin(const unsigned int key) + { + unsigned int etabin = key >> 16U; + return etabin; + } + + + + +unsigned int TowerInfoDefs::encode_epd(const unsigned int towerIndex) // convert from tower index to key + { + int channels_per_sector = 31; + int supersector = channels_per_sector * 12; + unsigned int supersectornumber = towerIndex / supersector; + int sector = ((towerIndex % supersector)) / channels_per_sector; + int channel = ((towerIndex % supersector)) % channels_per_sector; + unsigned int key = channel + (sector << 5U) + (supersectornumber << 9U); + return key; + } + +// convert from arm-rbin-phibin to key +unsigned int TowerInfoDefs::encode_epd (const unsigned int arm, const unsigned int rbin, const unsigned int phibin) +{ + if (rbin == 0 && phibin > 11) + { + std::cout << PHWHERE << " encode_epd invalid phibin value: " << phibin << " where max valid phibin is 11"<< std::endl; + gSystem->Exit(1); + } + + unsigned int sector = phibin/2; + if (rbin == 0) + { + sector = phibin; + } + + int channel = 0; + if (rbin != 0) + { + channel = epdchnlmap[rbin][phibin - 2 * sector]; + } + + unsigned int key = channel + (sector << 5U) + (arm << 9U); + return key; + } + + + +unsigned int TowerInfoDefs::decode_epd(const unsigned int tower_key) +{ + int channels_per_sector = 31; + int supersector = channels_per_sector * 12; + unsigned int ns_sector = tower_key >> 9U; + unsigned int sector = (tower_key - (ns_sector << 9U)) >> 5U; + unsigned int channel = tower_key - (ns_sector << 9U) - (sector << 5U); + unsigned int index = ns_sector * supersector + sector * channels_per_sector + channel; + return index; + } + + + + + + + // convert from epd key to arm bin +unsigned int TowerInfoDefs::get_epd_arm(unsigned int key) +{ + unsigned int arm = key >> 9U; + return arm; + } + //convert from epd key to sector number + unsigned int TowerInfoDefs::get_epd_sector(unsigned int key) + { + unsigned int arm = get_epd_arm(key); + unsigned int sector = (key - (arm << 9U) ) >> 5U; + return sector; + } + // convert from epd key to r bin + unsigned int TowerInfoDefs::get_epd_rbin(unsigned int key) + { + unsigned int arm = get_epd_arm(key); + unsigned int sector = get_epd_sector(key); + unsigned int channel = key - ( sector << 5U) - (arm << 9U); + unsigned int rbin = epd_rmap[channel]; + return rbin; + } + // convert from epd key to phi bin + unsigned int TowerInfoDefs::get_epd_phibin(unsigned int key) + { + unsigned int arm = get_epd_arm(key); + unsigned int rbin = get_epd_rbin(key); + unsigned int sector = get_epd_sector(key); + unsigned int channel = key - ( sector << 5U) - (arm << 9U); + unsigned int phibin = epd_phimap[channel] + 2*sector; + if (rbin == 0) + { + phibin = sector; + } + + return phibin; + } + + + + + + + + + + + +unsigned int TowerInfoDefs::encode_zdc(const unsigned int towerIndex) + { + if (towerIndex > 5) + { + std::cout << "Attempting to access zdc channel with invalid number " << towerIndex << std::endl; + exit(1); + } + // 3 bits: one for pos/neg z and 2 for the 3 modules + unsigned int key; + if(towerIndex==0) key = 0; + if(towerIndex==1) key = 1; + if(towerIndex==2) key = 2; + //negative side + if(towerIndex==3) {key = 1 << 2; key += 0;} + if(towerIndex==4) {key = 1 << 2; key += 1;} + if(towerIndex==5) {key = 1 << 2; key += 2;} + return key; + } + + + // convert from channel number to smd tower key + unsigned int TowerInfoDefs::encode_smd(const unsigned int towerIndex) + { + // 3 bits: one for pos/neg z and 2 for the 3 modules + if (towerIndex > 29) + { + std::cout << "Attempting to access smd channel with invalid number " << towerIndex << std::endl; + exit(1); + } + unsigned int Xpos[2] = {0,6}; + unsigned int Ypos[2] = {7,14}; + unsigned int Xneg[2] = {15,23}; + unsigned int Yneg[2] = {22,29}; + unsigned int xyBit = 0; + unsigned int fingerIndex; + unsigned int sideBit = 0; + if (towerIndex >= Xpos[0] && towerIndex <= Xpos[1] ) + { + xyBit = 0; + fingerIndex = towerIndex -Xpos[0]; + sideBit = 1; + } + if (towerIndex >= Ypos[0] && towerIndex <= Ypos[1] ) + { + xyBit = 1; + fingerIndex = towerIndex -Ypos[0]; + sideBit = 1; + } + if (towerIndex >= Xneg[0] && towerIndex <= Xneg[1] ) + { + xyBit = 0; + fingerIndex = towerIndex - Xneg[0]; + sideBit = 0; + } + if (towerIndex >= Yneg[0] && towerIndex <= Yneg[1] ) + { + xyBit = 1; + fingerIndex = towerIndex - Yneg[0]; + sideBit = 0; + } + unsigned int key = (sideBit << 4) + (xyBit << 3) + fingerIndex; + return key; + } + + + + +unsigned int TowerInfoDefs::decode_smd(const unsigned int key) + { + unsigned int index=999; + for (unsigned int i=0; i<30; i++) + { + if (encode_smd(i) == key) {index=i; break;} + } + return index; + } + + + // convert from zdc tower key to channel number +unsigned int TowerInfoDefs::decode_zdc(const unsigned int key) + { + unsigned int index=999; + for (unsigned int i=0; i<6; i++) + { + if (encode_zdc(i) == key) {index=i; break;} + } + return index; + } + + + + // convert from calorimeter key to zdc side +int TowerInfoDefs::get_zdc_side(const unsigned int key) + { + if (key&4) return 1; + if (!(key&4)) return -1; + return -999; + } + + // convert from calorimeter key to zdc module number +unsigned int TowerInfoDefs::get_zdc_module_index(const unsigned int key) + { + return key&3; + } + + // convert from calorimeter key to smd side + int TowerInfoDefs::get_smd_side(const unsigned int key) + { + if (key&(1<<4)) return 1; + if ( !(key&(1<<4)) ) return -1; + return -999; + } + // convert from calorimeter key to smd xy bin + int TowerInfoDefs::get_smd_xy(const unsigned int key) + { + if (key&(1<<3)) return 0; + if ( !(key&(1<<3)) ) return 1; + return -999; + } + // convert from calorimeter key to smd finger + int TowerInfoDefs::get_smd_finger_index(const unsigned int key) + { + return key&7; + } + + + + + + + + + + // convienent for interface to geometry class + RawTowerDefs::keytype TowerInfoDefs::get_emcal_geokey_at_channel(const unsigned int towerIndex) + { + unsigned int towerkey = encode_emcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, etabin, phibin); + return key; + } + + // convienent for interface to geometry class + RawTowerDefs::keytype TowerInfoDefs::get_hcalin_geokey_at_channel(const unsigned int towerIndex) + { + unsigned int towerkey = encode_hcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, etabin, phibin); + return key; + } + + // convienent for interface to geometry class + RawTowerDefs::keytype TowerInfoDefs::get_hcalout_geokey_at_channel(const unsigned int towerIndex) + { + unsigned int towerkey = encode_hcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, etabin, phibin); + return key; + } + +#pragma GCC diagnostic pop + diff --git a/offline/packages/CaloBase/TowerInfoDefs.h b/offline/packages/CaloBase/TowerInfoDefs.h index 1f3505f4aa..37dd163869 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.h +++ b/offline/packages/CaloBase/TowerInfoDefs.h @@ -2,430 +2,50 @@ #define CALOBASE_TOWERINFODEFS_H #include "RawTowerDefs.h" -#include -#include -#include -#include -/*! Namespace with functions to encode / decode calo information. - */ -int emcadc[8][8] = { - {62, 60, 46, 44, 30, 28, 14, 12}, - {63, 61, 47, 45, 31, 29, 15, 13}, - {58, 56, 42, 40, 26, 24, 10, 8}, - {59, 57, 43, 41, 27, 25, 11, 9}, - {54, 52, 38, 36, 22, 20, 6, 4}, - {55, 53, 39, 37, 23, 21, 7, 5}, - {50, 48, 34, 32, 18, 16, 2, 0}, - {51, 49, 35, 33, 19, 17, 3, 1}}; - -int hcaladc[8][2] = { - {0, 1}, - {2, 3}, - {4, 5}, - {6, 7}, - {8, 9}, - {10, 11}, - {12, 13}, - {14, 15}}; - - - -namespace TowerInfoDefs +namespace TowerInfoDefs { - // convert from tower index to key - inline unsigned int encode_emcal(const unsigned int towerIndex) - { - int phimap[64] = {0}; - int etamap[64] = {0}; - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 8; k++) - { - etamap[emcadc[j][k]] = j; - phimap[emcadc[j][k]] = k; - } - } - int channels_per_sector = 64; - int supersector = 64 * 12; - int nchannelsperpacket = 64 * 3; - int maxphibin = 7; - int maxetabin = 23; - int etabinoffset[4] = {24,0,48,72}; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << "Attempting to access channel with invalid value in EMCal " << packet << std::endl; - exit(1); - } - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel]; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin + 8 * interfaceboard; - if (packet == 0 || packet == 1) - { - packet_etabin = maxetabin - packet_etabin; - } - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); - return key; - } - - inline unsigned int encode_emcal (const unsigned int etabin, const unsigned int phibin) - { - unsigned int key = phibin + (etabin << 16U); - return key; - } - - // convert from tower index to hcal key - inline unsigned int encode_hcal(const unsigned int towerIndex) - { - int phimap[64] = {0}; - int etamap[64] = {0}; - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 2; k++) - { - etamap[hcaladc[j][k]] = j; - phimap[hcaladc[j][k]] = k; - } - } - int channels_per_sector = 16; - int supersector = 16 * 4 * 3; - int nchannelsperpacket = channels_per_sector * 4; - int etabinoffset[4] = {0,8,16,0}; - int phibinoffset[4] = {0,2,4,6}; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << "Attempting to access channel with invalid value ih HCAL " << packet << std::endl; - exit(1); - } - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel] + phibinoffset[interfaceboard]; - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin; - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); - return key; - } - - // convert from etabin-phibin to key - inline unsigned int encode_hcal (const unsigned int etabin, const unsigned int phibin) - { - unsigned int key = phibin + (etabin << 16U); - return key; - } - - // convert from channel index to EPD key - inline unsigned int encode_epd(const unsigned int towerIndex) // convert from tower index to key - { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int supersectornumber = towerIndex / supersector; - int sector = ((towerIndex % supersector)) / channels_per_sector; - int channel = ((towerIndex % supersector)) % channels_per_sector; - int rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; - int phimap_sepd[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; - unsigned int globalphi = phimap_sepd[channel] + 2 * sector; - unsigned int r = rmap[channel]; - unsigned int key = globalphi + (r << 10U) + (supersectornumber << 20U); - return key; - } - - // convert from arm-rbin-phibin to key - inline unsigned int encode_epd (const unsigned int arm, const unsigned int rbin, const unsigned int phibin) - { - unsigned int key = phibin + (rbin << 10U) + (arm << 20U); - return key; - } - - // convert from channel number to zdc tower key - inline unsigned int encode_zdc(const unsigned int towerIndex) - { - if (towerIndex > 5) - { - std::cout << "Attempting to access zdc channel with invalid number " << towerIndex << std::endl; - exit(1); - } - // 3 bits: one for pos/neg z and 2 for the 3 modules - - unsigned int key; - if(towerIndex==0) key = 0; - else if(towerIndex==1) key = 1; - else if(towerIndex==2) key = 2; - //negative side - else if(towerIndex==3) {key = 1 << 2; key += 0;} - else if(towerIndex==4) {key = 1 << 2; key += 1;} - else if(towerIndex==5) {key = 1 << 2; key += 2;} - return key; - } - - - // convert from channel number to smd tower key - inline unsigned int encode_smd(const unsigned int towerIndex) - { - // 3 bits: one for pos/neg z and 2 for the 3 modules - if (towerIndex > 29) - { - std::cout << "Attempting to access smd channel with invalid number " << towerIndex << std::endl; - exit(1); - } - unsigned int Xpos[2] = {0,6}; - unsigned int Ypos[2] = {7,14}; - unsigned int Xneg[2] = {15,23}; - unsigned int Yneg[2] = {22,29}; - unsigned int xyBit = 0; - unsigned int fingerIndex; - unsigned int sideBit = 0; - if (towerIndex >= Xpos[0] && towerIndex <= Xpos[1] ) - { - xyBit = 0; - fingerIndex = towerIndex -Xpos[0]; - sideBit = 1; - } - if (towerIndex >= Ypos[0] && towerIndex <= Ypos[1] ) - { - xyBit = 1; - fingerIndex = towerIndex -Ypos[0]; - sideBit = 1; - } - if (towerIndex >= Xneg[0] && towerIndex <= Xneg[1] ) - { - xyBit = 0; - fingerIndex = towerIndex - Xneg[0]; - sideBit = 0; - } - if (towerIndex >= Yneg[0] && towerIndex <= Yneg[1] ) - { - xyBit = 1; - fingerIndex = towerIndex - Yneg[0]; - sideBit = 0; - } - unsigned int key = (sideBit << 4) + (xyBit << 3) + fingerIndex; - return key; - } - - - // convert from smd tower key to channel number - inline unsigned int decode_smd(const unsigned int key) - { - unsigned int index=999; - for (unsigned int i=0; i<30; i++) - { - if (encode_smd(i) == key) {index=i; break;} - } - return index; - } - - - // convert from zdc tower key to channel number - inline unsigned int decode_zdc(const unsigned int key) - { - unsigned int index=999; - for (unsigned int i=0; i<6; i++) - { - if (encode_zdc(i) == key) {index=i; break;} - } - return index; - } - - - - // convert from EPD tower key to channel index - inline unsigned int decode_epd(const unsigned int tower_key) - { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int ns_sector = tower_key >> 20U; - unsigned int rbin = (tower_key - (ns_sector << 20U)) >> 10U; - unsigned int phibin = tower_key - (ns_sector << 20U) - (rbin << 10U); - int epdchnlmap[16][2] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24}, {25, 26}, {27, 28}, {29, 30}}; - int sector = phibin / 2; - int channel = 0; - if (rbin > 0) - { - channel = epdchnlmap[rbin][phibin - 2 * sector]; - } - else - { - channel = 0; - } - unsigned int index = 0; - index = ns_sector * supersector + sector * channels_per_sector + channel; - return index; - } - - - // convert from EMCAL tower key to channel index - inline unsigned int decode_emcal(const unsigned int tower_key) - { - int etabinoffset[4] = {0}; - int etabinmap[4] = {0}; - int channels_per_sector = 64; - int supersector = 64 * 12; - int nchannelsperpacket = 64 * 3; - int maxphibin = 7; - int maxetabin = 23; - etabinoffset[0] = 24; - etabinoffset[1] = 0; - etabinoffset[2] = 48; - etabinoffset[3] = 72; - - etabinmap[0] = 1; - etabinmap[1] = 0; - etabinmap[2] = 2; - etabinmap[3] = 3; - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabinmap[(int) etabin / 24]; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = 0; - if (packet == 0 || packet == 1) - { - localetabin = maxetabin - localetabin; - } - ib = localetabin / 8; - unsigned int index = 0; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - localetabin = localetabin % 8; - unsigned int localindex = emcadc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; - return index; - } - - // convert from HCAL tower key to channel index - inline unsigned int decode_hcal(const unsigned int tower_key) - { - int channels_per_sector = 16; - int supersector = 16 * 4 * 3; - int nchannelsperpacket = channels_per_sector * 4; - int etabinoffset[3] = {0,8,16}; - int phibinoffset[4] = {0,2,4,6}; - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabin / 8; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = localphibin / 2; - unsigned int index = 0; - localphibin = localphibin - phibinoffset[ib]; - unsigned int localindex = hcaladc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; - return index; - } - - // convert from calorimeter key to phi bin - inline unsigned int getCaloTowerPhiBin(const unsigned int key) - { - unsigned int etabin = key >> 16U; - unsigned int phibin = key - (etabin << 16U); - return phibin; - } - - // convert from calorimeter key to eta bin - inline unsigned int getCaloTowerEtaBin(const unsigned int key) - { - unsigned int etabin = key >> 16U; - return etabin; - } - - - - - - - // convert from calorimeter key to zdc side - inline int get_zdc_side(const unsigned int key) - { - if (key&4) return 1; - if (!(key&4)) return -1; - return -999; - } - - // convert from calorimeter key to zdc module number - inline unsigned int get_zdc_module_index(const unsigned int key) - { - return key&3; - } - - + unsigned int encode_emcal(const unsigned int towerIndex); + unsigned int encode_emcal (const unsigned int etabin, const unsigned int phibin); + unsigned int decode_emcal(const unsigned int tower_key); + unsigned int encode_hcal(const unsigned int towerIndex); + unsigned int encode_hcal (const unsigned int etabin, const unsigned int phibin); + unsigned int decode_hcal(const unsigned int tower_key); - // convert from calorimeter key to smd side - inline int get_smd_side(const unsigned int key) - { - if (key&(1<<4)) return 1; - if ( !(key&(1<<4)) ) return -1; - return -999; - } - // convert from calorimeter key to smd xy bin - inline int get_smd_xy(const unsigned int key) - { - if (key&(1<<3)) return 0; - if ( !(key&(1<<3)) ) return 1; - return -999; - } - // convert from calorimeter key to smd finger - inline int get_smd_finger_index(const unsigned int key) - { - return key&7; - } + unsigned int encode_epd(const unsigned int towerIndex); + unsigned int encode_epd (const unsigned int arm, const unsigned int rbin, const unsigned int phibin); + unsigned int decode_epd(const unsigned int tower_key); - // convienent for interface to geometry class - inline RawTowerDefs::keytype get_emcal_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_emcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, etabin, phibin); - return key; - } - // convienent for interface to geometry class - inline RawTowerDefs::keytype get_hcalin_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_hcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, etabin, phibin); - return key; - } + unsigned int get_epd_arm(unsigned int key); + unsigned int get_epd_sector(unsigned int key); + unsigned int get_epd_rbin(unsigned int key); + unsigned int get_epd_phibin(unsigned int key); + unsigned int getCaloTowerPhiBin(const unsigned int key); + unsigned int getCaloTowerEtaBin(const unsigned int key) ; - // convienent for interface to geometry class - inline RawTowerDefs::keytype get_hcalout_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_hcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, etabin, phibin); - return key; - } + int get_zdc_side(const unsigned int key) ; + unsigned int get_zdc_module_index(const unsigned int key); + int get_smd_side(const unsigned int key); + int get_smd_xy(const unsigned int key); + int get_smd_finger_index(const unsigned int key); + unsigned int encode_zdc(const unsigned int towerIndex); + unsigned int encode_smd(const unsigned int towerIndex); + unsigned int decode_smd(const unsigned int key); + unsigned int decode_zdc(const unsigned int key); + RawTowerDefs::keytype get_emcal_geokey_at_channel(const unsigned int towerIndex); + RawTowerDefs::keytype get_hcalin_geokey_at_channel(const unsigned int towerIndex) ; + RawTowerDefs::keytype get_hcalout_geokey_at_channel(const unsigned int towerIndex) ; From 5131eab25366a62f73694f3246f706d654bf7847 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 4 Apr 2023 16:32:35 -0400 Subject: [PATCH 107/468] Additional comments and cleaning up of CM Clusterizer and Matcher --- .../PHTpcCentralMembraneClusterizer.cc | 106 +--- .../PHTpcCentralMembraneClusterizer.h | 13 +- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 556 ++++-------------- .../tpccalib/PHTpcCentralMembraneMatcher.h | 39 +- .../g4tpc/PHG4TpcCentralMembrane.cc | 4 - .../g4tpc/PHG4TpcCentralMembrane.h | 10 - 6 files changed, 151 insertions(+), 577 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index 9289513cc8..2c662d73d0 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -74,13 +74,6 @@ int PHTpcCentralMembraneClusterizer::InitRun(PHCompositeNode *topNode) hDist2Adj=new TH1F("hDist2Adj","phi distance to nearby clusters on adjacent padrow;dist[rad]",100,-0.001,0.01); } - m_histogramfileMaps.reset( new TFile(m_histogramfilenameMaps.c_str(), "RECREATE")); - m_histogramfileMaps->cd(); - - - hrPhi_reco_pos = new TH2F("hrPhi_reco_pos","Reco R vs #phi Z > 0;#phi;R (cm)",400,-M_PI,M_PI,400,20,78); - hrPhi_reco_neg = new TH2F("hrPhi_reco_neg","Reco R vs #phi Z < 0;#phi;R (cm)",400,-M_PI,M_PI,400,20,78); - hrPhi_reco_petalModulo_pos = new TH2F("hrPhi_reco_petalModulo_pos","Reco R vs #phi Z > 0;#phi;R (cm)",50,0.0,M_PI/9,400,20,78); hrPhi_reco_petalModulo_neg = new TH2F("hrPhi_reco_petalModulo_neg","Reco R vs #phi;#phi Z < 0;R (cm)",50,0.0,M_PI/9,400,20,78); @@ -120,7 +113,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vectorisAcrossGap; int nTpcClust = 0; - + //first loop over clusters to make mod phi histograms of each layer and each pair of layers for(const auto& hitsetkey:_cluster_map->getHitSetKeys(TrkrDefs::TrkrId::tpcId)) { auto clusRange = _cluster_map->getClusters(hitsetkey); @@ -138,6 +131,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) double phiMod = phi; + //make sure phiMod is between 0 and pi/9 while(phiMod < 0.0 || phiMod > M_PI/9){ if(phiMod < 0.0) phiMod += M_PI/9; else if(phiMod > M_PI/9) phiMod -= M_PI/9; @@ -149,6 +143,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) hrPhi_reco_petalModulo_pos->Fill(phiMod, tmp_pos.Perp()); hphi_reco_pos[layer-7]->Fill(phiMod); + //for layer pairs, if last layer can only go in layer 53-54 pair, if first layer can only go in layer 7-8 pair if(layer < 54) hphi_reco_pair_pos[layer-7]->Fill(phiMod); if(layer > 7) hphi_reco_pair_pos[layer-8]->Fill(phiMod); }else{ @@ -157,6 +152,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) hrPhi_reco_petalModulo_neg->Fill(phiMod, tmp_pos.Perp()); hphi_reco_neg[layer-7]->Fill(phiMod); + //for layer pairs, if last layer can only go in layer 53-54 pair, if first layer can only go in layer 7-8 pair if(layer < 54) hphi_reco_pair_neg[layer-7]->Fill(phiMod); if(layer > 7) hphi_reco_pair_neg[layer-8]->Fill(phiMod); } @@ -164,7 +160,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } - + //loop over histos for each pair of layers, count number of bins above threshold + //for a given layer, layer pair with higher average value above threshold will be better match for meta-clustering for(int i=0; i<47; i++){ for(int j=1; jGetNbinsX(); j++){ if(hphi_reco_pair_pos[i]->GetBinContent(j) > m_metaClusterThreshold){ @@ -177,7 +174,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } } - + + + //loop over clusters again for(const auto& hitsetkey:_cluster_map->getHitSetKeys(TrkrDefs::TrkrId::tpcId)) { auto clusRange = _cluster_map->getClusters(hitsetkey); @@ -218,12 +217,13 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) bool aboveThreshold = true; + //Find which phiMod bin cluster is in (with given layer) and if counts below threshold don't use if(z >= 0){ phiBin = hphi_reco_pos[lay-7]->GetXaxis()->FindBin(phiMod); - if(hphi_reco_pos[lay-7]->GetBinContent(phiBin) < 5) aboveThreshold = false; + if(hphi_reco_pos[lay-7]->GetBinContent(phiBin) < m_moduloThreshold) aboveThreshold = false; }else{ phiBin = hphi_reco_neg[lay-7]->GetXaxis()->FindBin(phiMod); - if(hphi_reco_neg[lay-7]->GetBinContent(phiBin) < 5) aboveThreshold = false; + if(hphi_reco_neg[lay-7]->GetBinContent(phiBin) < m_moduloThreshold) aboveThreshold = false; } if( !aboveThreshold ) continue; @@ -231,15 +231,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(cluster->getAdc() < _min_adc_value) continue; if( std::abs(z) < _min_z_value) continue; + //require that z be within 1cm of peak in z distributions (separate for each side) if( (z>=0 && std::abs(z - hz_pos->GetBinCenter(hz_pos->GetMaximumBin())) > 1.0) || (z<0 && std::abs(z - hz_neg->GetBinCenter(hz_neg->GetMaximumBin())) > 1.0) ) continue; - // if(removeSector && TpcDefs::getSide(cluskey) > 0 && TpcDefs::getSectorId(cluskey) == 1 && TrkrDefs::getLayer(cluskey) < 38) continue; - if(removeSector && TpcDefs::getSide(cluskey) > 0 && TrkrDefs::getLayer(cluskey) < 38) continue; - - - if(z >= 0) hrPhi_reco_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - else hrPhi_reco_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - ++m_accepted_clusters; i_pair.push_back(-1); @@ -291,21 +285,24 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) { int layerMatch = -1; - - int nRowsMatch = 2; + int nRowsMatch = 2; if(layer[i] >= 39) nRowsMatch = 4; else if(layer[i] >= 23) nRowsMatch = 3; if( pos[i].Z() >= 0 ){ if(layer[i] == 7){ + //if layer is 7, can only get one layer match if(nPairAbove_pos[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; }else if(layer[i] == 54){ + //if layer is 8, can only get one layer match if(nPairAbove_pos[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; }else{ + //if both pairs of rows have enough bins above threshold, match to pair with higher average if(nPairAbove_pos[layer[i]-7] >= nRowsMatch && nPairAbove_pos[layer[i]-8] >= nRowsMatch){ if(pairAboveContent_pos[layer[i]-7]/nPairAbove_pos[layer[i]-7] > pairAboveContent_pos[layer[i]-8]/nPairAbove_pos[layer[i]-8]) layerMatch = layer[i]+1; else layerMatch = layer[i]-1; + //otherwise just use the one that is above threshold }else if(nPairAbove_pos[layer[i]-7] >= nRowsMatch) layerMatch = layer[i]+1; else if(nPairAbove_pos[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; } @@ -323,23 +320,23 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } - + //if the match is default and the layer is on the edge of a module, identify it as being across the gap if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39 || layer[i] == 7) ) isAcrossGap[i] = true; float bestphidist=maxphidist; for (int j=0;jget_radius(); PHG4TpcCylinderGeom *layergeom2 = _geom_container->GetLayerCellGeom(layer[i_pair[i]]); double rad2 = layergeom2->get_radius(); - // PHG4TpcCylinderGeom *layergeom0; + //matching done correctly now, so distance between layers should be directly calculable double layer_dr = std::abs(rad1 - rad2); - /* - if(layer[i] != 7 && layer[i] != 23 && layer[i] != 39) - { - layergeom0 = _geom_container->GetLayerCellGeom(layer[i]-1); - layer_dr = rad1 - layergeom0->get_radius(); - } - else - { - layergeom0 = _geom_container->GetLayerCellGeom(layer[i]+1); - layer_dr = layergeom0->get_radius() - rad1; - }*/ + double rad_lyr_boundary = rad1 + layer_dr / 2.0; @@ -462,17 +449,13 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if( _dcc) dist_pos = _distortionCorrection.get_corrected_position( dist_pos, _dcc ); double dist_r = sqrt(dist_pos[0]*dist_pos[0] + dist_pos[1] * dist_pos[1]); double cmclus_dr = _cmclus_dr_outer; - /* - if(dist_r < 41.0) - cmclus_dr = _cmclus_dr_inner; - else if(dist_r >= 41.0 && rad2 < 58.0) - cmclus_dr = _cmclus_dr_mid; - */ if(dist_r < 41.0){ + //if across boundary, use average if(rad2 >= 41.0) cmclus_dr = 0.5*(_cmclus_dr_inner + _cmclus_dr_mid); else cmclus_dr = _cmclus_dr_inner; }else if(dist_r >= 41.0 && dist_r < 58.0){ + //if across boundary, use average if(rad2 >= 58.0) cmclus_dr = 0.5*(_cmclus_dr_mid + _cmclus_dr_outer); else cmclus_dr = _cmclus_dr_mid; } @@ -499,9 +482,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } else { - std::cout << "singleton layer: " << layer[i] << " radius: " << pos[i].Perp() << " isAcrossGap? " << isAcrossGap[i] << std::endl; if(_histos) hClustE[2]->Fill(energy[i]); - // These single cluster cases have good phi, but do not have a good radius centroid estimate - may want to skip them, record nclusters + // These single cluster cases have good phi, but do not have a good radius centroid estimate - may want to skip them, record nclusters and identify if across gap if(layer[i] == 7) isAcrossGap[i] = true; aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); @@ -588,36 +570,6 @@ int PHTpcCentralMembraneClusterizer::End(PHCompositeNode * /*topNode*/ ) m_histogramfile->Close(); } - m_histogramfileMaps->cd(); - - hrPhi_reco_pos->SetMarkerStyle(20); - hrPhi_reco_pos->SetMarkerSize(0.25); - hrPhi_reco_pos->SetMarkerColor(kRed); - - hrPhi_reco_neg->SetMarkerStyle(20); - hrPhi_reco_neg->SetMarkerSize(0.25); - hrPhi_reco_neg->SetMarkerColor(kRed); - - hrPhi_reco_pos->Write(); - hrPhi_reco_neg->Write(); - - hrPhi_reco_petalModulo_pos->Write(); - hrPhi_reco_petalModulo_neg->Write(); - - for(int i=0; i<48; i++){ - hphi_reco_pos[i]->Write(); - hphi_reco_neg[i]->Write(); - - if(i<47){ - hphi_reco_pair_pos[i]->Write(); - hphi_reco_pair_neg[i]->Write(); - } - } - - m_histogramfileMaps->Close(); - - - // print statistics if( Verbosity() ) { diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h index 6b86b00756..0a5ff8db9e 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h @@ -45,8 +45,7 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco void set_min_z_value(const double val) {_min_z_value = val;} void set_stripe_dr_values(const double dr1, const double dr2, const double dr3){ _cmclus_dr_inner = dr1; _cmclus_dr_mid = dr2; _cmclus_dr_outer = dr3;} - void set_removeSector(bool a_removeSector){ removeSector = a_removeSector; } - + void set_modulo_threshold( int val ) { m_moduloThreshold = val; } void set_metaCluster_threshold( int val ) { m_metaClusterThreshold = val; } //! run initialization @@ -83,6 +82,7 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco int m_cm_clusters_size2 = 0; //@} + int m_moduloThreshold = 5; int m_metaClusterThreshold = 18; bool _histos = false; @@ -98,9 +98,6 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco TH1F *hDist2Adj = nullptr; TH1F *hClustE[3] = {nullptr}; - TH2F *hrPhi_reco_pos = nullptr; - TH2F *hrPhi_reco_neg = nullptr; - TH2F *hrPhi_reco_petalModulo_pos = nullptr; TH2F *hrPhi_reco_petalModulo_neg = nullptr; @@ -119,18 +116,12 @@ class PHTpcCentralMembraneClusterizer : public SubsysReco std::string m_histogramfilename = "PHTpcCentralMembraneClusterizer.root"; std::unique_ptr m_histogramfile; - - std::string m_histogramfilenameMaps = "CentralMembraneClusterizer_reco_maps.root"; - std::unique_ptr m_histogramfileMaps; - unsigned int _min_adc_value = 0; double _min_z_value = 0.0; double _cmclus_dr_inner = 0.51; //cm double _cmclus_dr_mid = 0.95; //cm double _cmclus_dr_outer = 1.025; //cm - bool removeSector = false; - }; #endif // PHTPCCENTRALMEMBRANECLUSTERIZER_H diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 6dc39073f6..74316d972c 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -167,103 +166,30 @@ std::vector PHTpcCentralMembraneMatcher::getRGaps( TH2F *r_phi ){ } */ +//get the average phi rotation using smoothed histograms double PHTpcCentralMembraneMatcher::getPhiRotation_smoothed(TH1D *hitHist, TH1D *clustHist){ - TCanvas *c1 = new TCanvas(); - - gStyle->SetOptFit(1); - + //smooth the truth and cluster histograms hitHist->Smooth(); clustHist->Smooth(); - TF1 *f1 = new TF1("f1",[&](double *x, double *p){ return p[0] * hitHist->GetBinContent(hitHist->FindBin(x[0] - p[1])); }, -M_PI, M_PI, 2); + //make a TF1 with a lambda function to make a function out of the truth histogram and shift it by a constant + TF1 *f1 = new TF1("f1",[&](double *x, double *p){ return p[0] * hitHist->GetBinContent(hitHist->FindBin((x[0] - p[1])>M_PI?x[0] - p[1] - 2*M_PI: x[0] - p[1])); }, -M_PI, M_PI, 2); f1->SetParNames("A","shift"); f1->SetParameters(1.0,0.0); // f1->SetParLimits(1,-M_PI/18,M_PI/18); f1->SetNpx(500); - clustHist->Fit("f1","I"); + clustHist->Fit("f1","IQ"); clustHist->Draw(); f1->Draw("same"); - c1->SaveAs(Form("%s_fit.png",clustHist->GetName())); - - gStyle->SetOptFit(0); - return f1->GetParameter(1); } -std::vector> PHTpcCentralMembraneMatcher::getPhiGaps( TH2F *r_phi ){ - - int bin0 = r_phi->GetYaxis()->FindBin(0.0); - int bin40 = r_phi->GetYaxis()->FindBin(40.0); - int bin58 = r_phi->GetYaxis()->FindBin(58.0); - int bin100 = r_phi->GetYaxis()->FindBin(99.99); - - TH1D *phiHist[3]; - phiHist[0] = r_phi->ProjectionX("phiHist_R1",bin0,bin40); - phiHist[1] = r_phi->ProjectionX("phiHist_R2",bin40,bin58); - phiHist[2] = r_phi->ProjectionX("phiHist_R3",bin58,bin100); - - std::vector> phiGaps; - - for(int R=0; R<3; R++){ - std::vector phiGaps_R; - for(int i=2; i<=phiHist[R]->GetNbinsX(); i++){ - if(phiHist[R]->GetBinContent(i) > 0 && phiHist[R]->GetBinContent(i-1) == 0){ - if(phiGaps_R.size() == 0) phiGaps_R.push_back(phiHist[R]->GetBinCenter(i)); - else if(phiHist[R]->GetBinCenter(i) - phiGaps_R[phiGaps_R.size()-1] > (M_PI/36.)) phiGaps_R.push_back(phiHist[R]->GetBinCenter(i)); - } - } - - phiGaps.push_back(phiGaps_R); - } - - return phiGaps; - -} - -std::vector PHTpcCentralMembraneMatcher::getAverageRotation(std::vector> hit, std::vector> clust){ - - std::vector avgAngle; - - for(int R=0; R<3; R++){ - - double di = 0.0; - double dj = 0.0; - - for(int i=0; i<(int)hit[R].size() - 1; i++){ - di += hit[R][i+1] - hit[R][i]; - } - di = di/(hit[R].size()-1); - - for(int j=0; j<(int)clust[R].size() - 1; j++){ - dj += clust[R][j+1] - clust[R][j]; - } - dj = dj/(clust[R].size()-1); - - double sum = 0.0; - int nMatch = 0; - for(int i=0; i<(int)hit[R].size(); i++){ - for(int j=0; j<(int)clust[R].size(); j++){ - if(fabs(clust[R][j] - hit[R][i]) > (di+dj)/4.0) continue; - if(j!=0 && clust[R][j] - clust[R][j] > 1.5*M_PI/9.0) continue; - sum += clust[R][j] - hit[R][i]; - nMatch++; - } - } - - avgAngle.push_back(sum/nMatch); - - } - - return avgAngle; - -} - - +//get vector with peak positions in Y (R) of histogram std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ TH1D *proj = r_phi->ProjectionY("R_proj"); @@ -271,9 +197,11 @@ std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ std::vector rPeaks; for(int i=2; iGetNbinsX(); i++){ + //peak is when content is higher than 0.15* maximum value and content is greater than or equal to both adjacent bins if(proj->GetBinContent(i) > 0.15*proj->GetMaximum() && proj->GetBinContent(i) >= proj->GetBinContent(i-1) && proj->GetBinContent(i) >= proj->GetBinContent(i+1)) rPeaks.push_back(proj->GetBinCenter(i)); } + //if two peaks are within 0.75 cm of eachother, remove one with fewer counts for(int i=0; i<(int)rPeaks.size()-1; i++){ if(rPeaks[i+1]-rPeaks[i] > 0.75) continue; if(proj->GetBinContent(proj->FindBin(rPeaks[i])) > proj->GetBinContent(proj->FindBin(rPeaks[i+1]))) rPeaks.erase(rPeaks.begin()+i+1); @@ -285,15 +213,9 @@ std::vector PHTpcCentralMembraneMatcher::getRPeaks(TH2F *r_phi){ int PHTpcCentralMembraneMatcher::getClusterRMatch( std::vector hitMatches, std::vector clusterPeaks, double clusterR){ - // int closest_clusterR = -1; - - /* for(int i=0; i<(int)hitMatches.size(); i++){ - - double lowGap = 0.5; - double highGap = 0.5; - */ double closestDist = 100.; int closestPeak = -1; + //find cluster peak closest to position of passed cluster for(int j=0; j<(int)clusterPeaks.size(); j++){ if(std::abs(clusterR - clusterPeaks[j]) < closestDist){ closestDist = std::abs(clusterR - clusterPeaks[j]); @@ -301,43 +223,7 @@ int PHTpcCentralMembraneMatcher::getClusterRMatch( std::vector hitMatches, } } - /* - - if(hitMatches[i] <= 14){ - lowGap = 0.565985; - highGap = 0.565985; - }else if(hitMatches[i] == 15){ - lowGap = 0.565985; - highGap = 1.2409686; - }else if(hitMatches[i] == 16){ - lowGap = 1.2409686; - highGap = 1.020695; - }else if(hitMatches[i] >= 17 && hitMatches[i] <= 22){ - lowGap = 1.020695; - highGap = 1.020695; - }else if(hitMatches[i] == 23){ - lowGap = 1.020695; - highGap = 1.5001502; - }else if(hitMatches[i] == 24){ - lowGap = 1.5001502; - highGap = 1.09705; - }else if(hitMatches[i] >= 25){ - lowGap = 1.09705; - highGap = 1.09705; - } - - - if( clusterR > (clusterPeaks[i] - lowGap) && clusterR <= (clusterPeaks[i] + highGap) ){ - closest_clusterR = hitMatches[i]; - break; - } - */ - // } - - - - // return closest_clusterR; - + //return hit match to cluster peak or -1 if closest peak failed (shouldn't be possible) if(closestPeak != -1) return hitMatches[closestPeak]; else return -1; @@ -381,21 +267,11 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) hnclus = new TH1F("hnclus", " nclusters ", 3, 0., 3.); } - fout2.reset( new TFile(m_outputfile2.c_str(),"RECREATE") ); - hit_r_phi = new TH2F("hit_r_phi","hit r vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - hit_r_phi_pos = new TH2F("hit_r_phi_pos","hit R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - hit_r_phi_neg = new TH2F("hit_r_phi_neg","hit R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - clust_r_phi = new TH2F("clust_r_phi","clust R vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - reco_ntup = new TNtuple("reco_ntuple","","hitR:hitPhi:hitZ:recoR:recoPhi:recoZ:nClus"); - - std::vector hitR; - std::vector hitPhi; - // Get truth cluster positions //===================== @@ -414,16 +290,11 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) m_truth_pos.push_back( source ); hit_r_phi->Fill(source.Phi(), source.Perp()); - hit_r_phi_pos->Fill(source.Phi(), source.Perp()); - hitR.push_back(source.Perp()); - hitPhi.push_back(source.Phi()); - source.SetZ( -1 ); m_truth_pos.push_back( source ); hit_r_phi->Fill(source.Phi(), source.Perp()); - hit_r_phi_neg->Fill(source.Phi(), source.Perp()); }; // inner region extended is the 8 layers inside 30 cm @@ -488,12 +359,6 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) if(m_savehistograms) hxy_truth->Fill(dummyPos.X(),dummyPos.Y()); } - hit_r_phi_gr = new TGraph((int)hitR.size(), &hitPhi[0], &hitR[0]); - hit_r_phi_gr->SetMarkerStyle(20); - hit_r_phi_gr->SetMarkerSize(0.5); - hit_r_phi_gr->GetXaxis()->SetTitle("#phi"); - hit_r_phi_gr->GetYaxis()->SetTitle("R (cm)"); - int ret = GetNodes(topNode); return ret; } @@ -504,41 +369,10 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) std::vector reco_pos; std::vector reco_nclusters; - std::vector clustR; - std::vector clustPhi; - - std::vector clustR_pos; - std::vector clustPhi_pos; - - std::vector clustR_neg; - std::vector clustPhi_neg; - - - std::vector clustR1; - std::vector clustPhi1; - - std::vector clustR_pos1; - std::vector clustPhi_pos1; - - std::vector clustR_neg1; - std::vector clustPhi_neg1; - - std::vector clustR2; - std::vector clustPhi2; - - std::vector clustR_pos2; - std::vector clustPhi_pos2; - - std::vector clustR_neg2; - std::vector clustPhi_neg2; - - - // reset output distortion correction container histograms for( const auto& harray:{m_dcc_out->m_hDRint, m_dcc_out->m_hDPint, m_dcc_out->m_hDZint, m_dcc_out->m_hentries} ) { for( const auto& h:harray ) { h->Reset(); } } - clust_r_phi->Reset(); clust_r_phi_pos->Reset(); clust_r_phi_neg->Reset(); @@ -552,6 +386,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) CMFlashClusterv2 *cmclus = dynamic_cast(cmclus_orig); const unsigned int nclus = cmclus->getNclusters(); + if(m_useOnly_nClus2 && nclus != 2) continue; + const bool isRGap = cmclus->getIsRGap(); @@ -561,55 +397,15 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) TVector3 tmp_pos(pos[0], pos[1], pos[2]); - // std::cout << "cmkey " << cmkey << " R: " << tmp_pos.Perp() << " isgap: " << isRGap << std::endl; - - // if(isRGap && Verbosity() > 2) std::cout << "here!" << std::endl; - - // if(isRGap && nclus == 1) continue; - if(isRGap) continue; reco_pos.push_back(tmp_pos); reco_nclusters.push_back(nclus); - clustR.push_back(tmp_pos.Perp()); - clustPhi.push_back(tmp_pos.Phi()); - - if(nclus == 1){ - clustR1.push_back(tmp_pos.Perp()); - clustPhi1.push_back(tmp_pos.Phi()); - }else{ - clustR2.push_back(tmp_pos.Perp()); - clustPhi2.push_back(tmp_pos.Phi()); - } - - clust_r_phi->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - if(tmp_pos.Z() > 0){ - clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - clustR_pos.push_back(tmp_pos.Perp()); - clustPhi_pos.push_back(tmp_pos.Phi()); - - if(nclus == 1){ - clustR_pos1.push_back(tmp_pos.Perp()); - clustPhi_pos1.push_back(tmp_pos.Phi()); - }else{ - clustR_pos2.push_back(tmp_pos.Perp()); - clustPhi_pos2.push_back(tmp_pos.Phi()); - } + if(tmp_pos.Z() < 0) clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); + else clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - }else if(tmp_pos.Z() < 0){ - clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); - clustR_neg.push_back(tmp_pos.Perp()); - clustPhi_neg.push_back(tmp_pos.Phi()); - - if(nclus == 1){ - clustR_neg1.push_back(tmp_pos.Perp()); - clustPhi_neg1.push_back(tmp_pos.Phi()); - }else{ - clustR_neg2.push_back(tmp_pos.Perp()); - clustPhi_neg2.push_back(tmp_pos.Phi()); - } - } + if(Verbosity()) { @@ -626,79 +422,10 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) } - clust_r_phi_gr = new TGraph((int)clustR.size(), &clustPhi[0], &clustR[0]); - clust_r_phi_gr->SetMarkerStyle(20); - clust_r_phi_gr->SetMarkerSize(0.5); - clust_r_phi_gr->SetMarkerColor(kMagenta); - - clust_r_phi_gr_pos = new TGraph((int)clustR_pos.size(), &clustPhi_pos[0], &clustR_pos[0]); - clust_r_phi_gr_pos->SetMarkerStyle(20); - clust_r_phi_gr_pos->SetMarkerSize(0.5); - clust_r_phi_gr_pos->SetMarkerColor(kMagenta); - - clust_r_phi_gr_neg = new TGraph((int)clustR_neg.size(), &clustPhi_neg[0], &clustR_neg[0]); - clust_r_phi_gr_neg->SetMarkerStyle(20); - clust_r_phi_gr_neg->SetMarkerSize(0.5); - clust_r_phi_gr_neg->SetMarkerColor(kMagenta); - - - clust_r_phi_gr1 = new TGraph((int)clustR1.size(), &clustPhi1[0], &clustR1[0]); - clust_r_phi_gr1->SetMarkerStyle(20); - clust_r_phi_gr1->SetMarkerSize(0.5); - clust_r_phi_gr1->SetMarkerColor(kBlue); - - clust_r_phi_gr1_pos = new TGraph((int)clustR_pos1.size(), &clustPhi_pos1[0], &clustR_pos1[0]); - clust_r_phi_gr1_pos->SetMarkerStyle(20); - clust_r_phi_gr1_pos->SetMarkerSize(0.5); - clust_r_phi_gr1_pos->SetMarkerColor(kBlue); - - clust_r_phi_gr1_neg = new TGraph((int)clustR_neg1.size(), &clustPhi_neg1[0], &clustR_neg1[0]); - clust_r_phi_gr1_neg->SetMarkerStyle(20); - clust_r_phi_gr1_neg->SetMarkerSize(0.5); - clust_r_phi_gr1_neg->SetMarkerColor(kBlue); - - - clust_r_phi_gr2 = new TGraph((int)clustR2.size(), &clustPhi2[0], &clustR2[0]); - clust_r_phi_gr2->SetMarkerStyle(20); - clust_r_phi_gr2->SetMarkerSize(0.5); - clust_r_phi_gr2->SetMarkerColor(kGreen+2); - - clust_r_phi_gr2_pos = new TGraph((int)clustR_pos2.size(), &clustPhi_pos2[0], &clustR_pos2[0]); - clust_r_phi_gr2_pos->SetMarkerStyle(20); - clust_r_phi_gr2_pos->SetMarkerSize(0.5); - clust_r_phi_gr2_pos->SetMarkerColor(kGreen+2); - - clust_r_phi_gr2_neg = new TGraph((int)clustR_neg2.size(), &clustPhi_neg2[0], &clustR_neg2[0]); - clust_r_phi_gr2_neg->SetMarkerStyle(20); - clust_r_phi_gr2_neg->SetMarkerSize(0.5); - clust_r_phi_gr2_neg->SetMarkerColor(kGreen+2); - - - std::vector> hit_phiGaps = getPhiGaps(hit_r_phi); - std::vector> clust_phiGaps = getPhiGaps(clust_r_phi); - std::vector angleDiff = getAverageRotation(hit_phiGaps, clust_phiGaps); - - - std::vector> hit_phiGaps_pos = getPhiGaps(hit_r_phi_pos); - std::vector> clust_phiGaps_pos = getPhiGaps(clust_r_phi_pos); - std::vector angleDiff_pos = getAverageRotation(hit_phiGaps_pos, clust_phiGaps_pos); - - std::vector> hit_phiGaps_neg = getPhiGaps(hit_r_phi_neg); - std::vector> clust_phiGaps_neg = getPhiGaps(clust_r_phi_neg); - std::vector angleDiff_neg = getAverageRotation(hit_phiGaps_neg, clust_phiGaps_neg); - - // std::cout << "rotation R1: " << angleDiff[0] << " R2: " << angleDiff[1] << " R3: " << angleDiff[2] << std::endl; - // std::cout << "pos rotation R1: " << angleDiff_pos[0] << " R2: " << angleDiff_pos[1] << " R3: " << angleDiff_pos[2] << std::endl; - // std::cout << "neg rotation R1: " << angleDiff_neg[0] << " R2: " << angleDiff_neg[1] << " R3: " << angleDiff_neg[2] << std::endl; - - double clustRotation[3]; double clustRotation_pos[3]; double clustRotation_neg[3]; - clustRotation[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi->ProjectionX("cR1",151,206)); - clustRotation[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi->ProjectionX("cR2",206,290)); - clustRotation[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi->ProjectionX("cR3",290,499)); - + //get global phi rotation for each module clustRotation_pos[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_pos->ProjectionX("cR1_pos",151,206)); clustRotation_pos[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_pos->ProjectionX("cR2_pos",206,290)); clustRotation_pos[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_pos->ProjectionX("cR3_pos",290,499)); @@ -707,14 +434,13 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) clustRotation_neg[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_neg->ProjectionX("cR2_neg",206,290)); clustRotation_neg[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_neg->ProjectionX("cR3_neg",290,499)); - std::cout << "clust rotation R1: "<< clustRotation[0] << " R2: " << clustRotation[1] << " R3: " << clustRotation[2] << std::endl; - std::cout << "pos clust rotation R1: "<< clustRotation_pos[0] << " R2: " << clustRotation_pos[1] << " R3: " << clustRotation_pos[2] << std::endl; - std::cout << "neg clust rotation R1: "<< clustRotation_neg[0] << " R2: " << clustRotation_neg[1] << " R3: " << clustRotation_neg[2] << std::endl; + //get hit and cluster peaks std::vector hit_RPeaks = getRPeaks(hit_r_phi); std::vector clust_RPeaks_pos = getRPeaks(clust_r_phi_pos); std::vector clust_RPeaks_neg = getRPeaks(clust_r_phi_neg); + //identify where gaps between module 1&2 and 2&3 are by finding largest distances between peaks std::vector clust_RGaps_pos; int R12Gap_pos = -1; int R23Gap_pos = -1; @@ -727,11 +453,6 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) R12Gap_pos = tmpGap_pos; R23Gap_pos = std::distance(clust_RGaps_pos.begin(),std::max_element(clust_RGaps_pos.begin()+R12Gap_pos+1,clust_RGaps_pos.end())); } - std::cout << "R12Gap_pos: " << R12Gap_pos << std::endl; - std::cout << "R23Gap_pos: " << R23Gap_pos << std::endl; - - - std::cout << "pos region sizes R1: " << R12Gap_pos+1 << " R2: " << R23Gap_pos-R12Gap_pos << " R3: " << (int)clust_RGaps_pos.size()-R23Gap_pos << std::endl; std::vector clust_RGaps_neg; int R12Gap_neg = -1; @@ -745,33 +466,26 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) R12Gap_neg = tmpGap_neg; R23Gap_neg = std::distance(clust_RGaps_neg.begin(),std::max_element(clust_RGaps_neg.begin()+R12Gap_neg+1,clust_RGaps_neg.end())); } - std::cout << "R12Gap_neg: " << R12Gap_neg << std::endl; - std::cout << "R23Gap_neg: " << R23Gap_neg << std::endl; - std::cout << "neg region sizes R1: " << R12Gap_neg+1 << " R2: " << R23Gap_neg-R12Gap_neg << " R3: " << (int)clust_RGaps_neg.size()-R23Gap_neg << std::endl; - - - std::cout << "hit matches pos = {"; std::vector hitMatches_pos; + //match cluster peaks to hit peaks using gap positions for(int i=0; i<(int)clust_RPeaks_pos.size(); i++){ - + + //Module 1 if(i < (R12Gap_pos+1)){ + //module 1-2 gap is between 15 & 16 in hitPeaks hitMatches_pos.push_back(15 + i - R12Gap_pos ); + //if multiple rows missing, offset for each one if(clust_RGaps_pos[R12Gap_pos] > 3.6) hitMatches_pos[i] -= 1; if(clust_RGaps_pos[R12Gap_pos] > 4.6) hitMatches_pos[i] -= 1; - if(clust_RGaps_pos[R12Gap_pos] > 5.8) hitMatches_pos[i] -= 1; - + if(clust_RGaps_pos[R12Gap_pos] > 5.8) hitMatches_pos[i] -= 1; } + //module 1-2 gap is between 15 & 16 else if(i < (R23Gap_pos+1) && i >= (R12Gap_pos+1)) hitMatches_pos.push_back(15+1 + i - (R12Gap_pos+1)); - else if(i >= R23Gap_pos+1) hitMatches_pos.push_back(23+1 + i - (R23Gap_pos+1)); - - - // hitMatches_pos.push_back(i + 23 - R23Gap_pos); - if(i<(int)clust_RPeaks_pos.size()-1) std::cout << " " << hitMatches_pos[i] << ","; - else std::cout << " " << hitMatches_pos[i] << "}" << std::endl; + //module 2-3 gap is between 22 & 23 + else if(i >= R23Gap_pos+1) hitMatches_pos.push_back(23+1 + i - (R23Gap_pos+1)); } - std::cout << "hit matches neg = {"; std::vector hitMatches_neg; for(int i=0; i<(int)clust_RPeaks_neg.size(); i++){ @@ -784,10 +498,6 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) } else if(i < (R23Gap_neg+1) && i >= (R12Gap_neg+1)) hitMatches_neg.push_back(15+1 + i - (R12Gap_neg+1)); else if(i >= R23Gap_neg+1) hitMatches_neg.push_back(23+1 + i - (R23Gap_neg+1)); - - // hitMatches_neg.push_back(i + 23 - R23Gap_neg); - if(i<(int)clust_RPeaks_neg.size()-1) std::cout << " " << hitMatches_neg[i] << ","; - else std::cout << " " << hitMatches_neg[i] << "}" << std::endl; } @@ -799,117 +509,108 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) std::vector hits_matched(m_truth_pos.size()); std::vector clusts_matched(reco_pos.size()); - for(int matchIt=0; matchIt<2; matchIt++){ + //do iterative matching m_nMatchIter times + for(int matchIt=0; matchIt= 41 && reco_pos[j].Perp() < 58) angleR = 1; - if(reco_pos[j].Perp() >= 58) angleR = 2; + const double z1 = m_truth_pos[i].Z(); + const double rad1= get_r( m_truth_pos[i].X(),m_truth_pos[i].Y()); + const double phi1 = m_truth_pos[i].Phi(); + int hitRadIndex = -1; - //const auto& nclus = reco_nclusters[j]; - double phi2 = reco_pos[j].Phi(); - const double z2 = reco_pos[j].Z(); - const double rad2=get_r(reco_pos[j].X(), reco_pos[j].Y()); - if(angleR != -1){ - if(z2 > 0) phi2 += (hitRotation[angleR+1] - clustRotation_pos[angleR]); - else phi2 += (hitRotation[angleR+1] - clustRotation_neg[angleR]); + //get which hit radial index this it + for(int k=0; k<(int)hit_RPeaks.size(); k++){ + if(std::abs(rad1 - hit_RPeaks[k]) < 0.5){ + hitRadIndex = k; + break; + } } - - int clustRMatchIndex = -1; - if(z2 > 0) clustRMatchIndex = getClusterRMatch(hitMatches_pos, clust_RPeaks_pos, rad2); - else clustRMatchIndex = getClusterRMatch(hitMatches_neg, clust_RPeaks_neg, rad2); - - - if(clustRMatchIndex == -1) continue; - - //const double phi2 = reco_pos[j].Phi(); - - // only match pairs that are on the same side of the TPC - const bool accepted_z = ((z1>0)==(z2>0)); - if( !accepted_z ) continue; - - - - const bool accepted_r = (hitRadIndex == clustRMatchIndex); - - // const auto dphi = delta_phi(phi1-phi2); - const auto dphi = delta_phi(phi1-phi2); - const bool accepted_phi = std::abs(dphi) < m_phi_cut; - - if(!accepted_r || !accepted_phi) continue; + //for iterative looping: identify closest phi + double prev_dphi = 1.1*m_phi_cut; + int matchJ = -1; - // std::cout << "matching cluster " << j << " rad: " << rad2 << " clustRMatchIndex: " << clustRMatchIndex << " hitRadIndex: " << hitRadIndex << " hitMatchedR: " << (clustRMatchIndex != -1 ? hit_RPeaks[clustRMatchIndex] : -1) << std::endl; - - - if(fabs(dphi)= 41 && reco_pos[j].Perp() < 58) angleR = 1; + if(reco_pos[j].Perp() >= 58) angleR = 2; + + + //const auto& nclus = reco_nclusters[j]; + double phi2 = reco_pos[j].Phi(); + const double z2 = reco_pos[j].Z(); + const double rad2=get_r(reco_pos[j].X(), reco_pos[j].Y()); + if(angleR != -1){ + if(z2 > 0) phi2 -= clustRotation_pos[angleR]; + else phi2 -= clustRotation_neg[angleR]; + } + + + int clustRMatchIndex = -1; + if(z2 > 0) clustRMatchIndex = getClusterRMatch(hitMatches_pos, clust_RPeaks_pos, rad2); + else clustRMatchIndex = getClusterRMatch(hitMatches_neg, clust_RPeaks_neg, rad2); + + + if(clustRMatchIndex == -1) continue; + + //const double phi2 = reco_pos[j].Phi(); + + // only match pairs that are on the same side of the TPC + const bool accepted_z = ((z1>0)==(z2>0)); + if( !accepted_z ) continue; + + + + const bool accepted_r = (hitRadIndex == clustRMatchIndex); - const auto dr = rad1-rad2; const auto dphi = delta_phi(phi1-phi2); + const bool accepted_phi = std::abs(dphi) < m_phi_cut; + + if(!accepted_r || !accepted_phi) continue; + + + + if(fabs(dphi)Fill( (float) nclus); double r = rad2; - //if( accepted_r ) - // { hdrphi->Fill(r * dphi); hdphi->Fill(dphi); hrdphi->Fill(r,dphi); - // } - - // if( accepted_r && accepted_phi) hdrdphi->Fill(dr, dphi); - - // if( accepted_phi ) - // { hrdr->Fill(r,dr); if(nclus==1) { @@ -923,10 +624,9 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) if(r >= 40.0 && r < 58.0) hdr2_double->Fill(dr); if(r >= 58.0) hdr3_double->Fill(dr); } - // } - }//end save histos - }//end if match was found - }//end loop over truth pos + }//end save histos + }//end if match was found + }//end loop over truth pos }//end loop over matching iterations // print some statistics: @@ -963,8 +663,6 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) m_cm_flash_diffs->addDifferenceSpecifyKey(key, cmdiff); - reco_ntup->Fill(m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),m_truth_pos[p.first].Z(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z(),nclus); - // store cluster position const double clus_r = reco_pos[p.second].Perp(); double clus_phi = reco_pos[p.second].Phi(); @@ -1054,36 +752,6 @@ int PHTpcCentralMembraneMatcher::End(PHCompositeNode * /*topNode*/ ) } } - fout2->cd(); - - hit_r_phi->Write(); - hit_r_phi_pos->Write(); - hit_r_phi_neg->Write(); - - hit_r_phi_gr->Write("hit_r_phi_gr"); - - - clust_r_phi->Write(); - clust_r_phi_pos->Write(); - clust_r_phi_neg->Write(); - - clust_r_phi_gr->Write("clust_r_phi_gr"); - clust_r_phi_gr_pos->Write("clust_r_phi_gr_pos"); - clust_r_phi_gr_neg->Write("clust_r_phi_gr_neg"); - - - clust_r_phi_gr1->Write("clust_r_phi_gr1"); - clust_r_phi_gr1_pos->Write("clust_r_phi_gr1_pos"); - clust_r_phi_gr1_neg->Write("clust_r_phi_gr1_neg"); - - clust_r_phi_gr2->Write("clust_r_phi_gr2"); - clust_r_phi_gr2_pos->Write("clust_r_phi_gr2_pos"); - clust_r_phi_gr2_neg->Write("clust_r_phi_gr2_neg"); - - reco_ntup->Write(); - - fout2->Close(); - // write evaluation histograms if(m_savehistograms && fout) { diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 3d109de757..21420bb6a1 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -23,7 +23,6 @@ class CMFlashClusterContainer; class CMFlashDifferenceContainer; class TF1; -class TNtuple; class TFile; class TH1F; class TH1D; @@ -50,6 +49,10 @@ class PHTpcCentralMembraneMatcher : public SubsysReco /// output file name for storing the space charge reconstruction matrices void setOutputfile(const std::string &outputfile) {m_outputfile = outputfile;} + + void setNMatchIter( int val ){ m_nMatchIter = val; } + + void set_useOnly_nClus2( bool val ){ m_useOnly_nClus2 = val; } void set_grid_dimensions( int phibins, int rbins ); @@ -113,33 +116,10 @@ class PHTpcCentralMembraneMatcher : public SubsysReco std::unique_ptr fout; TH2F *hit_r_phi; - TH2F *hit_r_phi_pos; - TH2F *hit_r_phi_neg; - TH2F *clust_r_phi; TH2F *clust_r_phi_pos; TH2F *clust_r_phi_neg; - TGraph *hit_r_phi_gr; - - TGraph *clust_r_phi_gr; - TGraph *clust_r_phi_gr_pos; - TGraph *clust_r_phi_gr_neg; - - TGraph *clust_r_phi_gr1; - TGraph *clust_r_phi_gr1_pos; - TGraph *clust_r_phi_gr1_neg; - - TGraph *clust_r_phi_gr2; - TGraph *clust_r_phi_gr2_pos; - TGraph *clust_r_phi_gr2_neg; - - TNtuple *reco_ntup = nullptr; - - - std::string m_outputfile2 = "CM_r_phi_maps.root"; - std::unique_ptr fout2; - //@} /// radius cut for matching clusters to pad, for size 2 clusters @@ -238,15 +218,12 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@} - double hitRotationTotal; - double hitRotation[4]; - double clustRotation[3]; - double clustRotation_pos[3]; - double clustRotation_neg[3]; + bool m_useOnly_nClus2 = false; - std::vector> getPhiGaps(TH2F *r_phi); + int m_nMatchIter = 2; - std::vector getAverageRotation(std::vector> hit, std::vector> clust); + double clustRotation_pos[3]; + double clustRotation_neg[3]; double getPhiRotation_smoothed( TH1D *hitHist, TH1D *clustHist ); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc index 9d88cae1d4..d2a0dd7749 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc @@ -126,28 +126,24 @@ int PHG4TpcCentralMembrane::InitRun(PHCompositeNode* /* topNode */) // loop over stripeID for (int k = 0; k < nGoodStripes_R1_e[j]; k++) { - if(skip_R1_e) continue; adjust_hits(GetPHG4HitFromStripe(i, 0, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R1[j]; k++) { - if(skip_R1) continue; adjust_hits(GetPHG4HitFromStripe(i, 1, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R2[j]; k++) { - if(skip_R2) continue; adjust_hits(GetPHG4HitFromStripe(i, 2, j, k, electrons_per_stripe)); } // loop over stripeID for (int k = 0; k < nGoodStripes_R3[j]; k++) { - if(skip_R3) continue; adjust_hits(GetPHG4HitFromStripe(i, 3, j, k, electrons_per_stripe)); } } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h index 3ac1e7fe0a..f8532284cb 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.h @@ -52,11 +52,6 @@ class PHG4TpcCentralMembrane : public SubsysReco, public PHParameterInterface /// set modulo for events in which to generate CM hits void setCentralMembraneEventModulo(int mod) { m_eventModulo = mod; }; - void setSkipR1_e( bool a_skip ) { skip_R1_e = a_skip; }; - void setSkipR1( bool a_skip ) { skip_R1 = a_skip; }; - void setSkipR2( bool a_skip ) { skip_R2 = a_skip; }; - void setSkipR3( bool a_skip ) { skip_R3 = a_skip; }; - private: /// detector name std::string detector = "TPC"; @@ -68,11 +63,6 @@ class PHG4TpcCentralMembrane : public SubsysReco, public PHParameterInterface int m_eventModulo = 10; int m_eventNum = 0; - bool skip_R1_e = false; - bool skip_R1 = false; - bool skip_R2 = false; - bool skip_R3 = false; - static constexpr double mm = 1.0; static constexpr double cm = 10.0; From ed613ebf87d7d7d39313b735f0a8be78f31edb78 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 4 Apr 2023 22:32:46 -0400 Subject: [PATCH 108/468] put printout behind verbosity --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index 34a6e17f07..b40c28cc15 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -185,10 +185,7 @@ int BbcSimReco::InitRun(PHCompositeNode *topNode) // Call user instructions for every event int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) { - // GetNodes(topNode); - f_evt = _evtheader->get_EvtSequence(); - // if(f_evt%100==0) std::cout << PHWHERE << "Events processed: " << f_evt << std::endl; //**** Initialize Variables @@ -225,7 +222,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) f_vz = vtxp->get_z(); f_vt = vtxp->get_t(); - if (f_evt < 20) + if (Verbosity() && f_evt < 20) { std::cout << "VTXP " << "\t" << f_vx << "\t" << f_vy << "\t" << f_vz << "\t" << f_vt << std::endl; From e0f732289d842809c6412207ceaeccbefa6bbd7e Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 5 Apr 2023 00:17:43 -0400 Subject: [PATCH 109/468] `PHG4TpcDigitizer` rewrite --- offline/packages/trackbase/TrkrHitSetTpc.h | 6 + offline/packages/trackbase/TrkrHitSetTpcv1.h | 5 + .../g4simulation/g4tpc/PHG4TpcDigitizer.cc | 413 ++---------------- .../g4simulation/g4tpc/PHG4TpcDigitizer.h | 8 +- 4 files changed, 62 insertions(+), 370 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpc.h b/offline/packages/trackbase/TrkrHitSetTpc.h index ae3e8b5f40..1c52b12dd2 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.h +++ b/offline/packages/trackbase/TrkrHitSetTpc.h @@ -66,6 +66,12 @@ class TrkrHitSetTpc : public TrkrHitSet return tmp; } + virtual TimeFrameADCDataType& getTimeFrameAdcData() + { + static TimeFrameADCDataType tmp; + + return tmp; + } virtual void setTimeFrameAdcData(const TimeFrameADCDataType&) { diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h index cabb6f43aa..02bd66cc20 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.h +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -119,6 +119,11 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc return m_timeFrameADCData; } + TimeFrameADCDataType& getTimeFrameAdcData() override + { + return m_timeFrameADCData; + } + void setTimeFrameAdcData(const TimeFrameADCDataType& timeFrameAdcData) override { m_timeFrameADCData = timeFrameAdcData; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index c8b242fc88..f57e4bf876 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include #include #include @@ -25,6 +25,7 @@ #include #include // for gsl_rng_alloc +#include #include // for exit #include #include @@ -153,7 +154,6 @@ void PHG4TpcDigitizer::CalculateCylinderCellADCScale(PHCompositeNode *topNode) void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) { - unsigned int print_layer = 18; // to print diagnostic output for layer 47 // Digitizes the Tpc cells that were created in PHG4CylinderCellTpcReco // These contain as edep the number of electrons out of the GEM stack, distributed between Z bins by shaper response and ADC clock window @@ -236,395 +236,74 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) std::cout << "Could not locate TRKR_HITSET_TPC node, quit! " << std::endl; exit(1); } - - TrkrHitTruthAssoc *hittruthassoc = findNode::getClass(topNode, "TRKR_HITTRUTHASSOC"); - if (!hittruthassoc) - { - std::cout << PHWHERE << " Could not locate TRKR_HITTRUTHASSOC node, quit! " << std::endl; - exit(1); - } - //------------- // Digitization //------------- - // Loop over all TPC layers - for (unsigned int layer = TpcMinLayer; layer < TpcMinLayer + TpcNLayers; ++layer) + TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(); + for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; + hitset_iter != hitset_range.second; + ++hitset_iter) { - // we need the geometry object for this layer - PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); - if (!layergeom) exit(1); + // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer + // get the hitset key + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - int nphibins = layergeom->get_phibins(); - if (Verbosity() > 1) - std::cout << " nphibins " << nphibins << std::endl; + // get all of the hits from this hitset + TrkrHitSetTpc *hitset = dynamic_cast(hitset_iter->second); - for (unsigned int side = 0; side < 2; ++side) + if (hitset == nullptr) { - if (Verbosity() > 1) - std::cout << "TPC layer " << layer << " side " << side << std::endl; + std::cout << __PRETTY_FUNCTION__ << " : fatal error : hitset received is not a TrkrHitSetTpc with key " << hitsetkey << " and content "; + hitset_iter->second->identify(); + } + assert(hitset); - // for this layer and side, use a vector of a vector of cells for each phibin - phi_sorted_hits.clear(); - for (int iphi = 0; iphi < nphibins; iphi++) - { - phi_sorted_hits.push_back(std::vector()); - } + std::vector pass_zero_suppression; - // TODO: edit with new hit container - // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin - TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId, layer); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; - hitset_iter != hitset_range.second; - ++hitset_iter) + for (auto & t_sorted_hits : hitset->getTimeFrameAdcData()) + { + // add noise + for (auto & adc_bin : t_sorted_hits) { - // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer - // get the hitset key - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - unsigned int this_side = TpcDefs::getSide(hitsetkey); - // skip this hitset if it is not on this side - if (this_side != side) continue; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "new: PHG4TpcDigitizer: processing signal hits for layer " << layer - << " hitsetkey " << hitsetkey << " side " << side << std::endl; - - // get all of the hits from this hitset - TrkrHitSetTpc *hitset = dynamic_cast( hitset_iter->second ); - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - // Fill the vector of signal hits for each phibin - unsigned int phibin = TpcDefs::getPad(hit_iter->first); - phi_sorted_hits[phibin].push_back(hit_iter); - } - // For this hitset we now have the signal hits sorted into vectors for each phi + adc_bin = static_cast(add_noise_to_bin((float) adc_bin)); } - // Process one phi bin at a time - if (Verbosity() > 1) std::cout << " phi_sorted_hits size " << phi_sorted_hits.size() << std::endl; - for (unsigned int iphi = 0; iphi < phi_sorted_hits.size(); iphi++) + // zero suppression + assert(m_nPostSample >= 1); + pass_zero_suppression.resize(t_sorted_hits.size(), false); + for (int i = 0; i < (int) t_sorted_hits.size(); ++i) { - // Make a fixed length vector to indicate whether each time bin is signal or noise - int ntbins = layergeom->get_zbins(); - is_populated.clear(); - is_populated.assign(ntbins, 2); // mark all as noise only, for now - - // add an empty vector of hits for each t bin - t_sorted_hits.clear(); - for (int it = 0; it < ntbins; it++) + if (t_sorted_hits[i] > ADCThreshold_mV) { - t_sorted_hits.push_back(std::vector()); - } - - // add a signal hit from phi_sorted_hits for each t bin that has one - for (unsigned int it = 0; it < phi_sorted_hits[iphi].size(); it++) - { - int tbin = TpcDefs::getTBin(phi_sorted_hits[iphi][it]->first); - is_populated[tbin] = 1; // this bin is a associated with a hit - t_sorted_hits[tbin].push_back(phi_sorted_hits[iphi][it]); - - if (Verbosity() > 2) - if (layer == print_layer) - { - TrkrDefs::hitkey hitkey = phi_sorted_hits[iphi][it]->first; - std::cout << "iphi " << iphi << " adding existing signal hit to t vector for layer " << layer - << " side " << side - << " tbin " << tbin << " hitkey " << hitkey - << " pad " << TpcDefs::getPad(hitkey) - << " t bin " << TpcDefs::getTBin(hitkey) - << " energy " << (phi_sorted_hits[iphi][it]->second)->getEnergy() - << std::endl; - } - } - - adc_input.clear(); - adc_hitid.clear(); - // initialize entries to zero for each t bin - adc_input.assign(ntbins, 0.0); - adc_hitid.assign(ntbins, 0); - - // Now for this phibin we process all bins ordered by t into hits with noise - //====================================================== - // For this step we take the edep value and convert it to mV at the ADC input - // See comments above for how to do this for signal and noise - - for (int it = 0; it < ntbins; it++) - { - if (is_populated[it] == 1) - { - // This tbin has a hit, add noise - float signal_with_noise = add_noise_to_bin((t_sorted_hits[it][0]->second)->getEnergy()); - adc_input[it] = signal_with_noise; - adc_hitid[it] = t_sorted_hits[it][0]->first; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "existing signal hit: layer " << layer << " iphi " << iphi << " it " << it - << " edep " << (t_sorted_hits[it][0]->second)->getEnergy() - << " adc gain " << ADCSignalConversionGain - << " signal with noise " << signal_with_noise - << " adc_input " << adc_input[it] << std::endl; - } - else if (is_populated[it] == 2) + for (int j = i - m_nPreSample; j < i + (int)m_nPostSample; ++j) { - if (!skip_noise) - { - // This t bin does not have a filled cell, add noise - float noise = add_noise_to_bin(0.0); - adc_input[it] = noise; - adc_hitid[it] = 0; // there is no hit, just add a placeholder in the vector for now, replace it later - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << "noise hit: layer " << layer << " side " << side << " iphi " << iphi << " it " << it - << " adc gain " << ADCSignalConversionGain - << " noise " << noise - << " adc_input " << adc_input[it] << std::endl; - } - } - else - { - // Cannot happen - std::cout << "Impossible value of is_populated, it = " << it - << " is_populated = " << is_populated[it] << std::endl; - exit(-1); - } - } - - // Now we can digitize the entire stream of t bins for this phi bin - int binpointer = 0; - - // Since we now store the local z of the hit as time of arrival at the readout plane, - // there is no difference between north and south - // The first to arrive is always bin 0 - - for (int it = 0; it < ntbins; it++) - { - if (it < binpointer) continue; + if (j < 0) continue; + if (j >= (int)pass_zero_suppression.size()) continue; - // optionally do not trigger on bins with no signal - if ((is_populated[it] == 2) && skip_noise) - { - binpointer++; - continue; + pass_zero_suppression[j] = true; } - - // convert threshold in "equivalent electrons" to mV - if (adc_input[it] > ADCThreshold_mV) - { - // digitize this bin and the following 4 bins - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << std::endl - << "Hit above threshold of " - << ADCThreshold * ADCNoiseConversionGain << " for phibin " << iphi - << " it " << it << " with adc_input " << adc_input[it] - << " digitize this and 4 following bins: " << std::endl; - - for (int itup = 0; itup < 5; itup++) - { - if (it + itup < ntbins && it + itup >= 0) // stay within the bin limits - { - float input = 0; - if ((is_populated[it + itup] == 2) && skip_noise) - { - input = add_noise_to_bin(0.0); // no noise added to this bin previously because skip_noise is true - } - else - { - input = adc_input[it + itup]; - } - // input voltage x 1024 channels over 2200 mV max range - unsigned int adc_output = (unsigned int) (input * 1024.0 / 2200.0); - - if (input < 0) adc_output = 0; - if (input > 1023) adc_output = 1023; - - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it + itup); - TrkrHit *hit = nullptr; - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << " Digitizing: iphi " << iphi << " it+itup " << it + itup - << " adc_hitid " << adc_hitid[it + itup] - << " is_populated " << is_populated[it + itup] - << " adc_input " << adc_input[it + itup] - << " ADCThreshold " << ADCThreshold * ADCNoiseConversionGain - << " adc_output " << adc_output - << " hitkey " << hitkey - << " side " << side - << " binpointer " << binpointer - << std::endl; - - if (is_populated[it + itup] == 1) - { - // this is a signal hit, it already exists - hit = t_sorted_hits[it + itup][0]->second; // pointer valid only for signal hits - } - else - { - // Hit does not exist yet, have to make one - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto hitset_iter = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); - - hit = new TrkrHitv2(); - hitset_iter->second->addHitSpecificKey(hitkey, hit); - - if (Verbosity() > 2) - if (layer == print_layer) - std::cout << " adding noise TrkrHit for iphi " << iphi - << " tbin " << it + itup - << " side " << side - << " created new hit with hitkey " << hitkey - << " energy " << adc_input[it + itup] << " adc " << adc_output - << " binpointer " << binpointer - << std::endl; - } - - hit->setAdc(adc_output); - - } // end boundary check - binpointer++; // skip this bin in future - } // end itup loop - - } // adc threshold if - else - { - // set adc value to zero if there is a hit - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto hitset = trkrhitsetcontainer->findHitSet(hitsetkey); - if (hitset) - { - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); - TrkrHit *hit = nullptr; - hit = hitset->getHit(hitkey); - if (hit) - { - hit->setAdc(0); - } - } - // bin below threshold, move on - binpointer++; - } // end adc threshold if/else - } // end time bin loop - } // end phibins loop - } // end loop over sides - } // end loop over TPC layers - - //====================================================== - if (Verbosity() > 5) - { - std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end before cleaning:" << std::endl; - } - std::vector> delete_hitkey_list; - - // Clean up undigitized hits - we want all hitsets for the Tpc - // This loop is pretty efficient because the remove methods all take a specified hitset as input - TrkrHitSetContainer::ConstRange hitset_range_now = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range_now.first; - hitset_iter != hitset_range_now.second; - ++hitset_iter) - { - // we have an iterator to one TrkrHitSet for the Tpc from the trkrHitSetContainer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - const unsigned int layer = TrkrDefs::getLayer(hitsetkey); - const int sector = TpcDefs::getSectorId(hitsetkey); - const int side = TpcDefs::getSide(hitsetkey); - if (Verbosity() > 5) - std::cout << "PHG4TpcDigitizer: hitset with key: " << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; - - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - TrkrDefs::hitkey hitkey = hit_iter->first; - TrkrHit *tpchit = hit_iter->second; - - if (Verbosity() > 5) - std::cout << " layer " << layer << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) - << " t bin " << TpcDefs::getTBin(hitkey) - << " adc " << tpchit->getAdc() << std::endl; - - if (tpchit->getAdc() == 0) - { - if (Verbosity() > 20) - { - std::cout << " -- this hit not digitized - delete it" << std::endl; + i += m_nPostSample - 1; } - // screws up the iterator to delete it here, store the hitkey for later deletion - delete_hitkey_list.push_back(std::make_pair(hitsetkey, hitkey)); } - } - } - - // delete all undigitized hits - for (unsigned int i = 0; i < delete_hitkey_list.size(); i++) - { - TrkrHitSet *hitset = trkrhitsetcontainer->findHitSet(delete_hitkey_list[i].first); - const unsigned int layer = TrkrDefs::getLayer(delete_hitkey_list[i].first); - hitset->removeHit(delete_hitkey_list[i].second); - if (Verbosity() > 20) - if (layer == print_layer) - std::cout << "removed hit with hitsetkey " << delete_hitkey_list[i].first - << " and hitkey " << delete_hitkey_list[i].second << std::endl; - - // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map - // hittruthassoc->removeAssoc(delete_hitkey_list[i].first, delete_hitkey_list[i].second); // Slow! Commented out by ADF 9/6/2022 - } + for (unsigned int i = 0; i < t_sorted_hits.size(); ++i) + { + if (not pass_zero_suppression[i]) t_sorted_hits[i] = 0; + } - // Final hitset dump - if (Verbosity() > 5) - std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end after cleaning:" << std::endl; - // We want all hitsets for the Tpc - TrkrHitSetContainer::ConstRange hitset_range_final = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range_final.first; - hitset_iter != hitset_range_now.second; - ++hitset_iter) - { - // we have an itrator to one TrkrHitSet for the Tpc from the trkrHitSetContainer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - const unsigned int layer = TrkrDefs::getLayer(hitsetkey); - if (layer != print_layer) continue; - const int sector = TpcDefs::getSectorId(hitsetkey); - const int side = TpcDefs::getSide(hitsetkey); - if (Verbosity() > 5 && layer == print_layer) - std::cout << "PHG4TpcDigitizer: hitset with key: " << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; + // mV -> ADC + for (auto &adc_bin : t_sorted_hits) + { + // input voltage x 1024 channels over 2200 mV max range + adc_bin = static_cast(adc_bin * 1024.0 / 2200.0); - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - TrkrDefs::hitkey hitkey = hit_iter->first; - TrkrHit *tpchit = hit_iter->second; - if (Verbosity() > 5) - std::cout << " LAYER " << layer << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) << " t bin " << TpcDefs::getTBin(hitkey) - << " adc " << tpchit->getAdc() << std::endl; + if (adc_bin < 0) adc_bin = 0; + if (adc_bin > 1023) adc_bin = 1023; + } // for (auto & adc_bin : t_sorted_hits) - if (tpchit->getAdc() == 0) - { - std::cout << " Oops! -- this hit not digitized and not deleted!" << std::endl; - } - } - } + } // for (auto & t_sorted_hits : hitset->getTimeFrameAdcData()) - // hittruthassoc->identify(); + } // for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; return; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index 4faf8e9649..968fc97735 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -46,6 +46,8 @@ class PHG4TpcDigitizer : public SubsysReco void SetENC(const float enc) { TpcEnc = enc; }; void set_drift_velocity(float vd) {_drift_velocity = vd;} void set_skip_noise_flag(const bool skip) {skip_noise = skip;} + void set_nPreSample(unsigned int s) {m_nPreSample = s;} + void set_nPostSample(unsigned int s) {m_nPostSample = s;} private: void CalculateCylinderCellADCScale(PHCompositeNode *topNode); @@ -64,12 +66,12 @@ class PHG4TpcDigitizer : public SubsysReco float ADCSignalConversionGain; float ADCNoiseConversionGain; + //! SAMPA zero-suppression digitization parameter + unsigned int m_nPreSample = 2; + unsigned int m_nPostSample = 3; bool skip_noise = false; - std::vector > phi_sorted_hits; - std::vector > t_sorted_hits; - std::vector adc_input; std::vector adc_hitid; std::vector is_populated; From cc450714d34bb4e888131904e2a2e2b5601992c4 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 5 Apr 2023 00:20:51 -0400 Subject: [PATCH 110/468] small clean up --- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index 968fc97735..35b3963d8c 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -72,10 +72,6 @@ class PHG4TpcDigitizer : public SubsysReco bool skip_noise = false; - std::vector adc_input; - std::vector adc_hitid; - std::vector is_populated; - // settings std::map _max_adc; std::map _energy_scale; From 7c007e52f06d5d632b6a4f35e31afcca29086a85 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 5 Apr 2023 11:18:36 -0400 Subject: [PATCH 111/468] Reverting changes to TpcClusterizer to 31c4e95 --- offline/packages/tpc/TpcClusterizer.cc | 149 +------------------------ 1 file changed, 3 insertions(+), 146 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index c3918baf60..a6e66f7d70 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -97,45 +97,7 @@ namespace }; pthread_mutex_t mythreadlock; - - std::vector clusterx; - std::vector clustery; - std::vector clusterz; - std::vector clustert; - std::vector clustert_early; - std::vector clusterE; - std::vector> hitx; - std::vector> hity; - std::vector> hitz; - std::vector> hitE; - - /* - void set_hitData(double x, double y, double z, double e){ - m_hitx.push_back(x); - m_hity.push_back(y); - m_hitz.push_back(z); - m_hitE.push_back(e); - return; - } - - void clear_hitData(){ - m_hitx.clear(); - m_hity.clear(); - m_hitz.clear(); - m_hitE.clear(); - return; - } - - void set_clustData(double x, double y, double z, double e){ - m_clustx = x; - m_clusty = y; - m_clustz = z; - m_clustE = e; - return; - } - */ - void remove_hit(double adc, int phibin, int tbin, int edge, std::multimap &all_hit_map, std::vector> &adcval) { typedef std::multimap::iterator hit_iterator; @@ -349,19 +311,6 @@ namespace int max_adc = 0; if(clus_size == 1) return; // std::cout << "process list" << std::endl; - - std::vector temp_vectx; - std::vector temp_vecty; - std::vector temp_vectz; - std::vector temp_vectE; - - //std::cout << "made temp vectors" << std::endl; - - //clear_hitData(); - //::m_hitx.clear(); - //::m_hity.clear(); - //::m_hitz.clear(); - //::m_hitE.clear(); std::vector hitkeyvec; for(auto iter = ihit_list.begin(); iter != ihit_list.end();++iter){ double adc = iter->adc; @@ -376,19 +325,6 @@ namespace if(it > tbinhi) tbinhi = it; if(it < tbinlo) tbinlo = it; - double hitPhi = my_data.layergeom->get_phicenter(iphi); - - //std::cout << "working on hit " << std::distance(std::begin(ihit_list),iter) << std::endl; - - //set_hitData(radius * cos(hitPhi), radius * sin(hitPhi), my_data.layergeom->get_zcenter(it),adc); - temp_vectx.push_back(radius * cos(hitPhi)); - temp_vecty.push_back(radius * sin(hitPhi)); - temp_vectz.push_back(my_data.layergeom->get_zcenter(it)); - temp_vectE.push_back(adc); - - //std::cout << "pushed back temp vectors" << std::endl; - - // update phi sums // double phi_center = my_data.layergeom->get_phicenter(iphi); @@ -469,9 +405,6 @@ namespace // To get equivalent charge per T bin, so that summing ADC input voltage over all T bins returns total input charge, divide voltages by 2.4 for 80 ns SAMPA // Equivalent charge per T bin is then (ADU x 2200 mV / 1024) / 2.4 x (1/20) fC/mV x (1/1.6e-04) electrons/fC x (1/2000) = ADU x 0.14 - clustert_early.push_back(clust); - - // SAMPA shaping bias correction clust = clust + my_data.sampa_tbias; @@ -483,25 +416,8 @@ namespace //std::cout << "done transform" << std::endl; // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) - //set_clustData(clusx,clusy,clusz,adc_sum); - - hitx.push_back(temp_vectx); - hity.push_back(temp_vecty); - hitz.push_back(temp_vectz); - hitE.push_back(temp_vectE); - - clusterx.push_back(clusx); - clustery.push_back(clusy); - clusterz.push_back(clusz); - clustert.push_back(clust); - clusterE.push_back(adc_sum); - - // std::cout << "pushed back namespace vectors" << std::endl; - - // ::m_cluster_tree->Fill(); - if(my_data.cluster_version==3){ - // std::cout << "ver3" << std::endl; + std::cout << "ver3" << std::endl; // Fill in the cluster details //================ auto clus = new TrkrClusterv3; @@ -516,7 +432,7 @@ namespace clus->setActsLocalError(1,1, t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2)); my_data.cluster_vector.push_back(clus); }else if(my_data.cluster_version==4){ - // std::cout << "ver4" << std::endl; + std::cout << "ver4" << std::endl; // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if(sqrt(phi_err_square) > 0.01){ auto clus = new TrkrClusterv4; @@ -535,6 +451,7 @@ namespace my_data.cluster_vector.push_back(clus); } }else if(my_data.cluster_version==5){ + std::cout << "ver5" << std::endl; // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if(sqrt(phi_err_square) > 0.01){ auto clus = new TrkrClusterv5; @@ -843,28 +760,6 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } - m_outfile = new TFile(m_filename.c_str(),"RECREATE"); - - m_hitEnergy = new TH1F("m_hitEnergy","",10000,0.0,1e-4); - m_cluster_hitEnergy = new TH1F("m_cluster_hitEnergy","",10000,0.0,100); - m_hit_clusterEnergy = new TH2F("m_hit_clusterEnergy","",10000,0.0,1e-4,10000,0.0,100); - - m_cluster_tree = new TTree("m_cluster_tree",""); - - m_cluster_tree->Branch("clustx",&m_clustx); - m_cluster_tree->Branch("clusty",&m_clusty); - m_cluster_tree->Branch("clustz",&m_clustz); - m_cluster_tree->Branch("clustt",&m_clustt); - m_cluster_tree->Branch("clustt_early",&m_clustt_early); - m_cluster_tree->Branch("clustE",&m_clustE); - - m_cluster_tree->Branch("hitx",&m_hitx); - m_cluster_tree->Branch("hity",&m_hity); - m_cluster_tree->Branch("hitz",&m_hitz); - m_cluster_tree->Branch("hitE",&m_hitE); - - - return Fun4AllReturnCodes::EVENT_OK; } @@ -1225,31 +1120,6 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) } } - // std::cout << "about to push back member vectors" << std::endl; - - for(int ic=0; ic<(int)clusterx.size(); ic++){ - //std::cout << "cluster number " << ic << std::endl; - - m_clustx = clusterx[ic]; - m_clusty = clustery[ic]; - m_clustz = clusterz[ic]; - m_clustt = clustert[ic]; - m_clustt_early = clustert_early[ic]; - m_clustE = clusterE[ic]; - - m_hitx = hitx[ic]; - m_hity = hity[ic]; - m_hitz = hitz[ic]; - m_hitE = hitE[ic]; - - //std::cout << "pushed back member vectors" << std::endl; - - m_cluster_tree->Fill(); - - //std::cout << "Filled tree" << std::endl; - - } - if (Verbosity() > 0) std::cout << "TPC Clusterizer found " << m_clusterlist->size() << " Clusters " << std::endl; return Fun4AllReturnCodes::EVENT_OK; @@ -1257,18 +1127,5 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) int TpcClusterizer::End(PHCompositeNode */*topNode*/) { - - m_outfile->cd(); - - m_cluster_tree->Write(); - - m_hitEnergy->Write(); - m_cluster_hitEnergy->Write(); - m_hit_clusterEnergy->Write(); - - - - m_outfile->Close(); - return Fun4AllReturnCodes::EVENT_OK; } From b0a440d825bc5fa7d14f7b07defda95fce87976c Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 5 Apr 2023 12:20:36 -0400 Subject: [PATCH 112/468] Added virtual methods to CMFlashCluster.h for get/set IsRGap and IsPhiGap. Added calls in v2 CopyFrom --- offline/packages/trackbase/CMFlashCluster.h | 5 +++++ offline/packages/trackbase/CMFlashClusterv2.cc | 2 ++ 2 files changed, 7 insertions(+) diff --git a/offline/packages/trackbase/CMFlashCluster.h b/offline/packages/trackbase/CMFlashCluster.h index 411b2b2e9e..cc2cf5f423 100644 --- a/offline/packages/trackbase/CMFlashCluster.h +++ b/offline/packages/trackbase/CMFlashCluster.h @@ -59,6 +59,11 @@ class CMFlashCluster : public PHObject virtual unsigned int getAdc() const { return UINT_MAX; } virtual unsigned int getNclusters() const {return UINT_MAX;} virtual void setNclusters( unsigned int) {} + virtual void setIsRGap(bool) {} + virtual bool getIsRGap() const { return false; } + virtual void setIsPhiGap(bool) {} + virtual bool getIsPhiGap() const { return false; } + protected: CMFlashCluster() = default; diff --git a/offline/packages/trackbase/CMFlashClusterv2.cc b/offline/packages/trackbase/CMFlashClusterv2.cc index 290b6b766f..978ef70e5b 100644 --- a/offline/packages/trackbase/CMFlashClusterv2.cc +++ b/offline/packages/trackbase/CMFlashClusterv2.cc @@ -48,6 +48,8 @@ void CMFlashClusterv2::CopyFrom( const CMFlashCluster& source ) setY( source.getY() ); setZ( source.getZ() ); setAdc( source.getAdc() ); + setIsRGap( source.getIsRGap() ); + setIsPhiGap( source.getIsPhiGap() ); } From e884157cca1e0d5514479dbc84c3d6f28cb9416f Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 5 Apr 2023 12:26:44 -0400 Subject: [PATCH 113/468] Removed personal debugging info from electron drift --- .../g4tpc/PHG4TpcElectronDrift.cc | 45 +------- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 106 ------------------ 2 files changed, 2 insertions(+), 149 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 7b5b8f907c..ff9f97dc42 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -82,10 +83,6 @@ namespace } } // namespace -genElecs::genElecs(){} - -g4HitClass::g4HitClass(){} - PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) : SubsysReco(name) , PHParameterInterface(name) @@ -325,12 +322,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } std::cout << std::endl; } - - m_outfile = new TFile("/sphenix/user/bkimelman/gen1_CM_on_Feb8_v2/PHG4TpcElectronDrift_Ben.root","RECREATE"); - m_g4Hits = new g4HitClass(); - m_hitTree = new TTree("m_hitTree",""); - m_hitTree->Branch("g4Hits",&m_g4Hits); - + return Fun4AllReturnCodes::EVENT_OK; } @@ -455,18 +447,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) pow(hiter->second->get_y(1), 2)) << std::endl; } - m_g4Hits->set_g4xStart(hiter->second->get_x(0)); - m_g4Hits->set_g4yStart(hiter->second->get_y(0)); - m_g4Hits->set_g4zStart(hiter->second->get_z(0)); - m_g4Hits->set_g4tStart(hiter->second->get_t(0)); - - m_g4Hits->set_g4xEnd(hiter->second->get_x(1)); - m_g4Hits->set_g4yEnd(hiter->second->get_y(1)); - m_g4Hits->set_g4zEnd(hiter->second->get_z(1)); - m_g4Hits->set_g4yEnd(hiter->second->get_t(1)); - - m_g4Hits->set_g4E(eion); - for (unsigned int i = 0; i < n_electrons; i++) { // We choose the electron starting position at random from a flat @@ -480,13 +460,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) const double z_start = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); const double t_start = hiter->second->get_t(0) + f * (hiter->second->get_t(1) - hiter->second->get_t(0)); - genElecs *tmp_elec = new genElecs(); - - tmp_elec->set_xStart(x_start); - tmp_elec->set_yStart(y_start); - tmp_elec->set_zStart(z_start); - tmp_elec->set_tStart(t_start); - unsigned int side = 0; if (z_start > 0) side = 1; @@ -562,13 +535,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } } - tmp_elec->set_xEnd(x_final); - tmp_elec->set_yEnd(y_final); - tmp_elec->set_zEnd(z_final); - tmp_elec->set_tEnd(t_final); - - m_g4Hits->addElectron(tmp_elec); - // remove electrons outside of our acceptance. Careful though, electrons from just inside 30 cm can contribute in the 1st active layer readout, so leave a little margin if (rad_final < min_active_radius - 2.0 || rad_final > max_active_radius + 1.0) { continue; } @@ -705,9 +671,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) single_hitsetcontainer->Reset(); - m_hitTree->Fill(); - m_g4Hits->reset_g4_electrons(); - } // end loop over g4hits truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ true); @@ -804,10 +767,6 @@ int PHG4TpcElectronDrift::End(PHCompositeNode * /*topNode*/) z_startmap->Write(); EDrift_outf->Close(); } - - m_outfile->cd(); - m_hitTree->Write(); - m_outfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 26f6132f25..4d3f6ff183 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -21,7 +21,6 @@ class PHCompositeNode; class TH1; class TH2; class TNtuple; -class TTree; class TFile; class TrkrHitSetContainer; class TrkrHitTruthAssoc; @@ -32,104 +31,6 @@ class DistortedTrackContainer; class TpcClusterBuilder; class PHG4TpcCylinderGeomContainer; -class genElecs{ - public: - genElecs(); - ~genElecs(); - - void set_xStart(double a_x){ m_xStart = a_x; }; - void set_yStart(double a_y){ m_yStart = a_y; }; - void set_zStart(double a_z){ m_zStart = a_z; }; - void set_tStart(double a_t){ m_yStart = a_t; }; - - void set_xEnd(double a_x){ m_xEnd = a_x; }; - void set_yEnd(double a_y){ m_yEnd = a_y; }; - void set_zEnd(double a_z){ m_zEnd = a_z; }; - void set_tEnd(double a_t){ m_tEnd = a_t; }; - - double get_xStart(){ return m_xStart; }; - double get_yStart(){ return m_yStart; }; - double get_zStart(){ return m_zStart; }; - double get_tStart(){ return m_tStart; }; - - double get_xEnd(){ return m_xEnd; }; - double get_yEnd(){ return m_yEnd; }; - double get_zEnd(){ return m_zEnd; }; - double get_tEnd(){ return m_tEnd; }; - - //void resetElec(){ m_xStart=0.0; m_yStart=0.0; m_zStart=0.0; m_tStart=0.0; m_xEnd=0.0; m_yEnd=0.0; m_zEnd=0.0; m_tEnd=0.0; }; - - private: - double m_xStart; - double m_yStart; - double m_zStart; - double m_tStart; - - double m_xEnd; - double m_yEnd; - double m_zEnd; - double m_tEnd; - -}; - -class g4HitClass{ - public: - g4HitClass(); - ~g4HitClass(); - - void set_g4xStart(double a_x){ m_g4xStart = a_x; }; - void set_g4yStart(double a_y){ m_g4yStart = a_y; }; - void set_g4zStart(double a_z){ m_g4zStart = a_z; }; - void set_g4tStart(double a_t){ m_g4tStart = a_t; }; - - void set_g4xEnd(double a_x){ m_g4xEnd = a_x; }; - void set_g4yEnd(double a_y){ m_g4yEnd = a_y; }; - void set_g4zEnd(double a_z){ m_g4zEnd = a_z; }; - void set_g4tEnd(double a_t){ m_g4tEnd = a_t; }; - - void set_g4E(double a_E){ m_g4E = a_E; }; - - void addElectron(genElecs *a_elec){ m_elecs.push_back(a_elec); }; - - double get_g4xStart(){ return m_g4xStart; }; - double get_g4yStart(){ return m_g4yStart; }; - double get_g4zStart(){ return m_g4zStart; }; - double get_g4tStart(){ return m_g4tStart; }; - - double get_g4xEnd(){ return m_g4xEnd; }; - double get_g4yEnd(){ return m_g4yEnd; }; - double get_g4zEnd(){ return m_g4zEnd; }; - double get_g4tEnd(){ return m_g4tEnd; }; - - double get_g4E(){ return m_g4E; }; - int get_nElec(){ return (int)m_elecs.size(); }; - - genElecs* getElectron(int elecIndex){ return m_elecs[elecIndex]; }; - - void reset_g4_electrons(){ m_elecs.clear(); }; - - //void reset_g4Hits(){ m_g4x=0.0; m_g4y=0.0; m_g4z=0.0; m_g4t=0.0; m_g4E=0.0; m_elecs.clear(); }; - - - private: - - double m_g4xStart; - double m_g4yStart; - double m_g4zStart; - double m_g4tStart; - - double m_g4xEnd; - double m_g4yEnd; - double m_g4zEnd; - double m_g4tEnd; - - double m_g4E; - - std::vector m_elecs; - -}; - - class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface { public: @@ -163,7 +64,6 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface //! setup readout plane void registerPadPlane(PHG4TpcPadPlane *padplane); - private: //! map a given x,y,z coordinates to plane hits /* TpcClusterBuilder MapToPadPlane(const double x, const double y, const */ @@ -231,11 +131,6 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface double max_time = NAN; - TFile *m_outfile; - TTree *m_hitTree; - g4HitClass *m_g4Hits; - - /* std::array layer_clusterers; // Generate TrkrClusterv4's for TrkrTruthTracks */ TpcClusterBuilder* truth_clusterer { nullptr }; @@ -251,5 +146,4 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface std::unique_ptr RandomGenerator; }; - #endif // G4TPC_PHG4TPCELECTRONDRIFT_H From 458c0b23267a59a944b204c5b5038fa5939bd859 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 5 Apr 2023 12:31:30 -0400 Subject: [PATCH 114/468] Reverted m_rbins and m_phibins to original values --- offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 21420bb6a1..d9fb2e6339 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -133,13 +133,13 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@{ /// distortion correction grid size along phi - int m_phibins = 200; + int m_phibins = 36; static constexpr float m_phiMin = 0; static constexpr float m_phiMax = 2.*M_PI; /// distortion correction grid size along r - int m_rbins = 58; + int m_rbins = 16; static constexpr float m_rMin = 20; // cm static constexpr float m_rMax = 78; // cm From 872cd1bc5c0faf4ee563c5a053f9304bc9812091 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 5 Apr 2023 13:39:23 -0400 Subject: [PATCH 115/468] Removed unnecessary include statements --- offline/packages/trackbase/CMFlashClusterContainerv1.cc | 2 -- simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 1 - 2 files changed, 3 deletions(-) diff --git a/offline/packages/trackbase/CMFlashClusterContainerv1.cc b/offline/packages/trackbase/CMFlashClusterContainerv1.cc index 95a8467bf2..f7389278cd 100644 --- a/offline/packages/trackbase/CMFlashClusterContainerv1.cc +++ b/offline/packages/trackbase/CMFlashClusterContainerv1.cc @@ -6,8 +6,6 @@ */ #include "CMFlashClusterContainerv1.h" #include "CMFlashCluster.h" -#include "CMFlashClusterv1.h" -//#include "CMFlashClusterv2.h" #include diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index ff9f97dc42..abbe1145b3 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -23,7 +23,6 @@ #include #include -#include #include #include From 4c99ba619b730d0bb56ebb264990ce9fab00ee7e Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 5 Apr 2023 13:39:39 -0400 Subject: [PATCH 116/468] Adding reading gain from maps --- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 31 +++++++++++-------- .../g4tpc/PHG4TpcPadPlaneReadout.h | 6 ++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 20be17a3e2..445b86c34e 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -62,16 +62,6 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) : PHG4TpcPadPlane(name) { InitializeParameters(); - // Reading TPC Gain Maps from the file - if(_flagToUseGain==1){ - std::cout<<"PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout :::"<Get("RadPhiPlot0")->Clone(); - h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); - h_gain[0]->SetDirectory(0); - h_gain[1]->SetDirectory(0); - fileGain->Close(); - } RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion @@ -293,10 +283,8 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( double phi_gain = phi; if(phi<0)phi_gain += 2*M_PI; double gain_weight = 1.0; - if(_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm - std::cout<Get("RadPhiPlot0")->Clone(); + h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); + h_gain[0]->SetDirectory(0); + h_gain[1]->SetDirectory(0); + fileGain->Close(); + } + //return; +} void PHG4TpcPadPlaneReadout::SetDefaultParameters() { set_default_int_param("ntpc_layers_inner", 16); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index edd4f0b770..0e6053f65d 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -30,9 +30,9 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane ~PHG4TpcPadPlaneReadout() override; - void SetDriftVelocity(double vd) override { drift_velocity = vd; } - void UseGain(int flagToUseGain) {_flagToUseGain = flagToUseGain;}; + void UseGain(const int flagToUseGain); + void SetDriftVelocity(double vd) override { drift_velocity = vd; } int CreateReadoutGeometry(PHCompositeNode *topNode, PHG4TpcCylinderGeomContainer *seggeo) override; @@ -92,7 +92,7 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array SectorPhi; int m_NHits = 0; - int _flagToUseGain = 0; + int m_flagToUseGain = 0; // gaussian sampling static constexpr double _nsigmas = 5; From 79dd2152e7a996611e0d63ea225837a458c698a2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 5 Apr 2023 16:18:13 -0400 Subject: [PATCH 117/468] Use bbc vertex instead of 0,0,0. In the event bbc vertex is also not available, still propagates to 0,0,0 but vertex associated to track remains as bbc vertex nan --- offline/packages/trackreco/Makefile.am | 1 + .../trackreco/PHActsVertexPropagator.cc | 39 +++++++++++++++---- .../trackreco/PHActsVertexPropagator.h | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index b1693c8e28..29404d795d 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -163,6 +163,7 @@ libtrack_reco_la_LIBADD = \ -lg4tpc \ -lg4intt \ -lg4mvtx \ + -lbbc_io \ -lmicromegas_io \ -lmvtx_io \ -lintt_io \ diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index a1d30e073f..d3b94ff77c 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -12,6 +12,8 @@ #include #include +#include + #include #include #include @@ -37,11 +39,15 @@ int PHActsVertexPropagator::InitRun(PHCompositeNode* topNode) int returnval = getNodes(topNode); return returnval; } -int PHActsVertexPropagator::process_event(PHCompositeNode*) +int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) { if (m_vertexMap->size() == 0) { - setTrackVertexTo0(); + bool ret = setTrackVertexToBbc(topNode); + if(!ret) + { + return Fun4AllReturnCodes::EVENT_OK; + } } std::vector deletedKeys; @@ -178,6 +184,12 @@ PHActsVertexPropagator::propagateTrack( { /// create perigee surface auto actsVertex = getVertex(vtxid); + + /// BBC vertex wasn't found. Propagate to perigee at 0,0,0 + if(actsVertex(2) < -9999) + { + actsVertex = Acts::Vector3::Zero(); + } auto perigee = Acts::Surface::makeShared(actsVertex); ActsPropagator propagator(m_tGeometry); @@ -195,17 +207,25 @@ Acts::Vector3 PHActsVertexPropagator::getVertex(const unsigned int vtxid) svtxVertex->get_z() * Acts::UnitConstants::cm); } -void PHActsVertexPropagator::setTrackVertexTo0() +bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) { - /// If we found no vertices in the event, propagate the tracks to 0,0,0 + auto bbcmap = findNode::getClass(topNode, "BbcOut"); + if(!bbcmap) + { + std::cout << PHWHERE << "Can't propagate tracks as no vertex was found" + << std::endl; + return false; + } + + /// If we found no vertices in the event, propagate the tracks to 0,0,bbcz auto vertex = std::make_unique(); vertex->set_chisq(0.); vertex->set_ndof(0); - vertex->set_t0(0); + vertex->set_t0(bbcmap->get_TimeZero()); vertex->set_id(0); vertex->set_x(0); vertex->set_y(0); - vertex->set_z(0); + vertex->set_z(bbcmap->get_VertexPoint()); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) @@ -213,15 +233,18 @@ void PHActsVertexPropagator::setTrackVertexTo0() vertex->set_error(i, j, 20.); } } - + vertex->set_error(2,2, bbcmap->get_dVertexPoint() * bbcmap->get_dVertexPoint()); m_vertexMap->insert(vertex.release()); - + for (auto& [key, track] : *m_trackMap) { track->set_vertex_id(0); } + + return true; } + int PHActsVertexPropagator::End(PHCompositeNode*) { return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/trackreco/PHActsVertexPropagator.h b/offline/packages/trackreco/PHActsVertexPropagator.h index ed17f5814f..4111529e44 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.h +++ b/offline/packages/trackreco/PHActsVertexPropagator.h @@ -36,7 +36,7 @@ class PHActsVertexPropagator : public SubsysReco private: int getNodes(PHCompositeNode *topNode); - void setTrackVertexTo0(); + bool setTrackVertexToBbc(PHCompositeNode *topNode); ActsPropagator::BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters ¶ms, const unsigned int vtxid); From fb211017d24d07b63162c84d1370082486de905f Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Thu, 6 Apr 2023 07:55:03 -0400 Subject: [PATCH 118/468] Update for TowerInfo objects --- .../CaloReco/RawClusterBuilderTopo.cc | 475 ++++++++++-------- 1 file changed, 279 insertions(+), 196 deletions(-) diff --git a/offline/packages/CaloReco/RawClusterBuilderTopo.cc b/offline/packages/CaloReco/RawClusterBuilderTopo.cc index d939506436..ec967830b0 100644 --- a/offline/packages/CaloReco/RawClusterBuilderTopo.cc +++ b/offline/packages/CaloReco/RawClusterBuilderTopo.cc @@ -7,6 +7,10 @@ #include #include #include +#include + +#include +#include #include #include @@ -19,6 +23,19 @@ #include #include +#include +#include +#include + +#include +#include + +#include + +//root +#include +#include + #include #include #include // for abs @@ -57,14 +74,8 @@ float RawClusterBuilderTopo::calculate_dR(float eta1, float eta2, float phi1, fl { float deta = eta1 - eta2; float dphi = phi1 - phi2; - while (dphi > M_PI) - { - dphi -= 2 * M_PI; - } - while (dphi < -M_PI) - { - dphi += 2 * M_PI; - } + while (dphi > M_PI) dphi -= 2 * M_PI; + while (dphi < -M_PI) dphi += 2 * M_PI; return sqrt(pow(deta, 2) + pow(dphi, 2)); } @@ -85,10 +96,7 @@ std::vector RawClusterBuilderTopo::get_adjacent_towers_by_ID(int ID) { for (int delta_phi = -1; delta_phi <= 1; delta_phi++) { - if (delta_layer == 0 && delta_eta == 0 && delta_phi == 0) - { - continue; // this is the same tower - } + if (delta_layer == 0 && delta_eta == 0 && delta_phi == 0) continue; // this is the same tower int test_eta = this_eta + delta_eta; if (test_eta < 0 || test_eta >= _HCAL_NETA) @@ -102,10 +110,7 @@ std::vector RawClusterBuilderTopo::get_adjacent_towers_by_ID(int ID) // disallow "corner" adjacency (diagonal in eta/phi plane and in different layer) if this option not enabled if (!_allow_corner_neighbor && delta_layer == 1 && abs(delta_phi) == 1 && abs(delta_eta) == 1) { - if (Verbosity() > 20) - { - std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : corner growth not allowed " << std::endl; - } + if (Verbosity() > 20) std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : corner growth not allowed " << std::endl; continue; } @@ -130,10 +135,7 @@ std::vector RawClusterBuilderTopo::get_adjacent_towers_by_ID(int ID) int new_phi = (EMCal_phi_start + delta_phi + _EMCAL_NPHI) % _EMCAL_NPHI; int EMCal_tower = get_ID(2, new_eta, new_phi); - if (Verbosity() > 20) - { - std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : HCal tower with eta / phi = " << this_eta << " / " << this_phi << ", adding EMCal tower with eta / phi = " << new_eta << " / " << new_phi << std::endl; - } + if (Verbosity() > 20) std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : HCal tower with eta / phi = " << this_eta << " / " << this_phi << ", adding EMCal tower with eta / phi = " << new_eta << " / " << new_phi << std::endl; adjacent_towers.push_back(EMCal_tower); } } @@ -147,10 +149,7 @@ std::vector RawClusterBuilderTopo::get_adjacent_towers_by_ID(int ID) { for (int delta_phi = -1; delta_phi <= 1; delta_phi++) { - if (delta_eta == 0 && delta_phi == 0) - { - continue; // this is the same tower - } + if (delta_eta == 0 && delta_phi == 0) continue; // this is the same tower int test_eta = this_eta + delta_eta; if (test_eta < 0 || test_eta >= _EMCAL_NETA) @@ -174,18 +173,12 @@ std::vector RawClusterBuilderTopo::get_adjacent_towers_by_ID(int ID) if (HCal_eta >= 0) { int IHCal_tower = get_ID(0, HCal_eta, HCal_phi); - if (Verbosity() > 20) - { - std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : EMCal tower with eta / phi = " << this_eta << " / " << this_phi << ", adding IHCal tower with eta / phi = " << HCal_eta << " / " << HCal_phi << std::endl; - } + if (Verbosity() > 20) std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : EMCal tower with eta / phi = " << this_eta << " / " << this_phi << ", adding IHCal tower with eta / phi = " << HCal_eta << " / " << HCal_phi << std::endl; adjacent_towers.push_back(IHCal_tower); } else { - if (Verbosity() > 20) - { - std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : EMCal tower with eta / phi = " << this_eta << " / " << this_phi << ", does not have matching IHCal due to large eta " << std::endl; - } + if (Verbosity() > 20) std::cout << "RawClusterBuilderTopo::get_adjacent_towers_by_ID : EMCal tower with eta / phi = " << this_eta << " / " << this_phi << ", does not have matching IHCal due to large eta " << std::endl; } } } @@ -215,9 +208,7 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow if (n_clusters != 1) // if we didn't just pass down from export_single_cluster { if (Verbosity() > 2) - { std::cout << "RawClusterBuilderTopo::export_clusters called on an initial cluster with " << n_clusters << " final clusters " << std::endl; - } } // build a RawCluster for output std::vector clusters; @@ -317,6 +308,10 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow _clusters->AddCluster(clusters[cl]); + _tree_cluster_e.push_back(clusters_E[cl]); + _tree_cluster_eta.push_back(-1 * log(tan(std::atan2(std::sqrt(mean_y * mean_y + mean_x * mean_x), mean_z) / 2.0))); + _tree_cluster_phi.push_back(std::atan2(mean_y, mean_x)); + if (Verbosity() > 1) { std::cout << "RawClusterBuilderTopo::export_clusters: added cluster with E = " << clusters_E[cl] << ", eta = " << -1 * log(tan(std::atan2(std::sqrt(mean_y * mean_y + mean_x * mean_x), mean_z) / 2.0)) << ", phi = " << std::atan2(mean_y, mean_x) << std::endl; @@ -326,8 +321,11 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow return; } -RawClusterBuilderTopo::RawClusterBuilderTopo(const std::string &name) +RawClusterBuilderTopo::RawClusterBuilderTopo(const std::string &name, const std::string &filename) : SubsysReco(name) + , _outfilename(filename) + , _outfile(nullptr) + , _tree(nullptr) { // geometry defined at run-time _EMCAL_NETA = -1; @@ -381,30 +379,42 @@ int RawClusterBuilderTopo::InitRun(PHCompositeNode *topNode) std::cout << "RawClusterBuilderTopo::InitRun: initialized with minE for local max in EMCal / IHCal / OHCal = " << _local_max_minE_LAYER[2] << " / " << _local_max_minE_LAYER[0] << " / " << _local_max_minE_LAYER[1] << std::endl; } + initializeTrees(); + return Fun4AllReturnCodes::EVENT_OK; } int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) { - RawTowerContainer *towersEM = findNode::getClass(topNode, "TOWER_CALIB_CEMC"); - RawTowerContainer *towersIH = findNode::getClass(topNode, "TOWER_CALIB_HCALIN"); - RawTowerContainer *towersOH = findNode::getClass(topNode, "TOWER_CALIB_HCALOUT"); - if (!towersEM) + CentralityInfo* cent_node = findNode::getClass(topNode, "CentralityInfo"); + if (!cent_node) { - std::cout << " RawClusterBuilderTopo::process_event : container TOWER_CALIB_CEMC does not exist, aborting " << std::endl; + std::cout << "RawClusterBuilderTopo::process_event - Error can not find centrality node " << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - if (!towersIH) + + TowerInfoContainer *towerinfosEM = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); + TowerInfoContainer *towerinfosIH = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALIN"); + TowerInfoContainer *towerinfosOH = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALOUT"); + + if (!towerinfosEM) { - std::cout << " RawClusterBuilderTopo::process_event : container TOWER_CALIB_HCALIN does not exist, aborting " << std::endl; + std::cout << " RawClusterBuilderTopo::process_event : container TOWERINFO_CALIB_CEMC does not exist, aborting " << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - if (!towersOH) + if (!towerinfosIH) { - std::cout << " RawClusterBuilderTopo::process_event : container TOWER_CALIB_HCALOUT does not exist, aborting " << std::endl; + std::cout << " RawClusterBuilderTopo::process_event : container TOWERINFO_CALIB_HCALIN does not exist, aborting " << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } + if (!towerinfosOH) + { + std::cout << " RawClusterBuilderTopo::process_event : container TOWERINFO_CALIB_HCALOUT does not exist, aborting " << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + _geom_containers[0] = findNode::getClass(topNode, "TOWERGEOM_HCALIN"); _geom_containers[1] = findNode::getClass(topNode, "TOWERGEOM_HCALOUT"); @@ -428,9 +438,9 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) if (Verbosity() > 10) { - std::cout << "RawClusterBuilderTopo::process_event: " << towersEM->size() << " TOWER_CALIB_CEMC towers" << std::endl; - std::cout << "RawClusterBuilderTopo::process_event: " << towersIH->size() << " TOWER_CALIB_HCALIN towers" << std::endl; - std::cout << "RawClusterBuilderTopo::process_event: " << towersOH->size() << " TOWER_CALIB_HCALOUT towers" << std::endl; + std::cout << "RawClusterBuilderTopo::process_event: " << towerinfosEM->size() << " TOWERINFO_CALIB_CEMC towers" << std::endl; + std::cout << "RawClusterBuilderTopo::process_event: " << towerinfosIH->size() << " TOWERINFO_CALIB_HCALIN towers" << std::endl; + std::cout << "RawClusterBuilderTopo::process_event: " << towerinfosOH->size() << " TOWERINFO_CALIB_HCALOUT towers" << std::endl; std::cout << "RawClusterBuilderTopo::process_event: pointer to TOWERGEOM_CEMC: " << _geom_containers[2] << std::endl; std::cout << "RawClusterBuilderTopo::process_event: pointer to TOWERGEOM_HCALIN: " << _geom_containers[0] << std::endl; @@ -487,19 +497,26 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // translate towers to our internal representation if (_enable_EMCal) { - RawTowerContainer::ConstRange begin_end_EM = towersEM->getTowers(); - for (RawTowerContainer::ConstIterator rtiter = begin_end_EM.first; rtiter != begin_end_EM.second; ++rtiter) + TowerInfo *towerInfo = nullptr; + for(unsigned int iEM = 0; iEM < towerinfosEM->size(); iEM++) { - RawTower *tower = rtiter->second; - RawTowerGeom *tower_geom = _geom_containers[2]->get_tower_geometry(tower->get_key()); + towerInfo = towerinfosEM->get_tower_at_channel(iEM); + unsigned int towerinfo_key = towerinfosEM->encode_key(iEM); + int ti_ieta = towerinfosEM->getTowerEtaBin(towerinfo_key); + int ti_iphi = towerinfosEM->getTowerPhiBin(towerinfo_key); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, ti_ieta, ti_iphi); + + RawTowerGeom *tower_geom = _geom_containers[2]->get_tower_geometry(key); int ieta = _geom_containers[2]->get_etabin(tower_geom->get_eta()); int iphi = _geom_containers[2]->get_phibin(tower_geom->get_phi()); - float this_E = tower->get_energy(); + float this_E = towerInfo->get_energy(); + + if(this_E < 1.E-10) continue; _EMTOWERMAP_STATUS_ETA_PHI[ieta][iphi] = -1; // change status to unknown _EMTOWERMAP_E_ETA_PHI[ieta][iphi] = this_E; - _EMTOWERMAP_KEY_ETA_PHI[ieta][iphi] = tower->get_key(); + _EMTOWERMAP_KEY_ETA_PHI[ieta][iphi] = key; if (this_E > _sigma_seed * _noise_LAYER[2]) { @@ -517,19 +534,26 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // translate towers to our internal representation if (_enable_HCal) { - RawTowerContainer::ConstRange begin_end_IH = towersIH->getTowers(); - for (RawTowerContainer::ConstIterator rtiter = begin_end_IH.first; rtiter != begin_end_IH.second; ++rtiter) + TowerInfo *towerInfo = nullptr; + for(unsigned int iIH = 0; iIH < towerinfosIH->size(); iIH++) { - RawTower *tower = rtiter->second; - RawTowerGeom *tower_geom = _geom_containers[0]->get_tower_geometry(tower->get_key()); + towerInfo = towerinfosIH->get_tower_at_channel(iIH); + unsigned int towerinfo_key = towerinfosIH->encode_key(iIH); + int ti_ieta = towerinfosIH->getTowerEtaBin(towerinfo_key); + int ti_iphi = towerinfosIH->getTowerPhiBin(towerinfo_key); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, ti_ieta, ti_iphi); + + RawTowerGeom *tower_geom = _geom_containers[0]->get_tower_geometry(key); int ieta = _geom_containers[0]->get_etabin(tower_geom->get_eta()); int iphi = _geom_containers[0]->get_phibin(tower_geom->get_phi()); - float this_E = tower->get_energy(); + float this_E = towerInfo->get_energy(); + + if(this_E < 1.E-10) continue; _TOWERMAP_STATUS_LAYER_ETA_PHI[0][ieta][iphi] = -1; // change status to unknown _TOWERMAP_E_LAYER_ETA_PHI[0][ieta][iphi] = this_E; - _TOWERMAP_KEY_LAYER_ETA_PHI[0][ieta][iphi] = tower->get_key(); + _TOWERMAP_KEY_LAYER_ETA_PHI[0][ieta][iphi] = key; if (this_E > _sigma_seed * _noise_LAYER[0]) { @@ -543,19 +567,25 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) } } - RawTowerContainer::ConstRange begin_end_OH = towersOH->getTowers(); - for (RawTowerContainer::ConstIterator rtiter = begin_end_OH.first; rtiter != begin_end_OH.second; ++rtiter) + for(unsigned int iOH = 0; iOH < towerinfosOH->size(); iOH++) { - RawTower *tower = rtiter->second; - RawTowerGeom *tower_geom = _geom_containers[1]->get_tower_geometry(tower->get_key()); + towerInfo = towerinfosOH->get_tower_at_channel(iOH); + unsigned int towerinfo_key = towerinfosOH->encode_key(iOH); + int ti_ieta = towerinfosOH->getTowerEtaBin(towerinfo_key); + int ti_iphi = towerinfosOH->getTowerPhiBin(towerinfo_key); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, ti_ieta, ti_iphi); + + RawTowerGeom *tower_geom = _geom_containers[1]->get_tower_geometry(key); int ieta = _geom_containers[1]->get_etabin(tower_geom->get_eta()); int iphi = _geom_containers[1]->get_phibin(tower_geom->get_phi()); - float this_E = tower->get_energy(); + float this_E = towerInfo->get_energy(); + + if(this_E < 1.E-10) continue; _TOWERMAP_STATUS_LAYER_ETA_PHI[1][ieta][iphi] = -1; // change status to unknown _TOWERMAP_E_LAYER_ETA_PHI[1][ieta][iphi] = this_E; - _TOWERMAP_KEY_LAYER_ETA_PHI[1][ieta][iphi] = tower->get_key(); + _TOWERMAP_KEY_LAYER_ETA_PHI[1][ieta][iphi] = key; if (this_E > _sigma_seed * _noise_LAYER[1]) { @@ -589,9 +619,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) } if (Verbosity() > 0) - { std::cout << "RawClusterBuilderTopo::process_event: initialized with " << list_of_seeds.size() << " seeds with E > 4*sigma " << std::endl; - } int cluster_index = 0; // begin counting clusters @@ -667,30 +695,21 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // if tower is owned by THIS cluster already, continue if (get_status_from_ID(this_adjacent_tower_ID) == cluster_index) { - if (Verbosity() > 10) - { - std::cout << "already owned by this cluster index " << cluster_index << std::endl; - } + if (Verbosity() > 10) std::cout << "already owned by this cluster index " << cluster_index << std::endl; continue; } // if tower has < 2*sigma energy, continue if (get_E_from_ID(this_adjacent_tower_ID) < _sigma_grow * _noise_LAYER[test_layer]) { - if (Verbosity() > 10) - { - std::cout << "E = " << get_E_from_ID(this_adjacent_tower_ID) << " under 2*sigma threshold " << std::endl; - } + if (Verbosity() > 10) std::cout << "E = " << get_E_from_ID(this_adjacent_tower_ID) << " under 2*sigma threshold " << std::endl; continue; } // if tower is owned by somebody else, continue (although should this really happen?) if (get_status_from_ID(this_adjacent_tower_ID) > -1) { - if (Verbosity() > 10) - { - std::cout << "ERROR! in growth stage, encountered >2sigma tower which is already owned?!" << std::endl; - } + if (Verbosity() > 10) std::cout << "ERROR! in growth stage, encountered >2sigma tower which is already owned?!" << std::endl; continue; } @@ -698,16 +717,10 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) grow_tower_ID.push_back(this_adjacent_tower_ID); cluster_tower_ID.push_back(this_adjacent_tower_ID); set_status_by_ID(this_adjacent_tower_ID, cluster_index); - if (Verbosity() > 10) - { - std::cout << "add this tower ( ID " << this_adjacent_tower_ID << " ) to grow list " << std::endl; - } + if (Verbosity() > 10) std::cout << "add this tower ( ID " << this_adjacent_tower_ID << " ) to grow list " << std::endl; } - if (Verbosity() > 5) - { - std::cout << " --> after examining neighbors, grow list is now " << grow_tower_ID.size() << ", # of towers in cluster = " << cluster_tower_ID.size() << std::endl; - } + if (Verbosity() > 5) std::cout << " --> after examining neighbors, grow list is now " << grow_tower_ID.size() << ", # of towers in cluster = " << cluster_tower_ID.size() << std::endl; } // done growing cluster, now add on perimeter towers with E > 0 * sigma @@ -730,56 +743,40 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (Verbosity() > 10) - { - std::cout << " --> --> --> checking possible adjacent tower with ID " << this_adjacent_tower_ID << " : "; - } + if (Verbosity() > 10) std::cout << " --> --> --> checking possible adjacent tower with ID " << this_adjacent_tower_ID << " : "; int test_layer = get_ilayer_from_ID(this_adjacent_tower_ID); // if tower does not exist, continue if (get_status_from_ID(this_adjacent_tower_ID) == -2) { - if (Verbosity() > 10) - { - std::cout << "does not exist " << std::endl; - } + if (Verbosity() > 10) std::cout << "does not exist " << std::endl; continue; } // if tower is owned by somebody else (including current cluster), continue. ( allowed during perimeter fixing state ) if (get_status_from_ID(this_adjacent_tower_ID) > -1) { - if (Verbosity() > 10) - { - std::cout << "already owned by other cluster index " << get_status_from_ID(this_adjacent_tower_ID) << std::endl; - } + if (Verbosity() > 10) std::cout << "already owned by other cluster index " << get_status_from_ID(this_adjacent_tower_ID) << std::endl; continue; } // if tower has < 0*sigma energy, continue if (get_E_from_ID(this_adjacent_tower_ID) < _sigma_peri * _noise_LAYER[test_layer]) { - if (Verbosity() > 10) - { - std::cout << "E = " << get_E_from_ID(this_adjacent_tower_ID) << " under 0*sigma threshold " << std::endl; - } + if (Verbosity() > 10) std::cout << "E = " << get_E_from_ID(this_adjacent_tower_ID) << " under 0*sigma threshold " << std::endl; continue; } // perimeter tower good to be added to cluster cluster_tower_ID.push_back(this_adjacent_tower_ID); set_status_by_ID(this_adjacent_tower_ID, cluster_index); - if (Verbosity() > 10) - { - std::cout << "add this tower ( ID " << this_adjacent_tower_ID << " ) to cluster " << std::endl; - } + if (Verbosity() > 10) std::cout << "add this tower ( ID " << this_adjacent_tower_ID << " ) to cluster " << std::endl; } - if (Verbosity() > 5) - { - std::cout << " --> after examining perimeter neighbors, # of towers in cluster is now = " << cluster_tower_ID.size() << std::endl; - } + + + if (Verbosity() > 5) std::cout << " --> after examining perimeter neighbors, # of towers in cluster is now = " << cluster_tower_ID.size() << std::endl; } // keep track of these @@ -789,13 +786,30 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) cluster_index++; } - if (Verbosity() > 0) + if (Verbosity() > 0) std::cout << "RawClusterBuilderTopo::process_event: " << cluster_index << " topo-clusters initially reconstructed, entering splitting step" << std::endl; + + int original_cluster_index = cluster_index; // since it may be updated + //Fill the tree + resetTreeVariables(); + _tree_centrality = cent_node->get_centile(CentralityInfo::PROP::bimp); + for (int cl = 0; cl < original_cluster_index; cl++) { - std::cout << "RawClusterBuilderTopo::process_event: " << cluster_index << " topo-clusters initially reconstructed, entering splitting step" << std::endl; + std::vector original_towers = all_cluster_towers.at(cl); + + //fill tree with towers + for(auto tid : original_towers) + { + _tree_tower_id.push_back(tid); + _tree_tower_e.push_back(get_E_from_ID(tid)); + _tree_tower_cluster_id.push_back(cl); + } + _tree_cluster_id.push_back(cl); } + + // now entering cluster splitting stage - int original_cluster_index = cluster_index; // since it may be updated + for (int cl = 0; cl < original_cluster_index; cl++) { std::vector original_towers = all_cluster_towers.at(cl); @@ -803,10 +817,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) if (!_do_split) { // don't run splitting, just export entire cluster as it is - if (Verbosity() > 2) - { - std::cout << "RawClusterBuilderTopo::process_event: splitting step disabled, cluster " << cluster_index << " is final" << std::endl; - } + if (Verbosity() > 2) std::cout << "RawClusterBuilderTopo::process_event: splitting step disabled, cluster " << cluster_index << " is final" << std::endl; export_single_cluster(original_towers); continue; } @@ -816,18 +827,12 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // iterate through each tower, looking for maxima for (int tower_ID : original_towers) { - if (Verbosity() > 10) - { - std::cout << " -> examining tower ID " << tower_ID << " for possible local maximum " << std::endl; - } + if (Verbosity() > 10) std::cout << " -> examining tower ID " << tower_ID << " for possible local maximum " << std::endl; // check minimum energy if (get_E_from_ID(tower_ID) < _local_max_minE_LAYER[get_ilayer_from_ID(tower_ID)]) { - if (Verbosity() > 10) - { - std::cout << " -> -> energy E = " << get_E_from_ID(tower_ID) << " < " << _local_max_minE_LAYER[get_ilayer_from_ID(tower_ID)] << " too low" << std::endl; - } + if (Verbosity() > 10) std::cout << " -> -> energy E = " << get_E_from_ID(tower_ID) << " < " << _local_max_minE_LAYER[get_ilayer_from_ID(tower_ID)] << " too low" << std::endl; continue; } @@ -839,36 +844,24 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) bool has_higher_neighbor = false; for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; // only consider neighbors in cluster, obviously - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; // only consider neighbors in cluster, obviously neighbors_in_cluster++; if (get_E_from_ID(this_adjacent_tower_ID) > get_E_from_ID(tower_ID)) { - if (Verbosity() > 10) - { - std::cout << " -> -> has higher-energy neighbor ID / E = " << this_adjacent_tower_ID << " / " << get_E_from_ID(this_adjacent_tower_ID) << std::endl; - } + if (Verbosity() > 10) std::cout << " -> -> has higher-energy neighbor ID / E = " << this_adjacent_tower_ID << " / " << get_E_from_ID(this_adjacent_tower_ID) << std::endl; has_higher_neighbor = true; // at this point we can break -- we won't need to count the number of good neighbors, since we won't even pass the E_neighbor test break; } } - if (has_higher_neighbor) - { - continue; // if we broke out, now continue - } + if (has_higher_neighbor) continue; // if we broke out, now continue // check number of neighbors if (neighbors_in_cluster < 4) { - if (Verbosity() > 10) - { - std::cout << " -> -> too few neighbors N = " << neighbors_in_cluster << std::endl; - } + if (Verbosity() > 10) std::cout << " -> -> too few neighbors N = " << neighbors_in_cluster << std::endl; continue; } @@ -876,21 +869,14 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) } // check for possible EMCal-OHCal seed overlaps - for (unsigned int n = 0; n < local_maxima_ID.size(); n++) { // only look at I/OHCal local maxima std::pair this_LM = local_maxima_ID.at(n); - if (get_ilayer_from_ID(this_LM.first) == 2) - { - continue; - } + if (get_ilayer_from_ID(this_LM.first) == 2) continue; float this_phi = _geom_containers[get_ilayer_from_ID(this_LM.first)]->get_phicenter(get_iphi_from_ID(this_LM.first)); - if (this_phi > M_PI) - { - this_phi -= 2 * M_PI; - } + if (this_phi > M_PI) this_phi -= 2 * M_PI; float this_eta = _geom_containers[get_ilayer_from_ID(this_LM.first)]->get_etacenter(get_ieta_from_ID(this_LM.first)); bool has_EM_overlap = false; @@ -898,23 +884,14 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // check all other local maxima for overlaps for (unsigned int n2 = 0; n2 < local_maxima_ID.size(); n2++) { - if (n == n2) - { - continue; // don't check the same one - } + if (n == n2) continue; // don't check the same one // only look at EMCal local mazima std::pair this_LM2 = local_maxima_ID.at(n2); - if (get_ilayer_from_ID(this_LM2.first) != 2) - { - continue; - } + if (get_ilayer_from_ID(this_LM2.first) != 2) continue; float this_phi2 = _geom_containers[get_ilayer_from_ID(this_LM2.first)]->get_phicenter(get_iphi_from_ID(this_LM2.first)); - if (this_phi2 > M_PI) - { - this_phi -= 2 * M_PI; - } + if (this_phi2 > M_PI) this_phi -= 2 * M_PI; float this_eta2 = _geom_containers[get_ilayer_from_ID(this_LM2.first)]->get_etacenter(get_ieta_from_ID(this_LM2.first)); // calculate geometric dR @@ -950,10 +927,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) int tower_ID = this_LM.first; std::cout << "RawClusterBuilderTopo::process_event in cluster " << cl << ", tower ID " << tower_ID << " is LOCAL MAXIMUM with layer / E = " << get_ilayer_from_ID(tower_ID) << " / " << get_E_from_ID(tower_ID) << ", "; float this_phi = _geom_containers[get_ilayer_from_ID(tower_ID)]->get_phicenter(get_iphi_from_ID(tower_ID)); - if (this_phi > M_PI) - { - this_phi -= 2 * M_PI; - } + if (this_phi > M_PI) this_phi -= 2 * M_PI; std::cout << " eta / phi = " << _geom_containers[get_ilayer_from_ID(tower_ID)]->get_etacenter(get_ieta_from_ID(tower_ID)) << " / " << this_phi << std::endl; } } @@ -961,10 +935,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) // do we have only 1 or 0 local maxima? if (local_maxima_ID.size() <= 1) { - if (Verbosity() > 2) - { - std::cout << "RawClusterBuilderTopo::process_event cluster " << cl << " has only " << local_maxima_ID.size() << " local maxima, not splitting " << std::endl; - } + if (Verbosity() > 2) std::cout << "RawClusterBuilderTopo::process_event cluster " << cl << " has only " << local_maxima_ID.size() << " local maxima, not splitting " << std::endl; export_single_cluster(original_towers); continue; @@ -1046,12 +1017,11 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) } // look over all towers THIS one is adjacent to, and count up... std::vector adjacent_tower_IDs = get_adjacent_towers_by_ID(neighbor_ID); + for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; + if (tower_ownership[this_adjacent_tower_ID].first > -1) { if (Verbosity() > 20) @@ -1143,10 +1113,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; if (tower_ownership[this_adjacent_tower_ID].first == -1) { new_neighbor_list.push_back(this_adjacent_tower_ID); @@ -1195,10 +1162,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; std::cout << " -> adjacent to add tower " << this_adjacent_tower_ID << " , which has status " << tower_ownership[this_adjacent_tower_ID].first << std::endl; } } @@ -1227,7 +1191,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) pseudocluster_sumE[the_pair.first] += get_E_from_ID(this_ID); float this_eta = _geom_containers[get_ilayer_from_ID(this_ID)]->get_etacenter(get_ieta_from_ID(this_ID)); float this_phi = _geom_containers[get_ilayer_from_ID(this_ID)]->get_phicenter(get_iphi_from_ID(this_ID)); - // float this_phi = ( get_ilayer_from_ID( this_ID ) == 2 ? geomEM->get_phicenter( get_iphi_from_ID( this_ID ) ) : geomOH->get_phicenter( get_iphi_from_ID( this_ID ) ) ); + //float this_phi = ( get_ilayer_from_ID( this_ID ) == 2 ? geomEM->get_phicenter( get_iphi_from_ID( this_ID ) ) : geomOH->get_phicenter( get_iphi_from_ID( this_ID ) ) ); pseudocluster_sumeta[the_pair.first] += this_eta; pseudocluster_sumphi[the_pair.first] += this_phi; pseudocluster_ntower[the_pair.first] += 1; @@ -1268,10 +1232,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; if (tower_ownership[this_adjacent_tower_ID].first > -1) { pseudocluster_adjacency[tower_ownership[this_adjacent_tower_ID].first] = true; @@ -1301,10 +1262,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (unsigned int n = 0; n < pseudocluster_adjacency.size(); n++) { - if (!pseudocluster_adjacency[n]) - { - continue; - } + if (!pseudocluster_adjacency[n]) continue; if (pseudocluster_sumE[n] > highest_pseudocluster_E) { @@ -1343,10 +1301,7 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) for (int this_adjacent_tower_ID : adjacent_tower_IDs) { - if (get_status_from_ID(this_adjacent_tower_ID) != cl) - { - continue; - } + if (get_status_from_ID(this_adjacent_tower_ID) != cl) continue; std::cout << " -> adjacent to add tower " << this_adjacent_tower_ID << " , which has status " << tower_ownership[this_adjacent_tower_ID].first << std::endl; } } @@ -1357,6 +1312,79 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) export_clusters(original_towers, tower_ownership, local_maxima_ID.size(), pseudocluster_sumE, pseudocluster_eta, pseudocluster_phi); } + + std::unique_ptr jetdef(new fastjet::JetDefinition(fastjet::antikt_algorithm, 0.4, fastjet::E_scheme, fastjet::Best)); + std::vector particles; + + GlobalVertexMap *vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if (!vertexmap) + { + std::cout << "ResonanceJetTagging::getEmcalClusters - Fatal Error - GlobalVertexMap node is missing. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl; + assert(vertexmap); // force quit + + return Fun4AllReturnCodes::EVENT_OK; + } + + if (vertexmap->empty()) + { + std::cout << "ResonanceJetTagging::getEmcalClusters - Fatal Error - GlobalVertexMap node is empty. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + GlobalVertex *vtx = vertexmap->begin()->second; + if (vtx == nullptr) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + CLHEP::Hep3Vector vertex(vtx->get_x(), vtx->get_y(), vtx->get_z()); + + /// Loop over the HCAL Topo clusters + for(unsigned int icluster = 0; icluster < _clusters->size(); icluster++) + { + RawCluster *topocluster = _clusters->getCluster(icluster); + + if(!topocluster) continue; + + CLHEP::Hep3Vector E_vec_cluster = RawClusterUtility::GetEVec(*topocluster, vertex); + double cluster_e = E_vec_cluster.mag(); + double cluster_pt = E_vec_cluster.perp(); + double cluster_phi = E_vec_cluster.getPhi(); + float cluster_theta = M_PI / 2.0 - atan2(topocluster->get_z(), topocluster->get_r() ); + float cluster_eta = -1 * log( tan( cluster_theta / 2.0 ) ); + + if(vtx) + { + cluster_eta = RawClusterUtility::GetPseudorapidity(*topocluster, vertex); + } + + double cluster_px = cluster_pt * cos(cluster_phi); + double cluster_py = cluster_pt * sin(cluster_phi); + double cluster_pz = cluster_pt * sinh(cluster_eta); + fastjet::PseudoJet part(cluster_px, cluster_py, cluster_pz, cluster_e); + particles.push_back(part); + } + + + fastjet::ClusterSequence jetFinder(particles, *jetdef); + std::vector fastjets = jetFinder.inclusive_jets(); + + + for(auto topojet : fastjets) + { + _jets_px.push_back(topojet.px()); + _jets_py.push_back(topojet.py()); + _jets_pz.push_back(topojet.pz()); + _jets_e.push_back(topojet.E()); + _jets_p.push_back(std::sqrt(topojet.modp2())); + _jets_pt.push_back(topojet.perp()); + _jets_eta.push_back(topojet.eta()); + _jets_phi.push_back(topojet.phi()); + } + + _tree->Fill(); + + if (Verbosity() > 1) { std::cout << "RawClusterBuilderTopo::process_event after splitting (if any) final clusters output to node are: " << std::endl; @@ -1375,6 +1403,9 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) int RawClusterBuilderTopo::End(PHCompositeNode * /*topNode*/) { + _outfile->cd(); + _tree->Write(); + _outfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } @@ -1402,3 +1433,55 @@ void RawClusterBuilderTopo::CreateNodes(PHCompositeNode *topNode) PHIODataNode *clusterNode = new PHIODataNode(_clusters, ClusterNodeName, "PHObject"); DetNode->addNode(clusterNode); } + +void RawClusterBuilderTopo::initializeTrees() +{ + + delete _outfile; + _outfile = new TFile(_outfilename.c_str(), "RECREATE"); + + delete _tree; + _tree = new TTree("tree", "A tree with tower and cluster info"); + _tree->Branch("_tree_centrality", &_tree_centrality, "_tree_centrality/I"); + _tree->Branch("_tree_tower_id", &_tree_tower_id); + _tree->Branch("_tree_tower_e", &_tree_tower_e); + _tree->Branch("_tree_tower_cluster_id", &_tree_tower_cluster_id); + _tree->Branch("_tree_cluster_id", &_tree_cluster_id); + + _tree->Branch("_tree_cluster_e", &_tree_cluster_e); + _tree->Branch("_tree_cluster_eta", &_tree_cluster_eta); + _tree->Branch("_tree_cluster_phi", &_tree_cluster_phi); + + _tree->Branch("_jets_px", &_jets_px); + _tree->Branch("_jets_py", &_jets_py); + _tree->Branch("_jets_pz", &_jets_pz); + _tree->Branch("_jets_e", &_jets_e); + _tree->Branch("_jets_p", &_jets_p); + _tree->Branch("_jets_pt", &_jets_pt); + _tree->Branch("_jets_eta", &_jets_eta); + _tree->Branch("_jets_phi", &_jets_phi); + +} + +void RawClusterBuilderTopo::resetTreeVariables() +{ + _tree_centrality = -1; + _tree_tower_id.clear(); + _tree_tower_e.clear(); + _tree_tower_cluster_id.clear(); + _tree_cluster_id.clear(); + + _tree_cluster_e.clear(); + _tree_cluster_eta.clear(); + _tree_cluster_phi.clear(); + + _jets_px.clear(); + _jets_py.clear(); + _jets_pz.clear(); + _jets_e.clear(); + _jets_p.clear(); + _jets_pt.clear(); + _jets_eta.clear(); + _jets_phi.clear(); + +} From 2d689a663a24d40af4fd530d0cd1c5978b57f056 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 6 Apr 2023 08:13:20 -0400 Subject: [PATCH 119/468] consistently use mm --- offline/packages/trackreco/ActsPropagator.cc | 6 +++--- offline/packages/trackreco/ActsPropagator.h | 10 ++++++++-- offline/packages/trackreco/PHActsTrackProjection.cc | 4 +--- offline/packages/trackreco/PHActsTrackPropagator.cc | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 670d3b4898..1ad42c4c73 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -103,7 +103,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, if (result.ok()) { auto finalparams = *result.value().endParameters; - auto pathlength = result.value().pathLength / Acts::UnitConstants::cm; + auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); @@ -142,7 +142,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, if (result.ok()) { auto finalparams = *result.value().endParameters; - auto pathlength = result.value().pathLength / Acts::UnitConstants::cm; + auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); @@ -181,7 +181,7 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, if (result.ok()) { auto finalparams = *result.value().endParameters; - auto pathlength = result.value().pathLength / Acts::UnitConstants::cm; + auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index b6b54d9b9b..61bd4f2a38 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -30,6 +30,7 @@ class ActsPropagator { public: using BoundTrackParam = const Acts::BoundTrackParameters; + /// Return type of std::pair using BoundTrackParamPair = std::pair; using BoundTrackParamResult = Acts::Result; using SurfacePtr = std::shared_ptr; @@ -44,15 +45,20 @@ class ActsPropagator } ~ActsPropagator() {} + /// Helper functions for creating needed input for track propagation + /// functions below SurfacePtr makeVertexSurface(const SvtxVertex* vertex); BoundTrackParam makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap); + /// The return type is an Acts::Result of a std::pair, where the pair is + /// a path length and the track parameters at the surface in units of mm + /// and GeV. For an example of how to unpack this, see + /// PHActsTrackProjection::propagateTrack and + /// PHActsTrackProjection::updateSvtxTrack BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters& params, const unsigned int sphenixLayer); - BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters& params, const SurfacePtr& surface); - /// The following function takes the track parameters at the vertex and /// propagates them in isolation to the requested surface, i.e. it does /// NOT stop at each layer in the sPHENIX detector on the way to the diff --git a/offline/packages/trackreco/PHActsTrackProjection.cc b/offline/packages/trackreco/PHActsTrackProjection.cc index 3b8f9b566e..b9263c2001 100644 --- a/offline/packages/trackreco/PHActsTrackProjection.cc +++ b/offline/packages/trackreco/PHActsTrackProjection.cc @@ -140,14 +140,12 @@ int PHActsTrackProjection::projectTracks(const int caloLayer) return Fun4AllReturnCodes::EVENT_OK; } - - void PHActsTrackProjection::updateSvtxTrack( const ActsPropagator::BoundTrackParamPair& parameters, SvtxTrack* svtxTrack, const int caloLayer) { - float pathlength = parameters.first; + float pathlength = parameters.first / Acts::UnitConstants::cm; auto params = parameters.second; SvtxTrackState_v1 out(pathlength); diff --git a/offline/packages/trackreco/PHActsTrackPropagator.cc b/offline/packages/trackreco/PHActsTrackPropagator.cc index f45f88e402..00a5b6421e 100644 --- a/offline/packages/trackreco/PHActsTrackPropagator.cc +++ b/offline/packages/trackreco/PHActsTrackPropagator.cc @@ -72,7 +72,7 @@ void PHActsTrackPropagator::addTrackState( BoundTrackParamResult &result, SvtxTrack *svtxTrack) { - float pathlength = result.value().first; + float pathlength = result.value().first / Acts::UnitConstants::cm; auto params = result.value().second; SvtxTrackState_v1 out(pathlength); From 3829244d67b2070ef94ef40c766371e011f384bf Mon Sep 17 00:00:00 2001 From: bogui56 Date: Thu, 6 Apr 2023 08:33:07 -0400 Subject: [PATCH 120/468] sector edge error modification for cluster v5 --- .../HelicalFitter.cc | 11 +++++-- .../MakeMilleFiles.cc | 11 +++++-- .../TrackingDiagnostics/TrkrNtuplizer.cc | 11 ++++--- .../packages/trackbase/ClusterErrorPara.cc | 31 +++++++++---------- offline/packages/trackbase/ClusterErrorPara.h | 2 +- offline/packages/trackreco/ALICEKF.cc | 8 +++-- offline/packages/trackreco/PHActsGSF.cc | 7 +++-- offline/packages/trackreco/PHActsTrkFitter.cc | 7 +++-- .../g4simulation/g4eval/SvtxEvaluator.cc | 20 ++++++------ .../g4simulation/g4eval/TrackEvaluation.cc | 2 +- 10 files changed, 65 insertions(+), 45 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index e3bb89aa27..0439a20502 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -595,9 +595,14 @@ Acts::Vector3 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu } else if(_cluster_version == 5) { - clus_sigma(2) = cluster->getZError(); - clus_sigma(0) = cluster->getRPhiError() / sqrt(2); - clus_sigma(1) = cluster->getRPhiError() / sqrt(2); + double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + TrkrClusterv5* clusterv5 = dynamic_cast(cluster); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,cluskey); + double phierror = sqrt(para_errors.first); + double zerror = sqrt(para_errors.second); + clus_sigma(2) = zerror; + clus_sigma(0) = phierror/ sqrt(2); + clus_sigma(1) = phierror/ sqrt(2); } return clus_sigma; diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index c448c2596d..62913b94a6 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -329,9 +329,14 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve } else if(_cluster_version == 5) { - clus_sigma(2) = cluster->getZError(); - clus_sigma(0) = cluster->getRPhiError() / sqrt(2); - clus_sigma(1) = cluster->getRPhiError() / sqrt(2); + double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + TrkrClusterv5* clusterv5 = dynamic_cast(cluster); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,ckey); + double phierror = sqrt(para_errors.first); + double zerror = sqrt(para_errors.second); + clus_sigma(2) = zerror; + clus_sigma(0) = phierror/ sqrt(2); + clus_sigma(1) = phierror/ sqrt(2); } if (std::isnan(clus_sigma(0)) || diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index f36d48ac51..572bcffa8c 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -875,6 +875,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); TrkrHitSetContainer* hitsets = findNode::getClass(topNode, "TRKR_HITSET"); TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); + ClusterErrorPara ClusErrPara; if (Verbosity() > 1) { @@ -955,8 +956,6 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) { phisize = cluster->getPhiSize(); zsize = cluster->getZSize(); - double clusRadius = r; - ClusterErrorPara ClusErrPara; TrackSeed* seed = nullptr; if (track != nullptr) { @@ -970,7 +969,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } if (seed != nullptr) { - auto para_errors = ClusErrPara.get_cluster_error(seed, cluster, clusRadius, cluster_key); + auto para_errors = ClusErrPara.get_cluster_error(seed, cluster, r, cluster_key); pephi = sqrt(para_errors.first * Acts::UnitConstants::cm2); pez = sqrt(para_errors.second * Acts::UnitConstants::cm2); } @@ -979,11 +978,13 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) else if (m_cluster_version == 5) { TrkrClusterv5* clusterv5 = dynamic_cast(cluster); + auto para_errors = ClusErrPara.get_clusterv5_modified_error(clusterv5,r ,cluster_key); + phisize = clusterv5->getPhiSize(); zsize = clusterv5->getZSize(); // double clusRadius = r; - ez = clusterv5->getZError(); - ephi = clusterv5->getRPhiError(); + ez = sqrt(para_errors.second); + ephi = sqrt(para_errors.first); maxadc = clusterv5->getMaxAdc(); } float e = cluster->getAdc(); diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 8f5b7bf9e1..205b89c51c 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -474,36 +474,33 @@ ClusterErrorPara::ClusterErrorPara() } //_________________________________________________________________________________ -ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_error(TrackSeed *seed, TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key) -{/* - float r = cluster_r; - float R = TMath::Abs(1.0/seed->get_qOverR()); - double alpha = (r*r) /(2*r*R); - double beta = TMath::Abs(atan(seed->get_slope())); - */ - if(seed==0) std::cout << "hallo" << std::endl; - if(cluster_r==0) std::cout << "hallo" << std::endl; - if(key==0) std::cout << "hallo" << std::endl; - +ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key) +{ + if(cluster_r>300){ + std::cout << " far out " << std::endl; + } int layer = TrkrDefs::getLayer(key); double phierror = clusterv5->getRPhiError(); double zerror = clusterv5->getZError(); if( TrkrDefs::getTrkrId( key )== TrkrDefs::tpcId){ if(layer==7||layer==22||layer==23||layer==38||layer==39){ - phierror *= 3.5; - zerror*= 3.5; + phierror *= 4; + zerror*= 4; } - if(clusterv5->getEdge()>=5) - phierror *= 2; + if(clusterv5->getEdge()>=3) + phierror *= 4; if(clusterv5->getOverlap()>=2) phierror *= 2; - + if(clusterv5->getPhiSize()==1) + phierror *= 10; + if(clusterv5->getPhiSize()>=5) + phierror *= 10; + if(phierror>0.1) phierror = 0.1; if(phierror<0.0005) phierror = 0.1; } return std::make_pair(square(phierror),square(zerror)); - // return get_cluster_error(cluster, key, alpha, beta); } //_________________________________________________________________________________ diff --git a/offline/packages/trackbase/ClusterErrorPara.h b/offline/packages/trackbase/ClusterErrorPara.h index ed1b1c6f1c..1755241355 100644 --- a/offline/packages/trackbase/ClusterErrorPara.h +++ b/offline/packages/trackbase/ClusterErrorPara.h @@ -56,7 +56,7 @@ class ClusterErrorPara using error_t = std::pair; - error_t get_clusterv5_error(TrackSeed *seed, TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key); + error_t get_clusterv5_modified_error(TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key); error_t get_cluster_error(TrackSeed *seed, TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key); error_t get_cluster_error(TrkrCluster* cluster, TrkrDefs::cluskey key, double alpha, double beta); diff --git a/offline/packages/trackreco/ALICEKF.cc b/offline/packages/trackreco/ALICEKF.cc index 30324edd4a..6848c40e04 100644 --- a/offline/packages/trackreco/ALICEKF.cc +++ b/offline/packages/trackreco/ALICEKF.cc @@ -83,15 +83,19 @@ double ALICEKF::getClusterError(TrkrCluster* c, TrkrDefs::cluskey key, Acts::Vec localErr[2][1] = 0.; localErr[2][2] = para_errors.second; }else if(m_cluster_version==5){ + double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + TrkrClusterv5* clusterv5 = dynamic_cast(c); + auto para_errors = _ClusErrPara->get_clusterv5_modified_error(clusterv5,clusRadius,key); + localErr[0][0] = 0.; localErr[0][1] = 0.; localErr[0][2] = 0.; localErr[1][0] = 0.; - localErr[1][1] = pow(c->getRPhiError(),2); + localErr[1][1] = para_errors.first; localErr[1][2] = 0.; localErr[2][0] = 0.; localErr[2][1] = 0.; - localErr[2][2] = pow(c->getZError(),2); + localErr[2][2] = para_errors.second; } float clusphi = atan2(global(1), global(0)); TMatrixF ROT(3,3); diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 35bf72986b..3f7d4afd4b 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -346,10 +346,13 @@ SourceLinkVec PHActsGSF::getSourceLinks(TrackSeed* track, } else if (m_cluster_version == 5) { - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(cluster->getRPhiError(),2) * Acts::UnitConstants::cm2; + double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + TrkrClusterv5* clusterv5 = dynamic_cast(cluster); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,cluskey); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(cluster->getZError(),2) * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; } ActsSourceLink::Index index = measurements.size(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 4ffa111543..7875c5bd22 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -705,10 +705,13 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; }else if(m_cluster_version==5){ - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = pow(cluster->getRPhiError(),2) * Acts::UnitConstants::cm2; + double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + TrkrClusterv5* clusterv5 = dynamic_cast(cluster); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,cluskey); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = pow(cluster->getZError(),2) * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; } ActsSourceLink::Index index = measurements.size(); diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index a28ffa879f..1455d48438 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1749,6 +1749,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); TrkrHitSetContainer* hitsets = findNode::getClass(topNode, "TRKR_HITSET"); TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); + ClusterErrorPara ClusErrPara; if (Verbosity() > 1){ if (clustermap != nullptr) @@ -1811,8 +1812,6 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) }else if(m_cluster_version==4){ phisize = cluster->getPhiSize(); zsize = cluster->getZSize(); - double clusRadius = r; - ClusterErrorPara ClusErrPara; TrackSeed *seed = nullptr; if(track!=NULL){ if(layer < 7){ @@ -1821,18 +1820,19 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) seed = track->get_tpc_seed(); } if(seed != nullptr){ - auto para_errors = ClusErrPara.get_cluster_error(seed,cluster,clusRadius,cluster_key); + auto para_errors = ClusErrPara.get_cluster_error(seed,cluster,r,cluster_key); pephi = sqrt(para_errors.first* Acts::UnitConstants::cm2); pez =sqrt( para_errors.second* Acts::UnitConstants::cm2); } } }else if(m_cluster_version==5){ TrkrClusterv5 *clusterv5 = dynamic_cast(cluster); + auto para_errors = ClusErrPara.get_clusterv5_modified_error(clusterv5,r,cluster_key); phisize = clusterv5->getPhiSize(); zsize = clusterv5->getZSize(); //double clusRadius = r; - ez = clusterv5->getZError(); - ephi = clusterv5->getRPhiError(); + ez = sqrt(para_errors.second); + ephi = sqrt(para_errors.first); maxadc = clusterv5->getMaxAdc(); } @@ -2343,8 +2343,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) { if (Verbosity() >= 1) cout << "Filling ntp_g4cluster " << endl; - - PHG4TruthInfoContainer* truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + ClusterErrorPara ClusErrPara; + PHG4TruthInfoContainer* truthinfo = findNode::getClass(topNode, "G4TruthInfo"); PHG4TruthInfoContainer::ConstRange range = truthinfo->GetParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; @@ -2439,11 +2439,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) phisize = reco_cluster->getPhiSize(); zsize = reco_cluster->getZSize(); }else if(m_cluster_version==5){ + TrkrClusterv5 *clusterv5 = dynamic_cast(reco_cluster); + auto para_errors = ClusErrPara.get_clusterv5_modified_error(clusterv5,r,ckey); //cout << " ver v4 " << endl; phisize = reco_cluster->getPhiSize(); zsize = reco_cluster->getZSize(); - ez = reco_cluster->getZError(); - ephi = reco_cluster->getRPhiError(); + ez = sqrt(para_errors.second); + ephi = sqrt(para_errors.first); } adc = reco_cluster->getAdc(); diff --git a/simulation/g4simulation/g4eval/TrackEvaluation.cc b/simulation/g4simulation/g4eval/TrackEvaluation.cc index 1dd23a104c..ce75abee52 100644 --- a/simulation/g4simulation/g4eval/TrackEvaluation.cc +++ b/simulation/g4simulation/g4eval/TrackEvaluation.cc @@ -686,7 +686,7 @@ TrackEvaluationContainerv1::ClusterStruct TrackEvaluation::create_cluster( TrkrD if(cluster_struct.layer>=7){ TrkrClusterv5 *clusterv5 = dynamic_cast(cluster); - auto para_errors_mm = ClusErrPara.get_clusterv5_error(tpc_seed,clusterv5,r,key); + auto para_errors_mm = ClusErrPara.get_clusterv5_modified_error(clusterv5,r,key); cluster_struct.phi_error = clusterv5->getRPhiError()/cluster_struct.r; cluster_struct.z_error = clusterv5->getZError(); From f78b492dd4bd3062c72d02f6f695d01e6c4d9d22 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 08:59:21 -0400 Subject: [PATCH 121/468] modified to take advantage of the TowerInfoDefs class --- .../packages/CaloBase/TowerInfoContainerv1.cc | 184 +----------------- 1 file changed, 10 insertions(+), 174 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index f1557df6af..6fdc11bdbc 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -1,5 +1,6 @@ #include "TowerInfoContainerv1.h" #include "TowerInfov1.h" +#include "TowerInfoDefs.h" #include #include @@ -45,10 +46,8 @@ TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) nchannels = 1536; } _clones = new TClonesArray("TowerInfov1", nchannels); - _clones->SetOwner(); _clones->SetName("TowerInfoContainerv1"); - for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -80,7 +79,6 @@ void TowerInfoContainerv1::Reset() } assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers obj->Clear(); obj->ResetBit(kHasUUID); @@ -89,7 +87,6 @@ void TowerInfoContainerv1::Reset() } } - TowerInfov1* TowerInfoContainerv1::get_tower_at_channel(int pos) { return (TowerInfov1*) _clones->At(pos); @@ -102,108 +99,21 @@ TowerInfov1* TowerInfoContainerv1::get_tower_at_key(int pos) return (TowerInfov1*) _clones->At(index); } - - - - - unsigned int TowerInfoContainerv1::encode_epd(unsigned int towerIndex) { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int supersectornumber = towerIndex / supersector; - int sector = ((towerIndex % supersector)) / channels_per_sector; - int channel = ((towerIndex % supersector)) % channels_per_sector; - int rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; - int phimap_sepd[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; - unsigned int globalphi = phimap_sepd[channel] + 2 * sector; - unsigned int r = rmap[channel]; - unsigned int key = globalphi + (r << 10U) + (supersectornumber << 20U); + unsigned int key = TowerInfoDefs::encode_epd(towerIndex); return key; } - - unsigned int TowerInfoContainerv1::encode_emcal(unsigned int towerIndex) { - int phimap[64] = {0}; - int etamap[64] = {0}; - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 8; k++) - { - etamap[emcadc[j][k]] = j; - phimap[emcadc[j][k]] = k; - } - } - int channels_per_sector = 64; - int supersector = 64 * 12; - int nchannelsperpacket = 64 * 3; - int maxphibin = 7; - int maxetabin = 23; - int etabinoffset[4] = {24,0,48,72}; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << PHWHERE << "Attempting to access channel with invalid value in EMCal " << packet << std::endl; - exit(1); - } - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel]; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin + 8 * interfaceboard; - if (packet == 0 || packet == 1) - { - packet_etabin = maxetabin - packet_etabin; - } - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); - return key; + unsigned int key = TowerInfoDefs::encode_emcal(towerIndex); + return key; } - - - unsigned int TowerInfoContainerv1::encode_hcal(unsigned int towerIndex) { - int phimap[64] = {0}; - int etamap[64] = {0}; - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 2; k++) - { - etamap[hcaladc[j][k]] = j; - phimap[hcaladc[j][k]] = k; - } - } - int channels_per_sector = 16; - int supersector = 16 * 4 * 3; - int nchannelsperpacket = channels_per_sector * 4; - int etabinoffset[4] = {0,8,16,0}; - int phibinoffset[4] = {0,2,4,6}; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << PHWHERE << "Attempting to access channel with invalid value ih HCAL " << packet << std::endl; - exit(1); - } - - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel] + phibinoffset[interfaceboard]; - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin; - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); + unsigned int key = TowerInfoDefs::encode_hcal(towerIndex); return key; } @@ -225,98 +135,25 @@ unsigned int TowerInfoContainerv1::encode_key(unsigned int towerIndex) return key; } - - - unsigned int TowerInfoContainerv1::decode_epd(unsigned int tower_key) { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int ns_sector = tower_key >> 20U; - unsigned int rbin = (tower_key - (ns_sector << 20U)) >> 10U; - unsigned int phibin = tower_key - (ns_sector << 20U) - (rbin << 10U); - int epdchnlmap[16][2] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24}, {25, 26}, {27, 28}, {29, 30}}; - int sector = phibin / 2; - int channel = 0; - if (rbin > 0) - { - channel = epdchnlmap[rbin][phibin - 2 * sector]; - } - else - { - channel = 0; - } - unsigned int index = 0; - index = ns_sector * supersector + sector * channels_per_sector + channel; + unsigned int index = TowerInfoDefs::decode_epd(tower_key); return index; } unsigned int TowerInfoContainerv1::decode_emcal(unsigned int tower_key) { - int etabinoffset[4] = {0}; - int etabinmap[4] = {0}; - int channels_per_sector = 64; - int supersector = 64 * 12; - int nchannelsperpacket = 64 * 3; - int maxphibin = 7; - int maxetabin = 23; - etabinoffset[0] = 24; - etabinoffset[1] = 0; - etabinoffset[2] = 48; - etabinoffset[3] = 72; - etabinmap[0] = 1; - etabinmap[1] = 0; - etabinmap[2] = 2; - etabinmap[3] = 3; - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabinmap[(int) etabin / 24]; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = 0; - if (packet == 0 || packet == 1) - { - localetabin = maxetabin - localetabin; - } - ib = localetabin / 8; - unsigned int index = 0; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - localetabin = localetabin % 8; - unsigned int localindex = emcadc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + unsigned int index = TowerInfoDefs::decode_emcal(tower_key); return index; } - - unsigned int TowerInfoContainerv1::decode_hcal(unsigned int tower_key) { - int channels_per_sector = 16; - int supersector = 16 * 4 * 3; - int nchannelsperpacket = channels_per_sector * 4; - int etabinoffset[3] = {0,8,16}; - int phibinoffset[4] = {0,2,4,6}; - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabin / 8; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = localphibin / 2; - unsigned int index = 0; - localphibin = localphibin - phibinoffset[ib]; - unsigned int localindex = hcaladc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + unsigned int index = TowerInfoDefs::decode_hcal(tower_key); return index; } - - unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) { int index = 0; @@ -338,13 +175,12 @@ unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) unsigned int TowerInfoContainerv1::getTowerPhiBin(unsigned int key) { - unsigned int etabin = key >> 16U; - unsigned int phibin = key - (etabin << 16U); + unsigned int phibin = TowerInfoDefs::getCaloTowerPhiBin(key); return phibin; } unsigned int TowerInfoContainerv1::getTowerEtaBin(unsigned int key) { - unsigned int etabin = key >> 16U; + unsigned int etabin = TowerInfoDefs::getCaloTowerEtaBin(key); return etabin; } From eb0e6933d8b737bd31a4b499aa007be94078b823 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 09:01:00 -0400 Subject: [PATCH 122/468] removed uneccessary array --- .../packages/CaloBase/TowerInfoContainerv1.cc | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index 6fdc11bdbc..ee67a4fd01 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -9,25 +9,6 @@ #include -int emcadc[8][8] = { - {62, 60, 46, 44, 30, 28, 14, 12}, - {63, 61, 47, 45, 31, 29, 15, 13}, - {58, 56, 42, 40, 26, 24, 10, 8}, - {59, 57, 43, 41, 27, 25, 11, 9}, - {54, 52, 38, 36, 22, 20, 6, 4}, - {55, 53, 39, 37, 23, 21, 7, 5}, - {50, 48, 34, 32, 18, 16, 2, 0}, - {51, 49, 35, 33, 19, 17, 3, 1}}; - -int hcaladc[8][2] = { - {0, 1}, - {2, 3}, - {4, 5}, - {6, 7}, - {8, 9}, - {10, 11}, - {12, 13}, - {14, 15}}; TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) : _detector(detec) From 9f1bb2a659a7b2fa18cebea2a302daefc947db2d Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Thu, 6 Apr 2023 09:27:21 -0400 Subject: [PATCH 123/468] Removing QA objects --- .../CaloReco/RawClusterBuilderTopo.cc | 179 ------------------ 1 file changed, 179 deletions(-) diff --git a/offline/packages/CaloReco/RawClusterBuilderTopo.cc b/offline/packages/CaloReco/RawClusterBuilderTopo.cc index ec967830b0..dcb80bcd87 100644 --- a/offline/packages/CaloReco/RawClusterBuilderTopo.cc +++ b/offline/packages/CaloReco/RawClusterBuilderTopo.cc @@ -3,12 +3,9 @@ #include #include #include -#include -#include #include #include #include - #include #include @@ -23,19 +20,6 @@ #include #include -#include -#include -#include - -#include -#include - -#include - -//root -#include -#include - #include #include #include // for abs @@ -308,10 +292,6 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow _clusters->AddCluster(clusters[cl]); - _tree_cluster_e.push_back(clusters_E[cl]); - _tree_cluster_eta.push_back(-1 * log(tan(std::atan2(std::sqrt(mean_y * mean_y + mean_x * mean_x), mean_z) / 2.0))); - _tree_cluster_phi.push_back(std::atan2(mean_y, mean_x)); - if (Verbosity() > 1) { std::cout << "RawClusterBuilderTopo::export_clusters: added cluster with E = " << clusters_E[cl] << ", eta = " << -1 * log(tan(std::atan2(std::sqrt(mean_y * mean_y + mean_x * mean_x), mean_z) / 2.0)) << ", phi = " << std::atan2(mean_y, mean_x) << std::endl; @@ -323,9 +303,6 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow RawClusterBuilderTopo::RawClusterBuilderTopo(const std::string &name, const std::string &filename) : SubsysReco(name) - , _outfilename(filename) - , _outfile(nullptr) - , _tree(nullptr) { // geometry defined at run-time _EMCAL_NETA = -1; @@ -379,21 +356,11 @@ int RawClusterBuilderTopo::InitRun(PHCompositeNode *topNode) std::cout << "RawClusterBuilderTopo::InitRun: initialized with minE for local max in EMCal / IHCal / OHCal = " << _local_max_minE_LAYER[2] << " / " << _local_max_minE_LAYER[0] << " / " << _local_max_minE_LAYER[1] << std::endl; } - initializeTrees(); - return Fun4AllReturnCodes::EVENT_OK; } int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) { - - CentralityInfo* cent_node = findNode::getClass(topNode, "CentralityInfo"); - if (!cent_node) - { - std::cout << "RawClusterBuilderTopo::process_event - Error can not find centrality node " << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - TowerInfoContainer *towerinfosEM = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); TowerInfoContainer *towerinfosIH = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALIN"); TowerInfoContainer *towerinfosOH = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALOUT"); @@ -789,24 +756,6 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) if (Verbosity() > 0) std::cout << "RawClusterBuilderTopo::process_event: " << cluster_index << " topo-clusters initially reconstructed, entering splitting step" << std::endl; int original_cluster_index = cluster_index; // since it may be updated - //Fill the tree - resetTreeVariables(); - _tree_centrality = cent_node->get_centile(CentralityInfo::PROP::bimp); - for (int cl = 0; cl < original_cluster_index; cl++) - { - std::vector original_towers = all_cluster_towers.at(cl); - - //fill tree with towers - for(auto tid : original_towers) - { - _tree_tower_id.push_back(tid); - _tree_tower_e.push_back(get_E_from_ID(tid)); - _tree_tower_cluster_id.push_back(cl); - } - _tree_cluster_id.push_back(cl); - } - - // now entering cluster splitting stage @@ -1312,79 +1261,6 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) export_clusters(original_towers, tower_ownership, local_maxima_ID.size(), pseudocluster_sumE, pseudocluster_eta, pseudocluster_phi); } - - std::unique_ptr jetdef(new fastjet::JetDefinition(fastjet::antikt_algorithm, 0.4, fastjet::E_scheme, fastjet::Best)); - std::vector particles; - - GlobalVertexMap *vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); - if (!vertexmap) - { - std::cout << "ResonanceJetTagging::getEmcalClusters - Fatal Error - GlobalVertexMap node is missing. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl; - assert(vertexmap); // force quit - - return Fun4AllReturnCodes::EVENT_OK; - } - - if (vertexmap->empty()) - { - std::cout << "ResonanceJetTagging::getEmcalClusters - Fatal Error - GlobalVertexMap node is empty. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - GlobalVertex *vtx = vertexmap->begin()->second; - if (vtx == nullptr) - { - return Fun4AllReturnCodes::EVENT_OK; - } - - CLHEP::Hep3Vector vertex(vtx->get_x(), vtx->get_y(), vtx->get_z()); - - /// Loop over the HCAL Topo clusters - for(unsigned int icluster = 0; icluster < _clusters->size(); icluster++) - { - RawCluster *topocluster = _clusters->getCluster(icluster); - - if(!topocluster) continue; - - CLHEP::Hep3Vector E_vec_cluster = RawClusterUtility::GetEVec(*topocluster, vertex); - double cluster_e = E_vec_cluster.mag(); - double cluster_pt = E_vec_cluster.perp(); - double cluster_phi = E_vec_cluster.getPhi(); - float cluster_theta = M_PI / 2.0 - atan2(topocluster->get_z(), topocluster->get_r() ); - float cluster_eta = -1 * log( tan( cluster_theta / 2.0 ) ); - - if(vtx) - { - cluster_eta = RawClusterUtility::GetPseudorapidity(*topocluster, vertex); - } - - double cluster_px = cluster_pt * cos(cluster_phi); - double cluster_py = cluster_pt * sin(cluster_phi); - double cluster_pz = cluster_pt * sinh(cluster_eta); - fastjet::PseudoJet part(cluster_px, cluster_py, cluster_pz, cluster_e); - particles.push_back(part); - } - - - fastjet::ClusterSequence jetFinder(particles, *jetdef); - std::vector fastjets = jetFinder.inclusive_jets(); - - - for(auto topojet : fastjets) - { - _jets_px.push_back(topojet.px()); - _jets_py.push_back(topojet.py()); - _jets_pz.push_back(topojet.pz()); - _jets_e.push_back(topojet.E()); - _jets_p.push_back(std::sqrt(topojet.modp2())); - _jets_pt.push_back(topojet.perp()); - _jets_eta.push_back(topojet.eta()); - _jets_phi.push_back(topojet.phi()); - } - - _tree->Fill(); - - if (Verbosity() > 1) { std::cout << "RawClusterBuilderTopo::process_event after splitting (if any) final clusters output to node are: " << std::endl; @@ -1403,9 +1279,6 @@ int RawClusterBuilderTopo::process_event(PHCompositeNode *topNode) int RawClusterBuilderTopo::End(PHCompositeNode * /*topNode*/) { - _outfile->cd(); - _tree->Write(); - _outfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } @@ -1433,55 +1306,3 @@ void RawClusterBuilderTopo::CreateNodes(PHCompositeNode *topNode) PHIODataNode *clusterNode = new PHIODataNode(_clusters, ClusterNodeName, "PHObject"); DetNode->addNode(clusterNode); } - -void RawClusterBuilderTopo::initializeTrees() -{ - - delete _outfile; - _outfile = new TFile(_outfilename.c_str(), "RECREATE"); - - delete _tree; - _tree = new TTree("tree", "A tree with tower and cluster info"); - _tree->Branch("_tree_centrality", &_tree_centrality, "_tree_centrality/I"); - _tree->Branch("_tree_tower_id", &_tree_tower_id); - _tree->Branch("_tree_tower_e", &_tree_tower_e); - _tree->Branch("_tree_tower_cluster_id", &_tree_tower_cluster_id); - _tree->Branch("_tree_cluster_id", &_tree_cluster_id); - - _tree->Branch("_tree_cluster_e", &_tree_cluster_e); - _tree->Branch("_tree_cluster_eta", &_tree_cluster_eta); - _tree->Branch("_tree_cluster_phi", &_tree_cluster_phi); - - _tree->Branch("_jets_px", &_jets_px); - _tree->Branch("_jets_py", &_jets_py); - _tree->Branch("_jets_pz", &_jets_pz); - _tree->Branch("_jets_e", &_jets_e); - _tree->Branch("_jets_p", &_jets_p); - _tree->Branch("_jets_pt", &_jets_pt); - _tree->Branch("_jets_eta", &_jets_eta); - _tree->Branch("_jets_phi", &_jets_phi); - -} - -void RawClusterBuilderTopo::resetTreeVariables() -{ - _tree_centrality = -1; - _tree_tower_id.clear(); - _tree_tower_e.clear(); - _tree_tower_cluster_id.clear(); - _tree_cluster_id.clear(); - - _tree_cluster_e.clear(); - _tree_cluster_eta.clear(); - _tree_cluster_phi.clear(); - - _jets_px.clear(); - _jets_py.clear(); - _jets_pz.clear(); - _jets_e.clear(); - _jets_p.clear(); - _jets_pt.clear(); - _jets_eta.clear(); - _jets_phi.clear(); - -} From 8c42ac691781615575a73e0d0aba89062dc9fd7b Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Thu, 6 Apr 2023 09:30:24 -0400 Subject: [PATCH 124/468] Fixing constructor --- offline/packages/CaloReco/RawClusterBuilderTopo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/RawClusterBuilderTopo.cc b/offline/packages/CaloReco/RawClusterBuilderTopo.cc index dcb80bcd87..2c3071d303 100644 --- a/offline/packages/CaloReco/RawClusterBuilderTopo.cc +++ b/offline/packages/CaloReco/RawClusterBuilderTopo.cc @@ -301,7 +301,7 @@ void RawClusterBuilderTopo::export_clusters(const std::vector &original_tow return; } -RawClusterBuilderTopo::RawClusterBuilderTopo(const std::string &name, const std::string &filename) +RawClusterBuilderTopo::RawClusterBuilderTopo(const std::string &name) : SubsysReco(name) { // geometry defined at run-time From 33ddc9b2cb11cfe523cee1a16c83eb03a5ecc292 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 6 Apr 2023 10:02:22 -0400 Subject: [PATCH 125/468] Added override and const override to new getting and setting functions --- offline/packages/trackbase/CMFlashClusterv2.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackbase/CMFlashClusterv2.h b/offline/packages/trackbase/CMFlashClusterv2.h index 12c4f02fd0..cfeb71ec73 100644 --- a/offline/packages/trackbase/CMFlashClusterv2.h +++ b/offline/packages/trackbase/CMFlashClusterv2.h @@ -52,10 +52,10 @@ class CMFlashClusterv2 : public CMFlashCluster void setZ(float z) override { m_pos[2] = z; } unsigned int getNclusters() const override {return m_nclusters;} void setNclusters(unsigned int n) override { m_nclusters = n;} - bool getIsRGap() { return m_isRGap; } - void setIsRGap(bool isRGap) { m_isRGap = isRGap;} - bool getIsPhiGap() { return m_isPhiGap; } - void setIsPhiGap(bool isPhiGap) { m_isPhiGap = isPhiGap;} + bool getIsRGap() const override { return m_isRGap; } + void setIsRGap(bool isRGap) override { m_isRGap = isRGap;} + bool getIsPhiGap() const override { return m_isPhiGap; } + void setIsPhiGap(bool isPhiGap) override { m_isPhiGap = isPhiGap;} // // cluster info From f5b2a21e122d8ad9ba6a36fac2905427759c905e Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 10:20:37 -0400 Subject: [PATCH 126/468] fixed the need for the template functions to be static --- offline/packages/CaloReco/CaloWaveformFitting.cc | 9 ++++----- offline/packages/CaloReco/CaloWaveformFitting.h | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 725157aafd..362eb695af 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -19,9 +19,6 @@ #include #include -// Define some items that must be defined globally in the .cc file -TProfile *CaloWaveformFitting::h_template = nullptr; - double CaloWaveformFitting::template_function(double *x, double *par) { Double_t v1 = par[0] * h_template->Interpolate(x[0] - par[1]) + par[2]; @@ -79,8 +76,10 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit { pedestal = 0.5 * (v.at(size1 - 3) + v.at(size1 - 2)); } - auto f = new TF1(Form("f_%d", (int) round(v.at(size1))), template_function, 0, 31, 3); - ROOT::Math::WrappedMultiTF1 *fitFunction = new ROOT::Math::WrappedMultiTF1(*f, 3); + + + auto f = new TF1(Form("f_%d", (int) round(v.at(size1))), this,&CaloWaveformFitting::template_function, 0, 31, 3,"CaloWaveformFitting","template_function"); + ROOT::Math::WrappedMultiTF1 *fitFunction = new ROOT::Math::WrappedMultiTF1(*f, 3); ROOT::Fit::BinData data(v.size() - 1, 1); ROOT::Fit::FillData(data, h); ROOT::Fit::Chi2Function *EPChi2 = new ROOT::Fit::Chi2Function(data, *fitFunction); diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 1259b85d6c..27ca2c194d 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -37,8 +37,8 @@ class CaloWaveformFitting private: void FastMax(float x0, float x1, float x2, float y0, float y1, float y2, float &xmax, float &ymax); - static TProfile *h_template; - static double template_function(double *x, double *par); + TProfile *h_template; + double template_function(double *x, double *par); int _nthreads = 1; std::string m_template_input_file; std::string url_template; From 55e53286a32d45be54bbf18ac75f7845e3dd9000 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 11:09:31 -0400 Subject: [PATCH 127/468] add new Bbc Vertex, insert/fetch vertices via VTXTYPE --- .../g4simulation/g4vertex/GlobalVertex.h | 11 ++- .../g4vertex/GlobalVertexFastSimReco.cc | 61 +++++++------ .../g4vertex/GlobalVertexFastSimReco.h | 13 ++- .../g4vertex/GlobalVertexMapv1.cc | 23 ++--- .../g4simulation/g4vertex/GlobalVertexMapv1.h | 2 +- .../g4simulation/g4vertex/GlobalVertexReco.cc | 75 ++++++++-------- .../g4simulation/g4vertex/GlobalVertexReco.h | 13 +-- .../g4simulation/g4vertex/GlobalVertexv1.cc | 87 ++++++++++--------- .../g4simulation/g4vertex/GlobalVertexv1.h | 19 ++-- simulation/g4simulation/g4vertex/Makefile.am | 5 +- 10 files changed, 161 insertions(+), 148 deletions(-) diff --git a/simulation/g4simulation/g4vertex/GlobalVertex.h b/simulation/g4simulation/g4vertex/GlobalVertex.h index 5d56823233..e5282e8e92 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertex.h +++ b/simulation/g4simulation/g4vertex/GlobalVertex.h @@ -12,11 +12,16 @@ class GlobalVertex : public PHObject { public: + +// the order matters (best vertex -> highest number), so leave some space in case we want to wedge other vertices in here enum VTXTYPE { - NONE = 0, - BBC = 1, - SVTX = 2 + UNDEFINED = 0, + TRUTH = 100, + SMEARED = 200, + BBC = 300, + SVTX = 400, + SVTX_BBC = 500 }; typedef std::map::const_iterator ConstVtxIter; diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc index 39573916e2..fd4f2117c7 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc @@ -27,14 +27,8 @@ #include // for exit #include -using namespace std; - -GlobalVertexFastSimReco::GlobalVertexFastSimReco(const string &name) +GlobalVertexFastSimReco::GlobalVertexFastSimReco(const std::string &name) : SubsysReco(name) - , _x_smear(NAN) - , _y_smear(NAN) - , _z_smear(NAN) - , _t_smear(NAN) { RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); } @@ -44,11 +38,6 @@ GlobalVertexFastSimReco::~GlobalVertexFastSimReco() gsl_rng_free(RandomGenerator); } -int GlobalVertexFastSimReco::Init(PHCompositeNode */*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) { if (isnan(_x_smear) || @@ -56,7 +45,7 @@ int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) isnan(_z_smear) || isnan(_t_smear)) { - cout << PHWHERE << "::ERROR - smearing must be defined for (x,y,z,t) via set_?_smearing(float)" << endl; + std::cout << PHWHERE << "::ERROR - smearing must be defined for (x,y,z,t) via set_?_smearing(float)" << std::endl; exit(-1); } @@ -65,13 +54,13 @@ int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { - cout << "=================== GlobalVertexFastSimReco::InitRun() ====================" << endl; - cout << " x smearing: " << _x_smear << " cm " << endl; - cout << " y smearing: " << _y_smear << " cm " << endl; - cout << " z smearing: " << _z_smear << " cm " << endl; - cout << " t smearing: " << _t_smear << " cm " << endl; - cout << " random seed: " << seed << endl; - cout << "===========================================================================" << endl; + std::cout << "=================== GlobalVertexFastSimReco::InitRun() ====================" << std::endl; + std::cout << " x smearing: " << _x_smear << " cm " << std::endl; + std::cout << " y smearing: " << _y_smear << " cm " << std::endl; + std::cout << " z smearing: " << _z_smear << " cm " << std::endl; + std::cout << " t smearing: " << _t_smear << " cm " << std::endl; + std::cout << " random seed: " << seed << std::endl; + std::cout << "===========================================================================" << std::endl; } return CreateNodes(topNode); @@ -79,7 +68,7 @@ int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) cout << "GlobalVertexFastSimReco::process_event -- entered" << endl; + if (Verbosity() > 1) std::cout << "GlobalVertexFastSimReco::process_event -- entered" << std::endl; //--------------------------------- // Get Objects off of the Node Tree @@ -87,14 +76,14 @@ int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); if (!truthinfo) { - cout << PHWHERE << "::ERROR - cannot find G4TruthInfo" << endl; + std::cout << PHWHERE << "::ERROR - cannot find G4TruthInfo" << std::endl; exit(-1); } GlobalVertexMap *vertexes = findNode::getClass(topNode, "GlobalVertexMap"); if (!vertexes) { - cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" << endl; + std::cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" << std::endl; exit(-1); } @@ -104,7 +93,22 @@ int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) PHG4VtxPoint *point = truthinfo->GetPrimaryVtx(truthinfo->GetPrimaryVertexIndex()); - GlobalVertex *vertex = new GlobalVertexv1(); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::TRUTH); + vertex->set_x(point->get_x()); + vertex->set_y(point->get_y()); + vertex->set_z(point->get_z()); + vertex->set_t(point->get_t()); + vertex->set_t_err(0.); + for (int i = 0; i<3; i++) + { + for (int j = 0; j<3; j++) + { + vertex->set_error(i, j, 0.0); + } + } + vertexes->insert(vertex); + + vertex = new GlobalVertexv1(GlobalVertex::SMEARED); vertex->set_x(point->get_x() + gsl_ran_gaussian(RandomGenerator, _x_smear)); vertex->set_y(point->get_y() + gsl_ran_gaussian(RandomGenerator, _y_smear)); @@ -130,11 +134,6 @@ int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int GlobalVertexFastSimReco::End(PHCompositeNode */*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - int GlobalVertexFastSimReco::CreateNodes(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -143,7 +142,7 @@ int GlobalVertexFastSimReco::CreateNodes(PHCompositeNode *topNode) PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { - cout << PHWHERE << "DST Node missing, doing nothing." << endl; + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; return Fun4AllReturnCodes::ABORTRUN; } @@ -165,7 +164,7 @@ int GlobalVertexFastSimReco::CreateNodes(PHCompositeNode *topNode) } else { - cout << PHWHERE << "::ERROR - GlobalVertexMap pre-exists, but should not if running FastSim" << endl; + std::cout << PHWHERE << "::ERROR - GlobalVertexMap pre-exists, but should not if running FastSim" << std::endl; exit(-1); } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h index 6bd5fcf334..a33601a9b0 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h @@ -13,6 +13,7 @@ #include +#include #include // for string class PHCompositeNode; @@ -27,10 +28,8 @@ class GlobalVertexFastSimReco : public SubsysReco GlobalVertexFastSimReco(const std::string &name = "GlobalVertexFastSimReco"); ~GlobalVertexFastSimReco() override; - int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode *topNode) override; void set_x_smearing(const float x_smear) { _x_smear = x_smear; } void set_y_smearing(const float y_smear) { _y_smear = y_smear; } @@ -40,11 +39,11 @@ class GlobalVertexFastSimReco : public SubsysReco private: int CreateNodes(PHCompositeNode *topNode); - float _x_smear; - float _y_smear; - float _z_smear; - float _t_smear; - gsl_rng *RandomGenerator; + float _x_smear = std::numeric_limits::quiet_NaN(); + float _y_smear = std::numeric_limits::quiet_NaN(); + float _z_smear = std::numeric_limits::quiet_NaN(); + float _t_smear = std::numeric_limits::quiet_NaN(); + gsl_rng *RandomGenerator = nullptr; }; #endif // G4VERTEX_GLOBALVERTEXFASTSIMRECO_H diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc index 1cd4273fa2..2bc067dd20 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc @@ -6,21 +6,18 @@ #include // for reverse_iterator #include // for pair, make_pair -using namespace std; - -GlobalVertexMapv1::GlobalVertexMapv1() - : _map() -{ -} - GlobalVertexMapv1::~GlobalVertexMapv1() { clear(); } -void GlobalVertexMapv1::identify(ostream& os) const +void GlobalVertexMapv1::identify(std::ostream& os) const { - os << "GlobalVertexMapv1: size = " << _map.size() << endl; + os << "GlobalVertexMapv1: size = " << _map.size() << std::endl; + for (auto &m : _map) + { + m.second->identify(os); + } return; } @@ -52,9 +49,7 @@ GlobalVertex* GlobalVertexMapv1::get(unsigned int id) GlobalVertex* GlobalVertexMapv1::insert(GlobalVertex* clus) { - unsigned int index = 0; - if (!_map.empty()) index = _map.rbegin()->first + 1; - _map.insert(make_pair(index, clus)); - _map[index]->set_id(index); - return _map[index]; + unsigned int index = clus->get_id(); + auto ret = _map.insert(std::make_pair(index, clus)); + return ret.first->second; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h index 00712dfa16..d1e9f6cf40 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h @@ -14,7 +14,7 @@ class GlobalVertexMapv1 : public GlobalVertexMap { public: - GlobalVertexMapv1(); + GlobalVertexMapv1() = default; ~GlobalVertexMapv1() override; void identify(std::ostream& os = std::cout) const override; diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index 6748c9024d..ba90b15c9e 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -8,6 +8,8 @@ #include #include +#include + #include #include @@ -33,22 +35,9 @@ using namespace std; GlobalVertexReco::GlobalVertexReco(const string &name) : SubsysReco(name) - , _xdefault(0.0) - , _xerr(0.3) - , _ydefault(0.0) - , _yerr(0.3) - , _tdefault(0.0) - , _terr(0.2) { } -GlobalVertexReco::~GlobalVertexReco() {} - -int GlobalVertexReco::Init(PHCompositeNode */*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - int GlobalVertexReco::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 0) @@ -73,10 +62,36 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" << endl; exit(-1); } +// just patch in the new bbc vertex + BbcOut *bbcout = findNode::getClass(topNode, "BbcOut"); + if (bbcout) + { + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::BBC); + + vertex->set_x(_xdefault); + vertex->set_y(_ydefault); + vertex->set_z(bbcout->get_VertexPoint()); + + vertex->set_t(bbcout->get_TimeZero()); + vertex->set_t_err(bbcout->get_dTimeZero()); + + vertex->set_error(0, 0, _xerr * _xerr); + vertex->set_error(0, 1, 0.0); + vertex->set_error(0, 2, 0.0); + + vertex->set_error(1, 1, 0.0); + vertex->set_error(1, 1, _yerr *_yerr); + vertex->set_error(1, 2, 0.0); + + vertex->set_error(2, 0, 0.0); + vertex->set_error(2, 1, 0.0); + vertex->set_error(2, 2, bbcout->get_dTimeZero()*bbcout->get_dTimeZero()); + if (Verbosity() > 1) vertex->identify(); + globalmap->insert(vertex); + } SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); BbcVertexMap *bbcmap = findNode::getClass(topNode, "BbcVertexMap"); - // we will make 3 different kinds of global vertexes // (1) SVTX+BBC vertexes - we match SVTX vertex to the nearest BBC vertex within 3 sigma in zvertex // the spatial point comes from the SVTX, the timing from the BBC @@ -126,7 +141,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) if (min_sigma > 3.0 || !bbc_best) continue; // we have a matching pair - GlobalVertex *vertex = new GlobalVertexv1(); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX_BBC); for (unsigned int i = 0; i < 3; ++i) { @@ -150,7 +165,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity()) vertex->identify(); + if (Verbosity() > 1) vertex->identify(); } } @@ -169,7 +184,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) if (isnan(svtx->get_z())) continue; // we have a standalone SVTX vertex - GlobalVertex *vertex = new GlobalVertexv1(); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX); for (unsigned int i = 0; i < 3; ++i) { @@ -192,7 +207,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity()) vertex->identify(); + if (Verbosity() > 1) vertex->identify(); } } @@ -210,7 +225,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) if (used_bbc_vtxids.find(bbc->get_id()) != used_bbc_vtxids.end()) continue; if (isnan(bbc->get_z())) continue; - GlobalVertex *vertex = new GlobalVertexv1(); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); // nominal beam location // could be replaced with a beam spot some day @@ -225,9 +240,9 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) vertex->set_error(0, 1, 0.0); vertex->set_error(0, 2, 0.0); - vertex->set_error(1, 1, 0.0); + vertex->set_error(1, 0, 0.0); vertex->set_error(1, 1, pow(_yerr, 2)); - vertex->set_error(1, 1, 0.0); + vertex->set_error(1, 2, 0.0); vertex->set_error(0, 2, 0.0); vertex->set_error(1, 2, 0.0); @@ -238,15 +253,13 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity()) vertex->identify(); + if (Verbosity() > 1) vertex->identify(); } } - - return Fun4AllReturnCodes::EVENT_OK; -} - -int GlobalVertexReco::End(PHCompositeNode */*topNode*/) +if (Verbosity()) { + globalmap->identify(); +} return Fun4AllReturnCodes::EVENT_OK; } @@ -255,7 +268,7 @@ int GlobalVertexReco::CreateNodes(PHCompositeNode *topNode) PHNodeIterator iter(topNode); // Looking for the DST node - PHCompositeNode *dstNode = static_cast(iter.findFirst("PHCompositeNode", "DST")); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { cout << PHWHERE << "DST Node missing, doing nothing." << endl; @@ -278,11 +291,5 @@ int GlobalVertexReco::CreateNodes(PHCompositeNode *topNode) PHIODataNode *VertexMapNode = new PHIODataNode(vertexes, "GlobalVertexMap", "PHObject"); globalNode->addNode(VertexMapNode); } - else - { - cout << PHWHERE << "::ERROR - GlobalVertexMap pre-exists, but should not, perhaps you are also running the FastSim" << endl; - exit(-1); - } - return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.h b/simulation/g4simulation/g4vertex/GlobalVertexReco.h index f01568a93f..b8ddf2f72b 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.h @@ -24,12 +24,10 @@ class GlobalVertexReco : public SubsysReco { public: GlobalVertexReco(const std::string &name = "GlobalVertexReco"); - ~GlobalVertexReco() override; + ~GlobalVertexReco() override = default; - int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode *topNode) override; void set_x_defaults(float xdefault, float xerr) { @@ -50,9 +48,12 @@ class GlobalVertexReco : public SubsysReco private: int CreateNodes(PHCompositeNode *topNode); - float _xdefault, _xerr; - float _ydefault, _yerr; - float _tdefault, _terr; + float _xdefault = 0.; + float _xerr = 0.3; + float _ydefault = 0.; + float _yerr = 0.3; + float _tdefault = 0.; + float _terr = 0.2; }; #endif // G4VERTEX_GLOBALVERTEXRECO_H diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc index 5baeef01cb..7269b13e44 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc @@ -2,85 +2,90 @@ #include -using namespace std; - -GlobalVertexv1::GlobalVertexv1() - : _id(0xFFFFFFFF) - , _t(NAN) - , _t_err(NAN) - , _pos() - , _chisq(NAN) - , _ndof(0xFFFFFFFF) - , _err() - , _vtx_ids() +GlobalVertexv1::GlobalVertexv1(const GlobalVertex::VTXTYPE id) + : _id(id) { - for (int i = 0; i < 3; ++i) _pos[i] = NAN; - - for (int j = 0; j < 3; ++j) - { - for (int i = j; i < 3; ++i) - { - set_error(i, j, NAN); - } - } + std::fill(std::begin(_pos), std::end(_pos), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(_err),std::end(_err), std::numeric_limits::quiet_NaN()); } -GlobalVertexv1::~GlobalVertexv1() {} - -void GlobalVertexv1::identify(ostream& os) const +void GlobalVertexv1::identify(std::ostream& os) const { - os << "---GlobalVertexv1-----------------------" << endl; - os << "vertexid: " << get_id() << endl; + os << "---GlobalVertexv1-----------------------" << std::endl; + os << "vertexid: " << get_id(); + switch(get_id()) + { + case GlobalVertex::UNDEFINED: + os << ", type GlobalVertex::UNDEFINED" << std::endl; + break; + case GlobalVertex::TRUTH: + os << ", type GlobalVertex::TRUTH" << std::endl; + break; + case GlobalVertex::SMEARED: + os << ", type GlobalVertex::SMEARED" << std::endl; + break; + case GlobalVertex::BBC: + os << ", type GlobalVertex::BBC" << std::endl; + break; + case GlobalVertex::SVTX: + os << ", type GlobalVertex::SVTX" << std::endl; + break; + case GlobalVertex::SVTX_BBC: + os << ", type GlobalVertex::SVTX_BBC" << std::endl; + break; + default: + os << "unknown type of GlobalVertex:" << get_id() << std::endl; + break; + } - os << " t = " << get_t() << endl; + os << " t = " << get_t() << std::endl; os << " (x,y,z) = (" << get_position(0); os << ", " << get_position(1) << ", "; - os << get_position(2) << ") cm" << endl; + os << get_position(2) << ") cm" << std::endl; os << " chisq = " << get_chisq() << ", "; - os << " ndof = " << get_ndof() << endl; + os << " ndof = " << get_ndof() << std::endl; os << " ( "; os << get_error(0, 0) << " , "; os << get_error(0, 1) << " , "; - os << get_error(0, 2) << " )" << endl; + os << get_error(0, 2) << " )" << std::endl; os << " err = ( "; os << get_error(1, 0) << " , "; os << get_error(1, 1) << " , "; - os << get_error(1, 2) << " )" << endl; + os << get_error(1, 2) << " )" << std::endl; os << " ( "; os << get_error(2, 0) << " , "; os << get_error(2, 1) << " , "; - os << get_error(2, 2) << " )" << endl; + os << get_error(2, 2) << " )" << std::endl; - os << " list of vtx ids: " << endl; + os << " list of vtx ids: " << std::endl; for (ConstVtxIter iter = begin_vtxids(); iter != end_vtxids(); ++iter) { - os << " " << iter->first << " => " << iter->second << endl; + os << " " << iter->first << " => " << iter->second << std::endl; } - os << "-----------------------------------------------" << endl; + os << "-----------------------------------------------" << std::endl; return; } int GlobalVertexv1::isValid() const { - if (_id == 0xFFFFFFFF) return 0; - if (isnan(_t)) return 0; - if (isnan(_t_err)) return 0; - if (isnan(_chisq)) return 0; - if (_ndof == 0xFFFFFFFF) return 0; + if (! std::isfinite(_t)) return 0; + if (! std::isfinite(_t_err)) return 0; + if (! std::isfinite(_chisq)) return 0; + if (_ndof == std::numeric_limits::max()) return 0; for (int i = 0; i < 3; ++i) { - if (isnan(_pos[i])) return 0; + if (! std::isfinite(_pos[i])) return 0; } for (int j = 0; j < 3; ++j) { for (int i = j; i < 3; ++i) { - if (isnan(get_error(i, j))) return 0; + if (! std::isfinite(get_error(i, j))) return 0; } } if (_vtx_ids.empty()) return 0; diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.h b/simulation/g4simulation/g4vertex/GlobalVertexv1.h index c43a06085b..21600fcfb9 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexv1.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexv1.h @@ -6,6 +6,7 @@ #include "GlobalVertex.h" #include // for size_t +#include #include #include #include // for pair, make_pair @@ -15,8 +16,8 @@ class PHObject; class GlobalVertexv1 : public GlobalVertex { public: - GlobalVertexv1(); - ~GlobalVertexv1() override; + GlobalVertexv1(const GlobalVertex::VTXTYPE id=GlobalVertex::UNDEFINED); + ~GlobalVertexv1() override = default; // PHObject virtual overloads @@ -82,13 +83,13 @@ class GlobalVertexv1 : public GlobalVertex private: unsigned int covar_index(unsigned int i, unsigned int j) const; - unsigned int _id; //< unique identifier within container - float _t; //< collision time - float _t_err; //< collision time uncertainty - float _pos[3]; //< collision position x,y,z - float _chisq; //< vertex fit chisq - unsigned int _ndof; //< degrees of freedom - float _err[6]; //< error covariance matrix (+/- cm^2) + unsigned int _id = std::numeric_limits::max(); //< unique identifier within container + float _t = std::numeric_limits::quiet_NaN(); //< collision time + float _t_err = std::numeric_limits::quiet_NaN(); //< collision time uncertainty + float _pos[3] = {}; //< collision position x,y,z + float _chisq = std::numeric_limits::quiet_NaN(); //< vertex fit chisq + unsigned int _ndof = std::numeric_limits::max(); + float _err[6] = {}; //< error covariance matrix (+/- cm^2) std::map _vtx_ids; //< list of vtx ids ClassDefOverride(GlobalVertexv1, 1); diff --git a/simulation/g4simulation/g4vertex/Makefile.am b/simulation/g4simulation/g4vertex/Makefile.am index 60caa2aa8f..8cb8fe78c4 100644 --- a/simulation/g4simulation/g4vertex/Makefile.am +++ b/simulation/g4simulation/g4vertex/Makefile.am @@ -18,11 +18,12 @@ libg4vertex_io_la_LIBADD = \ -ltrackbase_historic_io libg4vertex_la_LIBADD = \ + libg4vertex_io.la \ + -lbbc_io \ -lg4detectors \ -lfun4all \ -lg4bbc_io \ - -ltrackbase_historic_io \ - libg4vertex_io.la + -ltrackbase_historic_io pkginclude_HEADERS = \ GlobalVertex.h \ From 0cd6cc235a2f2a793d17951fb7e226e9b16ac2ae Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 11:10:42 -0400 Subject: [PATCH 128/468] remove eventheader - it is not useful --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 27 ++++++++------------- simulation/g4simulation/g4bbc/BbcSimReco.h | 1 - 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index b40c28cc15..764dd910d1 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -9,8 +9,6 @@ #include #include -#include - #include #include @@ -185,8 +183,6 @@ int BbcSimReco::InitRun(PHCompositeNode *topNode) // Call user instructions for every event int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) { - f_evt = _evtheader->get_EvtSequence(); - //**** Initialize Variables // Arm Data @@ -222,7 +218,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) f_vz = vtxp->get_z(); f_vt = vtxp->get_t(); - if (Verbosity() && f_evt < 20) + if (Verbosity()) { std::cout << "VTXP " << "\t" << f_vx << "\t" << f_vy << "\t" << f_vz << "\t" << f_vt << std::endl; @@ -308,7 +304,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) // Fill charge and time info if (len[ich] > 0.) { - if (f_evt < 20 && Verbosity() != 0) + if (Verbosity() > 0) { std::cout << "ich " << ich << "\t" << len[ich] << "\t" << edep[ich] << std::endl; } @@ -433,38 +429,35 @@ void BbcSimReco::GetNodes(PHCompositeNode *topNode) // Truth container _truth_container = findNode::getClass(topNode, "G4TruthInfo"); - if (!_truth_container && f_evt < 10) + if (!_truth_container) { std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl; + gSystem->Exit(1); } // BBC hit container _bbchits = findNode::getClass(topNode, "G4HIT_BBC"); - if (!_bbchits && f_evt < 10) - { - std::cout << PHWHERE << " G4HIT_BBC node not found on node tree" << std::endl; - } - - // Event Header info - _evtheader = findNode::getClass(topNode, "EventHeader"); - if (!_evtheader && f_evt < 10) + if (!_bbchits) { std::cout << PHWHERE << " G4HIT_BBC node not found on node tree" << std::endl; + gSystem->Exit(1); } /** DST Objects **/ // BbcOut data _bbcout = findNode::getClass(topNode, "BbcOut"); - if (!_bbcout && f_evt < 10) + if (!_bbcout) { std::cout << PHWHERE << " BbcOut node not found on node tree" << std::endl; + gSystem->Exit(1); } // BbcPmtContainer _bbcpmts = findNode::getClass(topNode, "BbcPmtContainer"); - if (!_bbcpmts && f_evt < 10) + if (!_bbcpmts) { std::cout << PHWHERE << " BbcPmtContainer node not found on node tree" << std::endl; + gSystem->Exit(1); } } diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.h b/simulation/g4simulation/g4bbc/BbcSimReco.h index d62a101f24..f6b1a7ef3d 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.h +++ b/simulation/g4simulation/g4bbc/BbcSimReco.h @@ -83,7 +83,6 @@ class BbcSimReco : public SubsysReco // Input Objects from DST PHG4TruthInfoContainer *_truth_container = nullptr; PHG4HitContainer *_bbchits = nullptr; - EventHeader *_evtheader = nullptr; // Output to DST BbcOut *_bbcout = nullptr; From 790e206f2ec771ceed81daac95131f82285dee8a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 11:18:31 -0400 Subject: [PATCH 129/468] remove using namespace, use std::numeric_limits::quiet_NaN() for NAN --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 24 ++++++++++----------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index 764dd910d1..2f2f4d0ab3 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -116,22 +116,20 @@ namespace BBCINFO }; */ -} // namespace BBCINFO - -using namespace BBCINFO; +} //____________________________________ BbcSimReco::BbcSimReco(const std::string &name) : SubsysReco(name) , _tres(0.05) { - std::fill(std::begin(f_pmtq), std::end(f_pmtq), NAN); - std::fill(std::begin(f_pmtt0), std::end(f_pmtt0), NAN); - std::fill(std::begin(f_pmtt1), std::end(f_pmtt1), NAN); + std::fill(std::begin(f_pmtq), std::end(f_pmtq), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(f_pmtt0), std::end(f_pmtt0), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(f_pmtt1), std::end(f_pmtt1), std::numeric_limits::quiet_NaN()); std::fill(std::begin(f_bbcn), std::end(f_bbcn), 0); - std::fill(std::begin(f_bbcq), std::end(f_bbcq), NAN); - std::fill(std::begin(f_bbct), std::end(f_bbct), NAN); - std::fill(std::begin(f_bbcte), std::end(f_bbcte), NAN); + std::fill(std::begin(f_bbcq), std::end(f_bbcq), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(f_bbct), std::end(f_bbct), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(f_bbcte), std::end(f_bbcte), std::numeric_limits::quiet_NaN()); hevt_bbct[0] = nullptr; hevt_bbct[1] = nullptr; m_RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); @@ -194,8 +192,8 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) f_bbct[1] = -9999.; f_bbcte[0] = -9999.; f_bbcte[1] = -9999.; - f_bbcz = NAN; - f_bbct0 = NAN; + f_bbcz = std::numeric_limits::quiet_NaN(); + f_bbct0 = std::numeric_limits::quiet_NaN(); hevt_bbct[0]->Reset(); hevt_bbct[1]->Reset(); @@ -279,7 +277,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) // get summed path length for particles that can create CKOV light // n.p.e. is determined from path length Double_t beta = v4.Beta(); - if (beta > v_ckov && charge != 0.) + if (beta > BBCINFO::v_ckov && charge != 0.) { len[ch] += this_hit->get_path_length(); @@ -375,7 +373,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) } // Now calculate zvtx, t0 from best times - f_bbcz = (f_bbct[0] - f_bbct[1]) * C / 2.0; + f_bbcz = (f_bbct[0] - f_bbct[1]) * BBCINFO::C / 2.0; f_bbct0 = (f_bbct[0] + f_bbct[1]) / 2.0; _bbcout->set_Vertex(f_bbcz, 0.6); From d80624538cc916f96f27bc9e13f7c51529b4b1f7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 11:19:11 -0400 Subject: [PATCH 130/468] clang-tidy --- .../g4vertex/GlobalVertexFastSimReco.cc | 3 +- .../g4vertex/GlobalVertexMapv1.cc | 12 +++--- .../g4simulation/g4vertex/GlobalVertexReco.cc | 39 ++++++++++++------- .../g4simulation/g4vertex/GlobalVertexv1.cc | 26 ++++++++----- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc index fd4f2117c7..3024804894 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc @@ -68,7 +68,8 @@ int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) std::cout << "GlobalVertexFastSimReco::process_event -- entered" << std::endl; + if (Verbosity() > 1) { std::cout << "GlobalVertexFastSimReco::process_event -- entered" << std::endl; +} //--------------------------------- // Get Objects off of the Node Tree diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc index 2bc067dd20..413043acb1 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc @@ -23,11 +23,9 @@ void GlobalVertexMapv1::identify(std::ostream& os) const void GlobalVertexMapv1::clear() { - for (Iter iter = _map.begin(); - iter != _map.end(); - ++iter) + for (auto & iter : _map) { - delete iter->second; + delete iter.second; } _map.clear(); return; @@ -36,14 +34,16 @@ void GlobalVertexMapv1::clear() const GlobalVertex* GlobalVertexMapv1::get(unsigned int id) const { ConstIter iter = _map.find(id); - if (iter == _map.end()) return nullptr; + if (iter == _map.end()) { return nullptr; +} return iter->second; } GlobalVertex* GlobalVertexMapv1::get(unsigned int id) { Iter iter = _map.find(id); - if (iter == _map.end()) return nullptr; + if (iter == _map.end()) { return nullptr; +} return iter->second; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index ba90b15c9e..170394b1ab 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -51,7 +51,8 @@ int GlobalVertexReco::InitRun(PHCompositeNode *topNode) int GlobalVertexReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) cout << "GlobalVertexReco::process_event -- entered" << endl; + if (Verbosity() > 1) { cout << "GlobalVertexReco::process_event -- entered" << endl; +} //--------------------------------- // Get Objects off of the Node Tree @@ -86,7 +87,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) vertex->set_error(2, 0, 0.0); vertex->set_error(2, 1, 0.0); vertex->set_error(2, 2, bbcout->get_dTimeZero()*bbcout->get_dTimeZero()); - if (Verbosity() > 1) vertex->identify(); + if (Verbosity() > 1) { vertex->identify(); +} globalmap->insert(vertex); } @@ -113,7 +115,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) if (svtxmap && bbcmap) { - if (Verbosity()) cout << "GlobalVertexReco::process_event - svtxmap && bbcmap" << endl; + if (Verbosity()) { cout << "GlobalVertexReco::process_event - svtxmap && bbcmap" << endl; +} for (SvtxVertexMap::ConstIter svtxiter = svtxmap->begin(); svtxiter != svtxmap->end(); @@ -138,7 +141,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } - if (min_sigma > 3.0 || !bbc_best) continue; + if (min_sigma > 3.0 || !bbc_best) { continue; +} // we have a matching pair GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX_BBC); @@ -165,14 +169,16 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) vertex->identify(); + if (Verbosity() > 1) { vertex->identify(); +} } } // okay now loop over all unused SVTX vertexes (2nd class)... if (svtxmap) { - if (Verbosity()) cout << "GlobalVertexReco::process_event - svtxmap " << endl; + if (Verbosity()) { cout << "GlobalVertexReco::process_event - svtxmap " << endl; +} for (SvtxVertexMap::ConstIter svtxiter = svtxmap->begin(); svtxiter != svtxmap->end(); @@ -180,8 +186,10 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) { const SvtxVertex *svtx = svtxiter->second; - if (used_svtx_vtxids.find(svtx->get_id()) != used_svtx_vtxids.end()) continue; - if (isnan(svtx->get_z())) continue; + if (used_svtx_vtxids.find(svtx->get_id()) != used_svtx_vtxids.end()) { continue; +} + if (isnan(svtx->get_z())) { continue; +} // we have a standalone SVTX vertex GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX); @@ -207,14 +215,16 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) vertex->identify(); + if (Verbosity() > 1) { vertex->identify(); +} } } // okay now loop over all unused BBC vertexes (3rd class)... if (bbcmap) { - if (Verbosity()) cout << "GlobalVertexReco::process_event - bbcmap" << endl; + if (Verbosity()) { cout << "GlobalVertexReco::process_event - bbcmap" << endl; +} for (BbcVertexMap::ConstIter bbciter = bbcmap->begin(); bbciter != bbcmap->end(); @@ -222,8 +232,10 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) { const BbcVertex *bbc = bbciter->second; - if (used_bbc_vtxids.find(bbc->get_id()) != used_bbc_vtxids.end()) continue; - if (isnan(bbc->get_z())) continue; + if (used_bbc_vtxids.find(bbc->get_id()) != used_bbc_vtxids.end()) { continue; +} + if (isnan(bbc->get_z())) { continue; +} GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); @@ -253,7 +265,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) vertex->identify(); + if (Verbosity() > 1) { vertex->identify(); +} } } if (Verbosity()) diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc index 7269b13e44..85ed99e6eb 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc @@ -72,23 +72,30 @@ void GlobalVertexv1::identify(std::ostream& os) const int GlobalVertexv1::isValid() const { - if (! std::isfinite(_t)) return 0; - if (! std::isfinite(_t_err)) return 0; - if (! std::isfinite(_chisq)) return 0; - if (_ndof == std::numeric_limits::max()) return 0; + if (! std::isfinite(_t)) { return 0; +} + if (! std::isfinite(_t_err)) { return 0; +} + if (! std::isfinite(_chisq)) { return 0; +} + if (_ndof == std::numeric_limits::max()) { return 0; +} - for (int i = 0; i < 3; ++i) + for (float _po : _pos) { - if (! std::isfinite(_pos[i])) return 0; + if (! std::isfinite(_po)) { return 0; +} } for (int j = 0; j < 3; ++j) { for (int i = j; i < 3; ++i) { - if (! std::isfinite(get_error(i, j))) return 0; + if (! std::isfinite(get_error(i, j))) { return 0; +} } } - if (_vtx_ids.empty()) return 0; + if (_vtx_ids.empty()) { return 0; +} return 1; } @@ -105,6 +112,7 @@ float GlobalVertexv1::get_error(unsigned int i, unsigned int j) const unsigned int GlobalVertexv1::covar_index(unsigned int i, unsigned int j) const { - if (i > j) std::swap(i, j); + if (i > j) { std::swap(i, j); +} return i + 1 + (j + 1) * (j) / 2 - 1; } From 0cc82eca5fff6d40f9f02cd9ad2e6041513b47ac Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 11:21:10 -0400 Subject: [PATCH 131/468] clang-format --- .../g4simulation/g4vertex/GlobalVertex.h | 3 +- .../g4vertex/GlobalVertexFastSimReco.cc | 26 ++-- .../g4vertex/GlobalVertexFastSimReco.h | 2 +- .../g4simulation/g4vertex/GlobalVertexMap.cc | 1 - .../g4vertex/GlobalVertexMapv1.cc | 20 +-- .../g4simulation/g4vertex/GlobalVertexMapv1.h | 2 +- .../g4simulation/g4vertex/GlobalVertexReco.cc | 136 +++++++++++------- .../g4simulation/g4vertex/GlobalVertexReco.h | 2 +- .../g4simulation/g4vertex/GlobalVertexv1.cc | 52 ++++--- .../g4simulation/g4vertex/GlobalVertexv1.h | 18 +-- 10 files changed, 154 insertions(+), 108 deletions(-) diff --git a/simulation/g4simulation/g4vertex/GlobalVertex.h b/simulation/g4simulation/g4vertex/GlobalVertex.h index e5282e8e92..b5c0928462 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertex.h +++ b/simulation/g4simulation/g4vertex/GlobalVertex.h @@ -12,8 +12,7 @@ class GlobalVertex : public PHObject { public: - -// the order matters (best vertex -> highest number), so leave some space in case we want to wedge other vertices in here + // the order matters (best vertex -> highest number), so leave some space in case we want to wedge other vertices in here enum VTXTYPE { UNDEFINED = 0, diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc index 3024804894..c7a3ba2034 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc @@ -1,30 +1,30 @@ #include "GlobalVertexFastSimReco.h" -#include "GlobalVertexMap.h" // for GlobalVertexMap +#include "GlobalVertex.h" // for GlobalVertex +#include "GlobalVertexMap.h" // for GlobalVertexMap #include "GlobalVertexMapv1.h" -#include "GlobalVertex.h" // for GlobalVertex #include "GlobalVertexv1.h" #include #include #include -#include // for SubsysReco +#include // for SubsysReco #include #include -#include // for PHNode +#include // for PHNode #include -#include // for PHObject +#include // for PHObject #include #include -#include // for PHWHERE +#include // for PHWHERE #include -#include // for gsl_rng_alloc, gsl_rng_free +#include // for gsl_rng_alloc, gsl_rng_free #include -#include // for exit +#include // for exit #include GlobalVertexFastSimReco::GlobalVertexFastSimReco(const std::string &name) @@ -68,8 +68,10 @@ int GlobalVertexFastSimReco::InitRun(PHCompositeNode *topNode) int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { std::cout << "GlobalVertexFastSimReco::process_event -- entered" << std::endl; -} + if (Verbosity() > 1) + { + std::cout << "GlobalVertexFastSimReco::process_event -- entered" << std::endl; + } //--------------------------------- // Get Objects off of the Node Tree @@ -100,9 +102,9 @@ int GlobalVertexFastSimReco::process_event(PHCompositeNode *topNode) vertex->set_z(point->get_z()); vertex->set_t(point->get_t()); vertex->set_t_err(0.); - for (int i = 0; i<3; i++) + for (int i = 0; i < 3; i++) { - for (int j = 0; j<3; j++) + for (int j = 0; j < 3; j++) { vertex->set_error(i, j, 0.0); } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h index a33601a9b0..1dcdc281b9 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.h @@ -14,7 +14,7 @@ #include #include -#include // for string +#include // for string class PHCompositeNode; diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMap.cc b/simulation/g4simulation/g4vertex/GlobalVertexMap.cc index fe6dd72064..55da18b389 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMap.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexMap.cc @@ -31,4 +31,3 @@ GlobalVertexMap::Iter GlobalVertexMap::end() { return DummyGlobalVertexMap.end(); } - diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc index 413043acb1..9abcae3a0b 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc @@ -3,8 +3,8 @@ #include "GlobalVertex.h" #include "GlobalVertexMap.h" -#include // for reverse_iterator -#include // for pair, make_pair +#include // for reverse_iterator +#include // for pair, make_pair GlobalVertexMapv1::~GlobalVertexMapv1() { @@ -14,7 +14,7 @@ GlobalVertexMapv1::~GlobalVertexMapv1() void GlobalVertexMapv1::identify(std::ostream& os) const { os << "GlobalVertexMapv1: size = " << _map.size() << std::endl; - for (auto &m : _map) + for (auto& m : _map) { m.second->identify(os); } @@ -23,7 +23,7 @@ void GlobalVertexMapv1::identify(std::ostream& os) const void GlobalVertexMapv1::clear() { - for (auto & iter : _map) + for (const auto& iter : _map) { delete iter.second; } @@ -34,16 +34,20 @@ void GlobalVertexMapv1::clear() const GlobalVertex* GlobalVertexMapv1::get(unsigned int id) const { ConstIter iter = _map.find(id); - if (iter == _map.end()) { return nullptr; -} + if (iter == _map.end()) + { + return nullptr; + } return iter->second; } GlobalVertex* GlobalVertexMapv1::get(unsigned int id) { Iter iter = _map.find(id); - if (iter == _map.end()) { return nullptr; -} + if (iter == _map.end()) + { + return nullptr; + } return iter->second; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h index d1e9f6cf40..33fb957cc6 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h @@ -7,7 +7,7 @@ #include "GlobalVertex.h" -#include // for size_t +#include // for size_t #include #include diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index 170394b1ab..71e28c2ed8 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -1,8 +1,8 @@ #include "GlobalVertexReco.h" +#include "GlobalVertex.h" // for GlobalVertex, GlobalVe... +#include "GlobalVertexMap.h" // for GlobalVertexMap #include "GlobalVertexMapv1.h" -#include "GlobalVertexMap.h" // for GlobalVertexMap -#include "GlobalVertex.h" // for GlobalVertex, GlobalVe... #include "GlobalVertexv1.h" #include @@ -14,22 +14,22 @@ #include #include -#include // for SubsysReco +#include // for SubsysReco #include #include -#include // for PHNode +#include // for PHNode #include -#include // for PHObject +#include // for PHObject #include -#include // for PHWHERE +#include // for PHWHERE #include #include -#include // for exit -#include // for _Rb_tree_const_iterator +#include // for exit #include -#include // for pair +#include // for _Rb_tree_const_iterator +#include // for pair using namespace std; @@ -51,8 +51,10 @@ int GlobalVertexReco::InitRun(PHCompositeNode *topNode) int GlobalVertexReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { cout << "GlobalVertexReco::process_event -- entered" << endl; -} + if (Verbosity() > 1) + { + cout << "GlobalVertexReco::process_event -- entered" << endl; + } //--------------------------------- // Get Objects off of the Node Tree @@ -63,33 +65,35 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" << endl; exit(-1); } -// just patch in the new bbc vertex + // just patch in the new bbc vertex BbcOut *bbcout = findNode::getClass(topNode, "BbcOut"); if (bbcout) { GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::BBC); - vertex->set_x(_xdefault); - vertex->set_y(_ydefault); - vertex->set_z(bbcout->get_VertexPoint()); + vertex->set_x(_xdefault); + vertex->set_y(_ydefault); + vertex->set_z(bbcout->get_VertexPoint()); - vertex->set_t(bbcout->get_TimeZero()); - vertex->set_t_err(bbcout->get_dTimeZero()); + vertex->set_t(bbcout->get_TimeZero()); + vertex->set_t_err(bbcout->get_dTimeZero()); - vertex->set_error(0, 0, _xerr * _xerr); - vertex->set_error(0, 1, 0.0); - vertex->set_error(0, 2, 0.0); + vertex->set_error(0, 0, _xerr * _xerr); + vertex->set_error(0, 1, 0.0); + vertex->set_error(0, 2, 0.0); - vertex->set_error(1, 1, 0.0); - vertex->set_error(1, 1, _yerr *_yerr); - vertex->set_error(1, 2, 0.0); + vertex->set_error(1, 1, 0.0); + vertex->set_error(1, 1, _yerr * _yerr); + vertex->set_error(1, 2, 0.0); - vertex->set_error(2, 0, 0.0); - vertex->set_error(2, 1, 0.0); - vertex->set_error(2, 2, bbcout->get_dTimeZero()*bbcout->get_dTimeZero()); - if (Verbosity() > 1) { vertex->identify(); -} - globalmap->insert(vertex); + vertex->set_error(2, 0, 0.0); + vertex->set_error(2, 1, 0.0); + vertex->set_error(2, 2, bbcout->get_dTimeZero() * bbcout->get_dTimeZero()); + if (Verbosity() > 1) + { + vertex->identify(); + } + globalmap->insert(vertex); } SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); @@ -115,8 +119,10 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) if (svtxmap && bbcmap) { - if (Verbosity()) { cout << "GlobalVertexReco::process_event - svtxmap && bbcmap" << endl; -} + if (Verbosity()) + { + cout << "GlobalVertexReco::process_event - svtxmap && bbcmap" << endl; + } for (SvtxVertexMap::ConstIter svtxiter = svtxmap->begin(); svtxiter != svtxmap->end(); @@ -141,8 +147,10 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } - if (min_sigma > 3.0 || !bbc_best) { continue; -} + if (min_sigma > 3.0 || !bbc_best) + { + continue; + } // we have a matching pair GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX_BBC); @@ -169,16 +177,20 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) { vertex->identify(); -} + if (Verbosity() > 1) + { + vertex->identify(); + } } } // okay now loop over all unused SVTX vertexes (2nd class)... if (svtxmap) { - if (Verbosity()) { cout << "GlobalVertexReco::process_event - svtxmap " << endl; -} + if (Verbosity()) + { + cout << "GlobalVertexReco::process_event - svtxmap " << endl; + } for (SvtxVertexMap::ConstIter svtxiter = svtxmap->begin(); svtxiter != svtxmap->end(); @@ -186,10 +198,14 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) { const SvtxVertex *svtx = svtxiter->second; - if (used_svtx_vtxids.find(svtx->get_id()) != used_svtx_vtxids.end()) { continue; -} - if (isnan(svtx->get_z())) { continue; -} + if (used_svtx_vtxids.find(svtx->get_id()) != used_svtx_vtxids.end()) + { + continue; + } + if (isnan(svtx->get_z())) + { + continue; + } // we have a standalone SVTX vertex GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX); @@ -215,16 +231,20 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) { vertex->identify(); -} + if (Verbosity() > 1) + { + vertex->identify(); + } } } // okay now loop over all unused BBC vertexes (3rd class)... if (bbcmap) { - if (Verbosity()) { cout << "GlobalVertexReco::process_event - bbcmap" << endl; -} + if (Verbosity()) + { + cout << "GlobalVertexReco::process_event - bbcmap" << endl; + } for (BbcVertexMap::ConstIter bbciter = bbcmap->begin(); bbciter != bbcmap->end(); @@ -232,10 +252,14 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) { const BbcVertex *bbc = bbciter->second; - if (used_bbc_vtxids.find(bbc->get_id()) != used_bbc_vtxids.end()) { continue; -} - if (isnan(bbc->get_z())) { continue; -} + if (used_bbc_vtxids.find(bbc->get_id()) != used_bbc_vtxids.end()) + { + continue; + } + if (isnan(bbc->get_z())) + { + continue; + } GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); @@ -265,14 +289,16 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); - if (Verbosity() > 1) { vertex->identify(); -} + if (Verbosity() > 1) + { + vertex->identify(); + } } } -if (Verbosity()) -{ - globalmap->identify(); -} + if (Verbosity()) + { + globalmap->identify(); + } return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.h b/simulation/g4simulation/g4vertex/GlobalVertexReco.h index b8ddf2f72b..6c0ae222fb 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.h @@ -12,7 +12,7 @@ #include -#include // for string +#include // for string class PHCompositeNode; diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc index 85ed99e6eb..88d90170a5 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexv1.cc @@ -6,14 +6,14 @@ GlobalVertexv1::GlobalVertexv1(const GlobalVertex::VTXTYPE id) : _id(id) { std::fill(std::begin(_pos), std::end(_pos), std::numeric_limits::quiet_NaN()); - std::fill(std::begin(_err),std::end(_err), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(_err), std::end(_err), std::numeric_limits::quiet_NaN()); } void GlobalVertexv1::identify(std::ostream& os) const { os << "---GlobalVertexv1-----------------------" << std::endl; os << "vertexid: " << get_id(); - switch(get_id()) + switch (get_id()) { case GlobalVertex::UNDEFINED: os << ", type GlobalVertex::UNDEFINED" << std::endl; @@ -72,30 +72,44 @@ void GlobalVertexv1::identify(std::ostream& os) const int GlobalVertexv1::isValid() const { - if (! std::isfinite(_t)) { return 0; -} - if (! std::isfinite(_t_err)) { return 0; -} - if (! std::isfinite(_chisq)) { return 0; -} - if (_ndof == std::numeric_limits::max()) { return 0; -} + if (!std::isfinite(_t)) + { + return 0; + } + if (!std::isfinite(_t_err)) + { + return 0; + } + if (!std::isfinite(_chisq)) + { + return 0; + } + if (_ndof == std::numeric_limits::max()) + { + return 0; + } for (float _po : _pos) { - if (! std::isfinite(_po)) { return 0; -} + if (!std::isfinite(_po)) + { + return 0; + } } for (int j = 0; j < 3; ++j) { for (int i = j; i < 3; ++i) { - if (! std::isfinite(get_error(i, j))) { return 0; -} + if (!std::isfinite(get_error(i, j))) + { + return 0; + } } } - if (_vtx_ids.empty()) { return 0; -} + if (_vtx_ids.empty()) + { + return 0; + } return 1; } @@ -112,7 +126,9 @@ float GlobalVertexv1::get_error(unsigned int i, unsigned int j) const unsigned int GlobalVertexv1::covar_index(unsigned int i, unsigned int j) const { - if (i > j) { std::swap(i, j); -} + if (i > j) + { + std::swap(i, j); + } return i + 1 + (j + 1) * (j) / 2 - 1; } diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.h b/simulation/g4simulation/g4vertex/GlobalVertexv1.h index 21600fcfb9..cd7119b817 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexv1.h +++ b/simulation/g4simulation/g4vertex/GlobalVertexv1.h @@ -5,18 +5,18 @@ #include "GlobalVertex.h" -#include // for size_t -#include +#include // for size_t #include +#include #include -#include // for pair, make_pair +#include // for pair, make_pair class PHObject; class GlobalVertexv1 : public GlobalVertex { public: - GlobalVertexv1(const GlobalVertex::VTXTYPE id=GlobalVertex::UNDEFINED); + GlobalVertexv1(const GlobalVertex::VTXTYPE id = GlobalVertex::UNDEFINED); ~GlobalVertexv1() override = default; // PHObject virtual overloads @@ -83,13 +83,13 @@ class GlobalVertexv1 : public GlobalVertex private: unsigned int covar_index(unsigned int i, unsigned int j) const; - unsigned int _id = std::numeric_limits::max(); //< unique identifier within container - float _t = std::numeric_limits::quiet_NaN(); //< collision time - float _t_err = std::numeric_limits::quiet_NaN(); //< collision time uncertainty + unsigned int _id = std::numeric_limits::max(); //< unique identifier within container + float _t = std::numeric_limits::quiet_NaN(); //< collision time + float _t_err = std::numeric_limits::quiet_NaN(); //< collision time uncertainty float _pos[3] = {}; //< collision position x,y,z - float _chisq = std::numeric_limits::quiet_NaN(); //< vertex fit chisq + float _chisq = std::numeric_limits::quiet_NaN(); //< vertex fit chisq unsigned int _ndof = std::numeric_limits::max(); - float _err[6] = {}; //< error covariance matrix (+/- cm^2) + float _err[6] = {}; //< error covariance matrix (+/- cm^2) std::map _vtx_ids; //< list of vtx ids ClassDefOverride(GlobalVertexv1, 1); From 57ec661ff36feda0b2e600abbc78a069c0d1b995 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 6 Apr 2023 11:40:13 -0400 Subject: [PATCH 132/468] initial compiling version of distortion qa module --- offline/QA/modules/Makefile.am | 2 + .../QA/modules/QAG4SimulationDistortions.cc | 285 ++++++++++++++++++ .../QA/modules/QAG4SimulationDistortions.h | 44 +++ offline/packages/tpccalib/PHTpcResiduals.cc | 6 +- offline/packages/tpccalib/PHTpcResiduals.h | 2 +- 5 files changed, 336 insertions(+), 3 deletions(-) create mode 100644 offline/QA/modules/QAG4SimulationDistortions.cc create mode 100644 offline/QA/modules/QAG4SimulationDistortions.h diff --git a/offline/QA/modules/Makefile.am b/offline/QA/modules/Makefile.am index c6720b9c78..f7d946d665 100644 --- a/offline/QA/modules/Makefile.am +++ b/offline/QA/modules/Makefile.am @@ -34,6 +34,7 @@ libqa_modules_la_LIBADD = \ pkginclude_HEADERS = \ QAG4SimulationCalorimeter.h \ QAG4SimulationCalorimeterSum.h \ + QAG4SimulationDistortions.h \ QAG4SimulationIntt.h \ QAG4SimulationJet.h \ QAG4SimulationKFParticle.h \ @@ -53,6 +54,7 @@ libqa_kfparticle_la_SOURCES = \ libqa_modules_la_SOURCES = \ QAG4SimulationCalorimeter.cc \ QAG4SimulationCalorimeterSum.cc \ + QAG4SimulationDistortions.cc \ QAG4SimulationIntt.cc \ QAG4SimulationJet.cc \ QAG4SimulationMicromegas.cc \ diff --git a/offline/QA/modules/QAG4SimulationDistortions.cc b/offline/QA/modules/QAG4SimulationDistortions.cc new file mode 100644 index 0000000000..ac0e6eed87 --- /dev/null +++ b/offline/QA/modules/QAG4SimulationDistortions.cc @@ -0,0 +1,285 @@ + +#include "QAG4SimulationDistortions.h" +#include "QAHistManagerDef.h" + +#include +#include + +#include +#include +#include // for PHWHERE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include // for map +#include // for pair + +namespace +{ + + // square + template inline constexpr T square( const T& x ) { return x*x; } + + // radius + template T get_r( const T& x, const T& y ) { return std::sqrt( square(x) + square(y) ); } + + template inline constexpr T deltaPhi(const T& phi) + { + if (phi > M_PI) + return phi - 2. * M_PI; + else if (phi <= -M_PI) + return phi + 2.* M_PI; + else + return phi; + } +} + +//____________________________________________________________________________.. +QAG4SimulationDistortions::QAG4SimulationDistortions(const std::string &name): + SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +QAG4SimulationDistortions::~QAG4SimulationDistortions() +{ +} + +//____________________________________________________________________________.. +int QAG4SimulationDistortions::Init(PHCompositeNode*) +{ + Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + TH1* h(nullptr); + + h = new TH2F(TString(get_histo_prefix()) + "betadz",";tan#beta; #Deltaz [cm]",100,-0.5,0.5,100,-0.5,0.5); + + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "alphardphi",";tan#alpha; r#Delta#phi [cm]", 100,-0.5,0.5,100,-0.5,0.5); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "rphiResid", ";r [cm]; #Deltar#phi [cm]", 60, 20, 80, 500, -2, 2); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "zResid", ";z [cm]; #Deltaz [cm]", 200, -100, 100, 1000, -2, 2); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "etaResid", ";#eta;#Delta#eta", 20, -1, 1, 500, -0.2, 0.2); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "etaResidLayer", ";r [cm]; #Delta#eta", 60, 20, 80, 500, -0.2, 0.2); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "zResidLayer", ";r [cm]; #Deltaz [cm]", 60, 20, 80, 1000, -2, 2); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "deltarphi_layer", ";layer; r.#Delta#phi_{track-cluster} (cm)", 57, 0, 57, 500, -2, 2 ); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "deltaz_layer", ";layer; #Deltaz_{track-cluster} (cm)", 57, 0, 57, 100, -2, 2 ); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "statez_pulls","layer; #Deltaz_{track-cluster}/#sigma_{z}^{state}",57,0,57,100,-5,5); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "staterphi_pulls","layer; #Deltar#phi_{track-cluster}/#sigma_{rphi}^{state}",57,0,57,100,-5,5); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "clusz_pulls","layer; #Deltaz_{track-cluster}/#sigma_{z}^{clus}",57,0,57,100,-5,5); + hm->registerHisto(h); + + h = new TH2F(TString(get_histo_prefix()) + "clusrphi_pulls","layer; #Deltar#phi_{track-cluster}/#sigma_{r#phi}^{clus}",57,0,57,100,-5,5); + hm->registerHisto(h); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int QAG4SimulationDistortions::InitRun(PHCompositeNode *topNode) +{ + m_trackMap = findNode::getClass(topNode,"SvtxSiliconMMTrackMap"); + m_clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); + + if(not m_trackMap or not m_clusterContainer) + { + std::cout << PHWHERE << "Necessary distortion container not on node tree. Bailing." + << std::endl; + + return Fun4AllReturnCodes::ABORTRUN; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int QAG4SimulationDistortions::process_event(PHCompositeNode*) +{ + Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + auto h_beta = dynamic_cast(hm->getHisto(get_histo_prefix() + "betadz")); + assert(h_beta); + + auto h_alpha = dynamic_cast(hm->getHisto(get_histo_prefix() + "alphardphi")); + assert(h_alpha); + + auto h_rphiResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "rphiResid")); + assert(h_rphiResid); + + auto h_zResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResid")); + assert(h_zResid); + + auto h_etaResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResid")); + assert(h_etaResid); + + auto h_etaResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResidLayer")); + assert(h_etaResidLayer); + + auto h_zResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResidLayer")); + assert(h_zResidLayer); + + auto h_deltarphi_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltarphi_layer")); + assert(h_deltarphi_layer); + + auto h_deltaz_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltaz_layer")); + assert(h_deltaz_layer); + + auto h_statez_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "statez_pulls")); + assert(h_statez_pulls); + + auto h_staterphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "staterphi_pulls")); + assert(h_staterphi_pulls); + + auto h_clusz_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusz_pulls")); + assert(h_clusz_pulls); + + auto h_clusrphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusrphi_pulls")); + assert(h_clusrphi_pulls); + + ActsTransformations transformer; + + for(const auto& [key, track] : *m_trackMap) + { + auto tpcSeed = track->get_tpc_seed(); + auto siliconSeed = track->get_silicon_seed(); + + /// Should have never been added to the map... + if(not tpcSeed or not siliconSeed) + { + continue; + } + + for(auto iter = track->begin_states(); iter!= track->end_states(); ++iter) + { + + auto state = iter->second; + TrkrDefs::cluskey key = std::stoi(state->get_name()); + auto cluster = m_clusterContainer->findCluster(key); + const auto clusGlobPosition = m_tGeometry->getGlobalPosition(key, cluster); + + const float clusR = get_r(clusGlobPosition(0), clusGlobPosition(1)); + const float clusPhi = std::atan2(clusGlobPosition(1), clusGlobPosition(0)); + const float clusZ = clusGlobPosition(2); + + // cluster errors + const float clusRPhiErr = cluster->getRPhiError(); + const float clusZErr = cluster->getZError(); + + const Acts::Vector3 stateGlobPosition = Acts::Vector3(state->get_x(), + state->get_y(), + state->get_z()); + const Acts::Vector3 stateGlobMom = Acts::Vector3(state->get_px(), + state->get_py(), + state->get_pz()); + const Acts::BoundSymMatrix statecov = + transformer.rotateSvtxTrackCovToActs(state); + + const float stateRPhiErr = std::sqrt(statecov(Acts::eBoundLoc0, Acts::eBoundLoc0))/Acts::UnitConstants::cm; + const float stateZErr = sqrt(statecov(Acts::eBoundLoc1, Acts::eBoundLoc1))/Acts::UnitConstants::cm; + + const float stateR = get_r(stateGlobPosition(0), stateGlobPosition(1)); + + const auto dr = clusR - stateR; + const auto trackDrDt = (stateGlobPosition(0) * stateGlobMom(0) + stateGlobPosition(1) * stateGlobMom(1)) / stateR; + const auto trackDxDr = stateGlobMom(0) / trackDrDt; + const auto trackDyDr = stateGlobMom(1) / trackDrDt; + const auto trackDzDr = stateGlobMom(2) / trackDrDt; + + const auto trackX = stateGlobPosition(0) + dr * trackDxDr; + const auto trackY = stateGlobPosition(1) + dr * trackDyDr; + const auto trackZ = stateGlobPosition(2) + dr * trackDzDr; + const float statePhi = std::atan2(trackY, trackX); + const float stateZ = trackZ; + + // Calculate residuals + const float drphi = clusR * deltaPhi(clusPhi - statePhi); + const float dz = clusZ - stateZ; + + const auto trackPPhi = -stateGlobMom(0) * std::sin(statePhi) + stateGlobMom(1) * std::cos(statePhi); + const auto trackPR = stateGlobMom(0) * std::cos(statePhi) + stateGlobMom(1) * std::sin(statePhi); + const auto trackPZ = stateGlobMom(2); + + const auto trackAlpha = -trackPPhi / trackPR; + const auto trackBeta = -trackPZ / trackPR; + const auto trackEta = std::atanh(stateGlobMom(2) / stateGlobMom.norm()); + const auto clusEta = std::atanh(clusZ / clusGlobPosition.norm()); + + + h_alpha->Fill(trackAlpha, drphi); + h_beta->Fill(trackBeta, dz); + h_rphiResid->Fill(clusR , drphi); + h_zResid->Fill(stateZ , dz); + h_etaResid->Fill(trackEta, clusEta - trackEta); + h_zResidLayer->Fill(clusR , dz); + h_etaResidLayer->Fill(clusR , clusEta - trackEta); + + const auto layer = TrkrDefs::getLayer(key); + h_deltarphi_layer->Fill( layer, drphi ); + h_deltaz_layer->Fill( layer, dz ); + + h_statez_pulls->Fill(layer, dz/stateZErr); + h_staterphi_pulls->Fill(layer, drphi/stateRPhiErr); + h_clusz_pulls->Fill(layer, dz/clusZErr); + h_clusrphi_pulls->Fill(layer, drphi/clusRPhiErr); + } + + } + return Fun4AllReturnCodes::EVENT_OK; +} + +std::vector QAG4SimulationDistortions::get_cluster_keys( SvtxTrack* track ) + { + std::vector out; + for( const auto& seed: { track->get_silicon_seed(), track->get_tpc_seed() } ) + { + if( seed ) + { std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter( out ) ); } + } + return out; + } + +//____________________________________________________________________________.. +int QAG4SimulationDistortions::End(PHCompositeNode*) +{ + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/QA/modules/QAG4SimulationDistortions.h b/offline/QA/modules/QAG4SimulationDistortions.h new file mode 100644 index 0000000000..6e14ed5b28 --- /dev/null +++ b/offline/QA/modules/QAG4SimulationDistortions.h @@ -0,0 +1,44 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef QAG4SIMULATIONDISTORTIONS_H +#define QAG4SIMULATIONDISTORTIONS_H + +#include +#include + +#include +#include +class PHCompositeNode; +class SvtxTrackMap; +class TrkrClusterContainer; +class SvtxTrack; +class ActsGeometry; + +class QAG4SimulationDistortions : public SubsysReco +{ + public: + + QAG4SimulationDistortions(const std::string &name = "QAG4SimulationDistortions"); + + ~QAG4SimulationDistortions() override; + + + int Init(PHCompositeNode*) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode*) override; + int End(PHCompositeNode*) override; + + private: + + std::string get_histo_prefix() + { + return std::string("h_") + Name() + std::string("_"); + } + std::vector get_cluster_keys(SvtxTrack* track); + + SvtxTrackMap* m_trackMap = nullptr; + TrkrClusterContainer* m_clusterContainer = nullptr; + ActsGeometry* m_tGeometry = nullptr; +}; + +#endif // QAG4SIMULATIONDISTORTIONS_H diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index f72046c6a1..90f81724ac 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -323,7 +323,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << std::endl; } - addTrackState( track, pathLength, trackStateParams ); + addTrackState( track, key, pathLength, trackStateParams ); // calculate residuals with respect to cluster // Get all the relevant information for residual calculation @@ -578,7 +578,7 @@ std::optional PHTpcResiduals::propagateTra } //_______________________________________________________________________________________________________ -void PHTpcResiduals::addTrackState( SvtxTrack* track, float pathlength, const Acts::BoundTrackParameters& params ) +void PHTpcResiduals::addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, float pathlength, const Acts::BoundTrackParameters& params ) { /* this is essentially a copy of the code from trackbase_historic/ActsTransformations::fillSvtxTrackStates */ @@ -603,6 +603,8 @@ void PHTpcResiduals::addTrackState( SvtxTrack* track, float pathlength, const Ac for (int i = 0; i < 6; ++i) for (int j = 0; j < 6; ++j) { state.set_error(i, j, globalCov(i,j)); } + + state.set_name(std::to_string((TrkrDefs::cluskey) key)); track->insert_state(&state); } diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index b7986a5f69..7acdfb4f00 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -99,7 +99,7 @@ class PHTpcResiduals : public SubsysReco void processTrack(SvtxTrack* track); /// fill track state from bound track parameters - void addTrackState( SvtxTrack* track, float pathlength, const Acts::BoundTrackParameters& params ); + void addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, float pathlength, const Acts::BoundTrackParameters& params ); /** \brief * Propagates the silicon+MM track fit to the surface on which From 2003f2ce4807cdf7bc1657158867f0e6f160feab Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:08:32 -0400 Subject: [PATCH 133/468] Update EpdGeomV1.cc to use TowerInfoDefs --- offline/packages/epd/EpdGeomV1.cc | 231 +++++------------------------- 1 file changed, 33 insertions(+), 198 deletions(-) diff --git a/offline/packages/epd/EpdGeomV1.cc b/offline/packages/epd/EpdGeomV1.cc index 8502d24f49..db59c5aa64 100644 --- a/offline/packages/epd/EpdGeomV1.cc +++ b/offline/packages/epd/EpdGeomV1.cc @@ -1,5 +1,9 @@ #include "EpdGeomV1.h" +#include + +#include + #include #include #include @@ -7,217 +11,48 @@ #include #include -// Initializes the EPD Geometry -EpdGeomV1::EpdGeomV1() { - build_lookup(); -} - -// Cleanup -EpdGeomV1::~EpdGeomV1() {}; - - -// Calculates the appropriate tower id from a given side/r/phi index -unsigned int EpdGeomV1::side_r_phi_to_id(unsigned int side, unsigned int r_index, unsigned int phi_index) { - unsigned int id = 0x0; - id = id | (side << 20); - id = id | (r_index << 10); - id = id | phi_index; - return id; -}; - -// Calculates the appropriate tower id from a given side/sector/tile index -unsigned int EpdGeomV1::side_sector_tile_to_id(unsigned int side, unsigned int sector, unsigned int tile) { - int rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; - int phimap[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; - unsigned int phi = phimap[tile] + (sector * 2); - return side_r_phi_to_id(side, rmap[tile], phi); -} - -// Calculates the appropriate side/r/phi index from a tower ID -std::tuple EpdGeomV1::id_to_side_r_phi(unsigned int id) { - unsigned int side, r_index, phi_index; - side = (id >> 20) & 0x1; - r_index = (id >> 10) & 0x3ff; - phi_index = id & 0x3ff; - return std::tuple(side, r_index, phi_index); -}; - -// Calculates the appropriate side/sector/tile from a tower ID -std::tuple EpdGeomV1::id_to_side_sector_tile(unsigned int id) { - unsigned int side, r_index, phi_index; - std::tie(side, r_index, phi_index) = id_to_side_r_phi(id); - unsigned int sector = phi_index / 2; - unsigned int tile = r_index * 2; - if (r_index && (phi_index % 2 == 0)) { - tile --; - } - return std::tuple(side, sector, tile); -} - -float EpdGeomV1::r(unsigned int id) { - return r_lookup[id]; -} - -// Returns the r location of the specified tile. -// Arguments: -// int id: The tile's ID -// Returns: -// float: the tile's location in r/phi space -float EpdGeomV1::r_from_key(unsigned int key) { - return r(decode_epd(key)); -}; - -// Returns the r location of the specified tile. -// Arguments: -// int r_index: The r index of the desired tile -// int phi_index: The phi index of the desired tile -// Returns: -// float: the tile's location in r/phi space -float EpdGeomV1::r_from_side_r_phi(unsigned int side, unsigned int r_index, unsigned int phi_index) { - unsigned int key; - key = side_r_phi_to_id(side, r_index, phi_index); - return r_from_key(key); -}; - -float EpdGeomV1::r_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) { - unsigned int key = side_sector_tile_to_id(side, sector, tile); - return r_from_key(key); +float EpdGeomV1::get_r(unsigned int key) const +{ + return tile_r[TowerInfoDefs::get_epd_rbin(key)]; } -float EpdGeomV1::phi(unsigned int id) { - return phi_lookup[id]; +float EpdGeomV1::get_z(unsigned int key) const +{ + return tile_z[TowerInfoDefs::get_epd_arm(key)]; } -// Returns the phi location of the specified tile. -// Arguments: -// int id: The tile's ID -// Returns: -// float: the tile's location in r/phi space -float EpdGeomV1::phi_from_key(unsigned int key) { - return phi(decode_epd(key)); -}; - -// Returns the phi location of the specified tile. -// Arguments: -// int r_index: The r index of the desired tile -// int phi_index: The phi index of the desired tile -// Returns: -// float: the tile's location in r/phi space -float EpdGeomV1::phi_from_side_r_phi(unsigned int side, unsigned int r_index, unsigned int phi_index) { - unsigned int key; - key = side_r_phi_to_id(side, r_index, phi_index); - return phi_from_key(key); -}; - -float EpdGeomV1::phi_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) { - unsigned int key = side_sector_tile_to_id(side, sector, tile); - return phi_from_key(key); -} +float EpdGeomV1::get_phi(unsigned int key) const +{ -float EpdGeomV1::z(unsigned int id) { - return z_lookup[id]; -} + if(TowerInfoDefs::get_epd_rbin(key) == 0) + { + return tile_phi0[TowerInfoDefs::get_epd_phibin(key)]; + } + else + { + return tile_phi[TowerInfoDefs::get_epd_phibin(key)]; + } -float EpdGeomV1::z_from_key(unsigned int key) { - return z(decode_epd(key)); } - -float EpdGeomV1::z_from_side_r_phi(unsigned int side, unsigned int r_index, unsigned int phi_index) { - unsigned int key = side_r_phi_to_id(side, r_index, phi_index); - return z_from_key(key); + +void EpdGeomV1::set_z(unsigned int key, float z) +{ + tile_z[TowerInfoDefs::get_epd_arm(key)] = z; } -float EpdGeomV1::z_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) { - unsigned int key = side_sector_tile_to_id(side, sector, tile); - return z_from_key(key); +void EpdGeomV1::set_r(unsigned int key, float r) +{ + tile_r[TowerInfoDefs::get_epd_rbin(key)] = r; } -unsigned int EpdGeomV1::decode_epd(unsigned int tower_key) { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int ns_sector = tower_key >> 20U; - unsigned int rbin = (tower_key - (ns_sector << 20U)) >> 10U; - unsigned int phibin = tower_key - (ns_sector << 20U) - (rbin << 10U); - int epdchnlmap[16][2] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24}, {25, 26}, {27, 28}, {29, 30}}; - int sector = phibin / 2; - int channel = 0; - if (rbin > 0) - { - channel = epdchnlmap[rbin][phibin - 2 * sector]; - } - else - { - channel = 0; - } - unsigned int index = 0; - index = ns_sector * supersector + sector * channels_per_sector + channel; - return index; +void EpdGeomV1::set_phi(unsigned int key, float f) +{ + tile_phi[TowerInfoDefs::get_epd_phibin(key)] = f; } - -// Generates the maps returning the r and phi for a particular tile -void EpdGeomV1::build_lookup() { - r_lookup = std::vector(NUM_TOWERS, -999); - phi_lookup = std::vector(NUM_TOWERS, -999); - z_lookup = std::vector(NUM_TOWERS, -999); - std::string epd_geom_file_path("epd_geometry.tsv"); - std::ifstream epd_geom_file(epd_geom_file_path); - if (!epd_geom_file.is_open()) { - std::cerr << "Could not read EPD Geometry file: " << epd_geom_file_path << std::endl; - return; // Should this throw an error? Not sure what the sPHENIX way to do things like that is - } - std::string line; - uint filled = 0; - while(std::getline(epd_geom_file, line)) { - std::stringstream tokens(line); - int tower; - tokens >> tower; // Read the first column into the tower name; - float r, phi, z; - tokens >> r; - tokens >> phi; - tokens >> z; // This could all use error checking - r_lookup[tower] = r; - phi_lookup[tower] = phi; - z_lookup[tower] = z; - filled++; - } - if (filled != NUM_TOWERS) { - std::cerr << "Did not find geometry values for all EPD towers!" << std::endl; - } - // for (uint i = 0; i < NUM_TOWERS; i++) { - // printf("%d\t%f\t%f\t%f\n", i, r_lookup[i], phi_lookup[i], z_lookup[i]); - // } +void EpdGeomV1::set_phi0(unsigned int key, float f0) +{ + tile_phi0[TowerInfoDefs::get_epd_phibin(key)] = f0; } -bool EpdGeomV1::test_id_mapping() { - bool pass = true; - for (unsigned int side = 0; side < 2; side++) { - for (unsigned int r_index = 0; r_index < 16; r_index++) { - for (unsigned int phi_index = 0; phi_index < 24; phi_index++) { - if (r_index == 0 && (phi_index & 0x1)) { - continue; - } - std::cout << "side: " << side << "\tr: " << r_index << "\tphi: " << phi_index << std::endl; - unsigned int id_from_r_phi = side_r_phi_to_id(side, r_index, phi_index); // side r phi to id - std::cout << "id 1: " << id_from_r_phi << std::endl; - unsigned int temp_side, sector, tile; - std::tie(temp_side, sector, tile) = id_to_side_sector_tile(id_from_r_phi); // id to side sector tile - std::cout << "side: " << side << "\tsector: " << sector << "\ttile: " << tile << std::endl; - unsigned int id_from_sector_tile = side_sector_tile_to_id(temp_side, sector, tile); // side sector tile to id - std::cout << "id 2: " << id_from_sector_tile << std::endl; - unsigned int final_side, final_r_index, final_phi_index; - std::tie(final_side, final_r_index, final_phi_index) = id_to_side_r_phi(id_from_sector_tile); /// id to side r phi - std::cout << "side: " << final_side << "\tr: " << final_r_index << "\tphi: " << final_phi_index << std::endl; - if (side != final_side || r_index != final_r_index || phi_index != final_phi_index) { - pass = false; - std::cout << "COORDINATE FAILED" << std::endl; - } else{ - std::cout << "coordinate passed" << std::endl; - } - std::cout << "\n\n" << std::endl; - } - } - } - return pass; -} From ba32120f41b51b54039a62b82b898863155f0027 Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:10:01 -0400 Subject: [PATCH 134/468] Update EpdGeomV1.h to use TowerInfoDefs --- offline/packages/epd/EpdGeomV1.h | 83 ++++++-------------------------- 1 file changed, 14 insertions(+), 69 deletions(-) diff --git a/offline/packages/epd/EpdGeomV1.h b/offline/packages/epd/EpdGeomV1.h index 4f7403fb32..62c1f733bc 100644 --- a/offline/packages/epd/EpdGeomV1.h +++ b/offline/packages/epd/EpdGeomV1.h @@ -1,92 +1,37 @@ -/* -sEPD Geometry class - -Tristan Protzman -tlprotzman@gmail.com -December 15, 2022 - -Converts from r/phi index to location in r/phi space - -Key format: -100000000000000000000_2 -211111111110000000000 -098765432109876543210 -*/ - #ifndef EPD_GEOM_V1_H #define EPD_GEOM_V1_H #include "EpdGeom.h" -#include "EpdGeomV1.h" -#include #include #include #include -#include - -// sEPD geometry class class EpdGeomV1 : public EpdGeom { public: - EpdGeomV1(); - ~EpdGeomV1() override; - - unsigned int side_r_phi_to_id(unsigned int side, unsigned int r_index, unsigned int phi_index) override; - unsigned int side_sector_tile_to_id(unsigned int side, unsigned int sector, unsigned int tile) override; - std::tuple id_to_side_r_phi(unsigned int id) override; - std::tuple id_to_side_sector_tile(unsigned int id) override; - float r(unsigned int id) override; - float r_from_key(unsigned int key) override; - float r_from_side_r_phi(unsigned int side, unsigned int r_index, unsigned int phi_index) override; - float r_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) override; - float phi(unsigned int id) override; - float phi_from_key(unsigned int key) override; - float phi_from_side_r_phi(unsigned int side, unsigned int r_index, unsigned int phi_index) override; - float phi_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) override; - float z(unsigned int id) override; - float z_from_key(unsigned int key) override; - float z_from_side_r_phi(unsigned int side, unsigned int r_inxed, unsigned int phi_index) override; - float z_from_side_sector_tile(unsigned int side, unsigned int sector, unsigned int tile) override; - unsigned int decode_epd(unsigned int tower_key) override; - + EpdGeomV1() = default; + ~EpdGeomV1() override = default; + float get_r(unsigned int key) const override; + float get_z(unsigned int key) const override; + float get_phi(unsigned int key) const override; + void set_z(unsigned int key, float z) override; + void set_r(unsigned int key, float r) override; + void set_phi(unsigned int key, float f) override; + void set_phi0(unsigned int key, float f0) override; - void Reset() override {return;}; // Reset doesn't need to do anything private: - const unsigned int NUM_TOWERS = 744; - const unsigned int MAX_R = 16; - const unsigned int MAX_PHI = 24; - const unsigned int NUM_SECTORS = 12; - const unsigned int NUM_TILES = 31; - - std::vector r_lookup; - std::vector phi_lookup; - std::vector z_lookup; - bool test_id_mapping(); - - // const float NAIVE_R_INDEX[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; - const float NAIVE_R_LOC[16] = {6.8, 11.2, 15.6, 20.565, 26.095, 31.625, 37.155, 42.685, 48.215, 53.745, 59.275, 64.805, 70.335, 75.865, 81.395, 86.925}; - const float NAIVE_PHI_LOC_RING_0[12] = {0.26179939, 0.78539816, 1.30899694, 1.83259571, 2.35619449, - 2.87979327, 3.40339204, 3.92699082, 4.45058959, 4.97418837, - 5.49778714, 6.02138592}; + float tile_r[16] = {}; + float tile_z[2] = {}; + float tile_phi[24] = {}; + float tile_phi0[12] = {}; - const float NAIVE_PHI_LOC[24] = {0.13089969, 0.39269908, 0.65449847, 0.91629786, 1.17809725, - 1.43989663, 1.70169602, 1.96349541, 2.2252948 , 2.48709418, - 2.74889357, 3.01069296, 3.27249235, 3.53429174, 3.79609112, - 4.05789051, 4.3196899 , 4.58148929, 4.84328867, 5.10508806, - 5.36688745, 5.62868684, 5.89048623, 6.15228561}; - - const float NAIVE_Z_MAP[2] = {-316, 316}; - - void build_lookup(); - ClassDefOverride(EpdGeomV1, 1) }; -#endif // EPD_GEOM_V1_H \ No newline at end of file +#endif // EPD_GEOM_V1_H From 97c9e79163a12c6b2358b4bf62f33ac4cd638ebe Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 13:10:11 -0400 Subject: [PATCH 135/468] updated epdmodulereco to use the new key encoding as implemented in TowerInfoDefs --- simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc index 2fd9ab5a3f..9b77581756 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc @@ -1,6 +1,7 @@ #include "PHG4EPDModuleReco.h" +#include #include #include #include @@ -123,13 +124,14 @@ int PHG4EPDModuleReco::process_event(PHCompositeNode *topNode) { unsigned int globalphi = Getphimap(j) + 2 * i; unsigned int r = Getrmap(j); + if (r == 0) + { + globalphi = i; + } - unsigned int key = globalphi + (r << 10U) + (k << 20U); - + unsigned int key = TowerInfoDefs::encode_epd(k,r,globalphi); unsigned int ch = m_TowerInfoContainer->decode_key(key); - m_TowerInfoContainer->get_tower_at_channel(ch)->set_energy(m_EpdTile_e[k][i][j]); - m_TowerInfoContainer_calib->get_tower_at_channel(ch)->set_energy(m_EpdTile_Calib_e[k][i][j]); } } From 4ace577a4fde408513593fc3ff68ecc02b19cee3 Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:11:14 -0400 Subject: [PATCH 136/468] Update EpdGeom.h to use TowerInfoDefs --- offline/packages/epd/EpdGeom.h | 38 ++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/offline/packages/epd/EpdGeom.h b/offline/packages/epd/EpdGeom.h index 4b829ec48d..fb15ae81b2 100644 --- a/offline/packages/epd/EpdGeom.h +++ b/offline/packages/epd/EpdGeom.h @@ -1,12 +1,18 @@ +/* + Originated by Tristan Protzman 12/15/22 + Re-written by Ejiro Umaka 03/28/23 +*/ + #ifndef EPD_GEOM_H #define EPD_GEOM_H +#include + #include #include #include #include - -#include +#include class EpdGeom : public PHObject { @@ -14,29 +20,17 @@ class EpdGeom : public PHObject EpdGeom() = default; ~EpdGeom() override {}; - virtual unsigned int side_r_phi_to_id(unsigned int /*side*/, unsigned int /*r_index*/, unsigned int /*phi_index*/) {return 999;}; - virtual unsigned int side_sector_tile_to_id(unsigned int /*side*/, unsigned int /*sector*/, unsigned int /*tile*/) {return 999;}; - virtual std::tuple id_to_side_r_phi(unsigned int /*id*/) {return {0, 0, 0};}; - virtual std::tuple id_to_side_sector_tile(unsigned int /*id*/) {return {0, 0, 0};}; - virtual float r(unsigned int /*id*/) {return -999;}; - virtual float r_from_key(unsigned int /*key*/) {return -999;}; - virtual float r_from_side_r_phi(unsigned int /*side*/, unsigned int /*r_index*/, unsigned int /*phi_index*/) {return -999;}; - virtual float r_from_side_sector_tile(unsigned int /*side*/, unsigned int /*sector*/, unsigned int /*tile*/) {return -999;}; - virtual float phi(unsigned int /*id*/) {return -999;}; - virtual float phi_from_key(unsigned int /*key*/) {return -999;}; - virtual float phi_from_side_r_phi(unsigned int /*side*/, unsigned int /*r_index*/, unsigned int /*phi_index*/) {return -999;}; - virtual float phi_from_side_sector_tile(unsigned int /*side*/, unsigned int /*sector*/, unsigned int /*tile*/) {return -999;}; - virtual float z(unsigned int /*id*/) {return -999;}; - virtual float z_from_key(unsigned int /*key*/) {return -999;}; - virtual float z_from_side_r_phi(unsigned int /*side*/, unsigned int /*r_inxed*/, unsigned int /*phi_index*/) {return -999;}; - virtual float z_from_side_sector_tile(unsigned int /*side*/, unsigned int /*sector*/, unsigned int /*tile*/) {return -999;}; - virtual unsigned int decode_epd(unsigned int /*tower_key*/) {return 999;}; - - virtual void Reset() override {return;}; // Reset doesn't need to do anything + virtual void set_z(unsigned int /*key*/, float /*z*/) {return;} + virtual void set_r(unsigned int /*key*/, float /*r*/) {return;} + virtual void set_phi(unsigned int /*key*/, float /*f*/) {return;} + virtual void set_phi0(unsigned int /*key*/, float /*f*/) {return;} + virtual float get_r(unsigned int /*key*/) const {return NAN;}; + virtual float get_z(unsigned int /*key*/) const {return NAN;}; + virtual float get_phi(unsigned int /*key*/) const {return NAN;}; private: ClassDefOverride(EpdGeom, 1); }; -#endif // EPD_GEOM_H \ No newline at end of file +#endif // EPD_GEOM_H From c65f9dacc75f8e18d21ea8f4141615310220e229 Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:14:30 -0400 Subject: [PATCH 137/468] Update PHG4EPDModuleReco.cc to fill in sEPD geom --- .../g4simulation/g4epd/PHG4EPDModuleReco.cc | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc index 2fd9ab5a3f..45abd2f18b 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc @@ -1,10 +1,11 @@ - #include "PHG4EPDModuleReco.h" #include #include #include +#include + #include #include @@ -62,6 +63,24 @@ int PHG4EPDModuleReco::InitRun(PHCompositeNode *topNode) PHIODataNode *newNode = new PHIODataNode(epdGeom, "TOWERGEOM_EPD", "PHObject"); runNode->addNode(newNode); } + + //fill epd geometry + unsigned int epdchannels = 744; + for (unsigned int ch = 0; ch < epdchannels; ch++) + { + unsigned int thiskey = TowerInfoDefs::encode_epd(ch); + epdGeom->set_z(thiskey, GetTileZ(TowerInfoDefs::get_epd_arm(thiskey))); + epdGeom->set_r(thiskey, GetTileR(TowerInfoDefs::get_epd_rbin(thiskey))); + if(TowerInfoDefs::get_epd_rbin(thiskey) == 0) + { + epdGeom->set_phi0(thiskey, GetTilePhi0(TowerInfoDefs::get_epd_phibin(thiskey))); + } + else + { + epdGeom->set_phi(thiskey, GetTilePhi(TowerInfoDefs::get_epd_phibin(thiskey))); + } + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -155,18 +174,42 @@ void PHG4EPDModuleReco::set_timing_window(const double tmi, const double tma) int PHG4EPDModuleReco::Getrmap(int rindex) { - int rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; + static const int rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; return rmap[rindex]; } int PHG4EPDModuleReco::Getphimap(int phiindex) { - int phimap[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + static const int phimap[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; return phimap[phiindex]; } +float PHG4EPDModuleReco::GetTilePhi(int thisphi) +{ + static const float tilephi[24] = {0.13089969, 0.39269908, 0.65449847, 0.91629786, 1.17809725,1.43989663, 1.70169602, 1.96349541, 2.2252948 , 2.48709418, 2.74889357, 3.01069296, 3.27249235, 3.53429174, 3.79609112, 4.05789051, 4.3196899 , 4.58148929, 4.84328867, 5.10508806, 5.36688745, 5.62868684, 5.89048623, 6.15228561}; + return tilephi[thisphi]; +} + +float PHG4EPDModuleReco::GetTilePhi0(int thisphi0) +{ + static const float tilephi0[12] = {0.26179939, 0.78539816, 1.30899694, 1.83259571, 2.35619449, 2.87979327, 3.40339204, 3.92699082, 4.45058959, 4.97418837, 5.49778714, 6.02138592}; + return tilephi0[thisphi0]; +} + +float PHG4EPDModuleReco::GetTileR(int thisr) +{ + static const float tileR[16] = {6.8, 11.2, 15.6, 20.565, 26.095, 31.625, 37.155, 42.685, 48.215, 53.745, 59.275, 64.805, 70.335, 75.865, 81.395, 86.925}; + return tileR[thisr]; +} + +float PHG4EPDModuleReco::GetTileZ(int thisz) +{ + static const float tileZ[2] = {-316.0, 316.0}; + return tileZ[thisz]; +} + void PHG4EPDModuleReco::CreateNodes(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); From 36fec4a455f64929d28a3dfd464c3ad7ac7c5ee9 Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:15:39 -0400 Subject: [PATCH 138/468] Update PHG4EPDModuleReco.h for sEPD geom --- simulation/g4simulation/g4epd/PHG4EPDModuleReco.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.h b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.h index aa0fd6f2aa..ac3f9cc4b0 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.h +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.h @@ -62,6 +62,10 @@ class PHG4EPDModuleReco : public SubsysReco, public PHParameterInterface private: int Getrmap(int rindex); int Getphimap(int phiindex); + float GetTilePhi(int thisphi); + float GetTilePhi0(int thisphi0); + float GetTileR(int thisr); + float GetTileZ(int thisz); void CreateNodes(PHCompositeNode *topNode); std::string m_Detector; From b53a98e2ca6d1005ddeffc7350d3908d2ed15ade Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:18:29 -0400 Subject: [PATCH 139/468] Update Makefile.am --- offline/packages/epd/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/epd/Makefile.am b/offline/packages/epd/Makefile.am index 9dce4ebb5f..8dfd0037f0 100644 --- a/offline/packages/epd/Makefile.am +++ b/offline/packages/epd/Makefile.am @@ -20,7 +20,8 @@ AM_LDFLAGS = \ -L$(ROOTSYS)/lib libepd_io_la_LIBADD = \ - -lphool + -lphool \ + -lcalo_io libepd_la_LIBADD = \ libepd_io.la \ From 4c62ab2c6cbca3208dc164a8f5ce8707746e6171 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 13:19:02 -0400 Subject: [PATCH 140/468] fixed a cppcheck error with h_template --- offline/packages/CaloReco/CaloWaveformFitting.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 27ca2c194d..6b9bae72b8 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -37,7 +37,7 @@ class CaloWaveformFitting private: void FastMax(float x0, float x1, float x2, float y0, float y1, float y2, float &xmax, float &ymax); - TProfile *h_template; + TProfile *h_template = nullptr; double template_function(double *x, double *par); int _nthreads = 1; std::string m_template_input_file; From e7bf4850e4d86d8206f0bbf9a8a62e1e11032c7c Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Thu, 6 Apr 2023 13:28:22 -0400 Subject: [PATCH 141/468] minor change --- offline/packages/epd/EpdGeom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/epd/EpdGeom.h b/offline/packages/epd/EpdGeom.h index fb15ae81b2..5564fc3c6e 100644 --- a/offline/packages/epd/EpdGeom.h +++ b/offline/packages/epd/EpdGeom.h @@ -23,7 +23,7 @@ class EpdGeom : public PHObject virtual void set_z(unsigned int /*key*/, float /*z*/) {return;} virtual void set_r(unsigned int /*key*/, float /*r*/) {return;} virtual void set_phi(unsigned int /*key*/, float /*f*/) {return;} - virtual void set_phi0(unsigned int /*key*/, float /*f*/) {return;} + virtual void set_phi0(unsigned int /*key*/, float /*f0*/) {return;} virtual float get_r(unsigned int /*key*/) const {return NAN;}; virtual float get_z(unsigned int /*key*/) const {return NAN;}; virtual float get_phi(unsigned int /*key*/) const {return NAN;}; From 5d4d3b552de91b1d231958a32194bfb617fb5048 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 6 Apr 2023 14:44:40 -0400 Subject: [PATCH 142/468] Removed unused variable and replaced use of local variables with (previously) unused member variables --- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 19 ++++++++----------- .../tpccalib/PHTpcCentralMembraneMatcher.h | 8 ++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 74316d972c..b1c10dd259 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -422,17 +422,14 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) } - double clustRotation_pos[3]; - double clustRotation_neg[3]; - //get global phi rotation for each module - clustRotation_pos[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_pos->ProjectionX("cR1_pos",151,206)); - clustRotation_pos[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_pos->ProjectionX("cR2_pos",206,290)); - clustRotation_pos[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_pos->ProjectionX("cR3_pos",290,499)); + m_clustRotation_pos[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_pos->ProjectionX("cR1_pos",151,206)); + m_clustRotation_pos[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_pos->ProjectionX("cR2_pos",206,290)); + m_clustRotation_pos[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_pos->ProjectionX("cR3_pos",290,499)); - clustRotation_neg[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_neg->ProjectionX("cR1_neg",151,206)); - clustRotation_neg[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_neg->ProjectionX("cR2_neg",206,290)); - clustRotation_neg[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_neg->ProjectionX("cR3_neg",290,499)); + m_clustRotation_neg[0] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR1",151,206),clust_r_phi_neg->ProjectionX("cR1_neg",151,206)); + m_clustRotation_neg[1] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR2",206,290),clust_r_phi_neg->ProjectionX("cR2_neg",206,290)); + m_clustRotation_neg[2] = getPhiRotation_smoothed(hit_r_phi->ProjectionX("hR3",290,499),clust_r_phi_neg->ProjectionX("cR3_neg",290,499)); //get hit and cluster peaks @@ -552,8 +549,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) const double z2 = reco_pos[j].Z(); const double rad2=get_r(reco_pos[j].X(), reco_pos[j].Y()); if(angleR != -1){ - if(z2 > 0) phi2 -= clustRotation_pos[angleR]; - else phi2 -= clustRotation_neg[angleR]; + if(z2 > 0) phi2 -= m_clustRotation_pos[angleR]; + else phi2 -= m_clustRotation_neg[angleR]; } diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index d9fb2e6339..80afe3bae3 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -123,7 +123,7 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@} /// radius cut for matching clusters to pad, for size 2 clusters - double m_rad_cut= 0.5; + // double m_rad_cut= 0.5; /// phi cut for matching clusters to pad /** TODO: this will need to be adjusted to match beam-induced time averaged distortions */ @@ -221,9 +221,9 @@ class PHTpcCentralMembraneMatcher : public SubsysReco bool m_useOnly_nClus2 = false; int m_nMatchIter = 2; - - double clustRotation_pos[3]; - double clustRotation_neg[3]; + + double m_clustRotation_pos[3]; + double m_clustRotation_neg[3]; double getPhiRotation_smoothed( TH1D *hitHist, TH1D *clustHist ); From 6fe639d550813d8fe86b8538b3096bb6cbbf8ac5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 6 Apr 2023 14:59:14 -0400 Subject: [PATCH 143/468] runs and produces correct output --- .../QA/modules/QAG4SimulationDistortions.cc | 108 +++++++++++------- .../QA/modules/QAG4SimulationDistortions.h | 4 +- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- 3 files changed, 71 insertions(+), 43 deletions(-) diff --git a/offline/QA/modules/QAG4SimulationDistortions.cc b/offline/QA/modules/QAG4SimulationDistortions.cc index ac0e6eed87..adcee2d132 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.cc +++ b/offline/QA/modules/QAG4SimulationDistortions.cc @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -50,6 +49,14 @@ namespace else return phi; } + + /// return number of clusters of a given type that belong to a tracks + template + int count_clusters( const std::vector& keys ) + { + return std::count_if( keys.begin(), keys.end(), + []( const TrkrDefs::cluskey& key ) { return TrkrDefs::getTrkrId(key) == type; } ); + } } //____________________________________________________________________________.. @@ -120,7 +127,9 @@ int QAG4SimulationDistortions::InitRun(PHCompositeNode *topNode) m_trackMap = findNode::getClass(topNode,"SvtxSiliconMMTrackMap"); m_clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); - if(not m_trackMap or not m_clusterContainer) + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + + if(not m_trackMap or not m_clusterContainer or not m_tGeometry) { std::cout << PHWHERE << "Necessary distortion container not on node tree. Bailing." << std::endl; @@ -139,50 +148,52 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) auto h_beta = dynamic_cast(hm->getHisto(get_histo_prefix() + "betadz")); assert(h_beta); - + auto h_alpha = dynamic_cast(hm->getHisto(get_histo_prefix() + "alphardphi")); assert(h_alpha); - + auto h_rphiResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "rphiResid")); assert(h_rphiResid); - + auto h_zResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResid")); assert(h_zResid); - + auto h_etaResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResid")); assert(h_etaResid); - + auto h_etaResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResidLayer")); assert(h_etaResidLayer); - + auto h_zResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResidLayer")); assert(h_zResidLayer); - + auto h_deltarphi_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltarphi_layer")); assert(h_deltarphi_layer); - + auto h_deltaz_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltaz_layer")); assert(h_deltaz_layer); - + auto h_statez_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "statez_pulls")); assert(h_statez_pulls); - + auto h_staterphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "staterphi_pulls")); assert(h_staterphi_pulls); - + auto h_clusz_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusz_pulls")); assert(h_clusz_pulls); - + auto h_clusrphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusrphi_pulls")); assert(h_clusrphi_pulls); - - ActsTransformations transformer; + + std::cout << "track map size " << m_trackMap->size() << std::endl; for(const auto& [key, track] : *m_trackMap) { + if(!checkTrack(track)) + { continue; } auto tpcSeed = track->get_tpc_seed(); auto siliconSeed = track->get_silicon_seed(); - + /// Should have never been added to the map... if(not tpcSeed or not siliconSeed) { @@ -191,10 +202,19 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) for(auto iter = track->begin_states(); iter!= track->end_states(); ++iter) { - auto state = iter->second; - TrkrDefs::cluskey key = std::stoi(state->get_name()); + + /// If the state name wasn't set to the ckey, it wasn't analyzed + /// in PHTpcResiduals (i.e. it isn't in the tpc) + if((state->get_name()).find("UNKNOWN") != std::string::npos) + { + continue; + } + + TrkrDefs::cluskey key = std::stoll(state->get_name()); + auto cluster = m_clusterContainer->findCluster(key); + const auto clusGlobPosition = m_tGeometry->getGlobalPosition(key, cluster); const float clusR = get_r(clusGlobPosition(0), clusGlobPosition(1)); @@ -204,21 +224,19 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) // cluster errors const float clusRPhiErr = cluster->getRPhiError(); const float clusZErr = cluster->getZError(); - + const Acts::Vector3 stateGlobPosition = Acts::Vector3(state->get_x(), state->get_y(), state->get_z()); const Acts::Vector3 stateGlobMom = Acts::Vector3(state->get_px(), state->get_py(), state->get_pz()); - const Acts::BoundSymMatrix statecov = - transformer.rotateSvtxTrackCovToActs(state); - - const float stateRPhiErr = std::sqrt(statecov(Acts::eBoundLoc0, Acts::eBoundLoc0))/Acts::UnitConstants::cm; - const float stateZErr = sqrt(statecov(Acts::eBoundLoc1, Acts::eBoundLoc1))/Acts::UnitConstants::cm; + + const float stateRPhiErr = state->get_rphi_error(); + const float stateZErr = state->get_z_error(); const float stateR = get_r(stateGlobPosition(0), stateGlobPosition(1)); - + const auto dr = clusR - stateR; const auto trackDrDt = (stateGlobPosition(0) * stateGlobMom(0) + stateGlobPosition(1) * stateGlobMom(1)) / stateR; const auto trackDxDr = stateGlobMom(0) / trackDrDt; @@ -238,13 +256,12 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) const auto trackPPhi = -stateGlobMom(0) * std::sin(statePhi) + stateGlobMom(1) * std::cos(statePhi); const auto trackPR = stateGlobMom(0) * std::cos(statePhi) + stateGlobMom(1) * std::sin(statePhi); const auto trackPZ = stateGlobMom(2); - + const auto trackAlpha = -trackPPhi / trackPR; const auto trackBeta = -trackPZ / trackPR; const auto trackEta = std::atanh(stateGlobMom(2) / stateGlobMom.norm()); const auto clusEta = std::atanh(clusZ / clusGlobPosition.norm()); - - + h_alpha->Fill(trackAlpha, drphi); h_beta->Fill(trackBeta, dz); h_rphiResid->Fill(clusR , drphi); @@ -267,19 +284,30 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) return Fun4AllReturnCodes::EVENT_OK; } +bool QAG4SimulationDistortions::checkTrack(SvtxTrack* track) +{ + if(track->get_pt() < 0.5) + { return false; } + + // ignore tracks with too few mvtx, intt and micromegas hits + const auto cluster_keys( get_cluster_keys( track ) ); + if( count_clusters(cluster_keys) < 2 ) return false; + if( count_clusters(cluster_keys) < 2 ) return false; + if( count_clusters(cluster_keys) < 2 ) { return false; } + + + return true; + +} + std::vector QAG4SimulationDistortions::get_cluster_keys( SvtxTrack* track ) - { - std::vector out; - for( const auto& seed: { track->get_silicon_seed(), track->get_tpc_seed() } ) +{ + std::vector out; + for( const auto& seed: { track->get_silicon_seed(), track->get_tpc_seed() } ) { if( seed ) - { std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter( out ) ); } + { std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter( out ) ); } } - return out; - } - -//____________________________________________________________________________.. -int QAG4SimulationDistortions::End(PHCompositeNode*) -{ - return Fun4AllReturnCodes::EVENT_OK; + return out; } + diff --git a/offline/QA/modules/QAG4SimulationDistortions.h b/offline/QA/modules/QAG4SimulationDistortions.h index 6e14ed5b28..c01dd254fb 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.h +++ b/offline/QA/modules/QAG4SimulationDistortions.h @@ -26,7 +26,6 @@ class QAG4SimulationDistortions : public SubsysReco int Init(PHCompositeNode*) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode*) override; - int End(PHCompositeNode*) override; private: @@ -34,8 +33,9 @@ class QAG4SimulationDistortions : public SubsysReco { return std::string("h_") + Name() + std::string("_"); } + std::vector get_cluster_keys(SvtxTrack* track); - + bool checkTrack(SvtxTrack* track); SvtxTrackMap* m_trackMap = nullptr; TrkrClusterContainer* m_clusterContainer = nullptr; ActsGeometry* m_tGeometry = nullptr; diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 90f81724ac..0ee0be65aa 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -605,7 +605,7 @@ void PHTpcResiduals::addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, flo { state.set_error(i, j, globalCov(i,j)); } state.set_name(std::to_string((TrkrDefs::cluskey) key)); - + std::cout << "set to " << state.get_name() << std::endl; track->insert_state(&state); } From 480edb7cb2507d16fe0c23e0901a5d0e798013c0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 6 Apr 2023 15:02:53 -0400 Subject: [PATCH 144/468] clang format --- .../QA/modules/QAG4SimulationDistortions.cc | 347 +++++++++--------- .../QA/modules/QAG4SimulationDistortions.h | 17 +- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- 3 files changed, 188 insertions(+), 178 deletions(-) diff --git a/offline/QA/modules/QAG4SimulationDistortions.cc b/offline/QA/modules/QAG4SimulationDistortions.cc index adcee2d132..a57bb43ce8 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.cc +++ b/offline/QA/modules/QAG4SimulationDistortions.cc @@ -2,18 +2,18 @@ #include "QAG4SimulationDistortions.h" #include "QAHistManagerDef.h" -#include #include +#include #include #include #include // for PHWHERE -#include #include +#include #include -#include #include +#include #include #include @@ -31,37 +31,47 @@ #include // for map #include // for pair -namespace +namespace { - + // square - template inline constexpr T square( const T& x ) { return x*x; } + template + inline constexpr T square(const T& x) + { + return x * x; + } // radius - template T get_r( const T& x, const T& y ) { return std::sqrt( square(x) + square(y) ); } + template + T get_r(const T& x, const T& y) + { + return std::sqrt(square(x) + square(y)); + } - template inline constexpr T deltaPhi(const T& phi) + template + inline constexpr T deltaPhi(const T& phi) { - if (phi > M_PI) + if (phi > M_PI) return phi - 2. * M_PI; - else if (phi <= -M_PI) - return phi + 2.* M_PI; - else + else if (phi <= -M_PI) + return phi + 2. * M_PI; + else return phi; } /// return number of clusters of a given type that belong to a tracks - template - int count_clusters( const std::vector& keys ) + template + int count_clusters(const std::vector& keys) { - return std::count_if( keys.begin(), keys.end(), - []( const TrkrDefs::cluskey& key ) { return TrkrDefs::getTrkrId(key) == type; } ); + return std::count_if(keys.begin(), keys.end(), + [](const TrkrDefs::cluskey& key) + { return TrkrDefs::getTrkrId(key) == type; }); } -} +} // namespace //____________________________________________________________________________.. -QAG4SimulationDistortions::QAG4SimulationDistortions(const std::string &name): - SubsysReco(name) +QAG4SimulationDistortions::QAG4SimulationDistortions(const std::string& name) + : SubsysReco(name) { } @@ -73,69 +83,69 @@ QAG4SimulationDistortions::~QAG4SimulationDistortions() //____________________________________________________________________________.. int QAG4SimulationDistortions::Init(PHCompositeNode*) { - Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager(); + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); assert(hm); TH1* h(nullptr); - h = new TH2F(TString(get_histo_prefix()) + "betadz",";tan#beta; #Deltaz [cm]",100,-0.5,0.5,100,-0.5,0.5); - + h = new TH2F(TString(get_histo_prefix()) + "betadz", ";tan#beta; #Deltaz [cm]", 100, -0.5, 0.5, 100, -0.5, 0.5); + hm->registerHisto(h); - - h = new TH2F(TString(get_histo_prefix()) + "alphardphi",";tan#alpha; r#Delta#phi [cm]", 100,-0.5,0.5,100,-0.5,0.5); + + h = new TH2F(TString(get_histo_prefix()) + "alphardphi", ";tan#alpha; r#Delta#phi [cm]", 100, -0.5, 0.5, 100, -0.5, 0.5); hm->registerHisto(h); - + h = new TH2F(TString(get_histo_prefix()) + "rphiResid", ";r [cm]; #Deltar#phi [cm]", 60, 20, 80, 500, -2, 2); hm->registerHisto(h); - + h = new TH2F(TString(get_histo_prefix()) + "zResid", ";z [cm]; #Deltaz [cm]", 200, -100, 100, 1000, -2, 2); hm->registerHisto(h); - - h = new TH2F(TString(get_histo_prefix()) + "etaResid", ";#eta;#Delta#eta", 20, -1, 1, 500, -0.2, 0.2); + + h = new TH2F(TString(get_histo_prefix()) + "etaResid", ";#eta;#Delta#eta", 20, -1, 1, 500, -0.2, 0.2); hm->registerHisto(h); - + h = new TH2F(TString(get_histo_prefix()) + "etaResidLayer", ";r [cm]; #Delta#eta", 60, 20, 80, 500, -0.2, 0.2); hm->registerHisto(h); - + h = new TH2F(TString(get_histo_prefix()) + "zResidLayer", ";r [cm]; #Deltaz [cm]", 60, 20, 80, 1000, -2, 2); hm->registerHisto(h); - - h = new TH2F(TString(get_histo_prefix()) + "deltarphi_layer", ";layer; r.#Delta#phi_{track-cluster} (cm)", 57, 0, 57, 500, -2, 2 ); + + h = new TH2F(TString(get_histo_prefix()) + "deltarphi_layer", ";layer; r.#Delta#phi_{track-cluster} (cm)", 57, 0, 57, 500, -2, 2); hm->registerHisto(h); - - h = new TH2F(TString(get_histo_prefix()) + "deltaz_layer", ";layer; #Deltaz_{track-cluster} (cm)", 57, 0, 57, 100, -2, 2 ); + + h = new TH2F(TString(get_histo_prefix()) + "deltaz_layer", ";layer; #Deltaz_{track-cluster} (cm)", 57, 0, 57, 100, -2, 2); hm->registerHisto(h); - - h = new TH2F(TString(get_histo_prefix()) + "statez_pulls","layer; #Deltaz_{track-cluster}/#sigma_{z}^{state}",57,0,57,100,-5,5); + + h = new TH2F(TString(get_histo_prefix()) + "statez_pulls", "layer; #Deltaz_{track-cluster}/#sigma_{z}^{state}", 57, 0, 57, 100, -5, 5); hm->registerHisto(h); - h = new TH2F(TString(get_histo_prefix()) + "staterphi_pulls","layer; #Deltar#phi_{track-cluster}/#sigma_{rphi}^{state}",57,0,57,100,-5,5); + h = new TH2F(TString(get_histo_prefix()) + "staterphi_pulls", "layer; #Deltar#phi_{track-cluster}/#sigma_{rphi}^{state}", 57, 0, 57, 100, -5, 5); hm->registerHisto(h); - h = new TH2F(TString(get_histo_prefix()) + "clusz_pulls","layer; #Deltaz_{track-cluster}/#sigma_{z}^{clus}",57,0,57,100,-5,5); + h = new TH2F(TString(get_histo_prefix()) + "clusz_pulls", "layer; #Deltaz_{track-cluster}/#sigma_{z}^{clus}", 57, 0, 57, 100, -5, 5); hm->registerHisto(h); - h = new TH2F(TString(get_histo_prefix()) + "clusrphi_pulls","layer; #Deltar#phi_{track-cluster}/#sigma_{r#phi}^{clus}",57,0,57,100,-5,5); + h = new TH2F(TString(get_histo_prefix()) + "clusrphi_pulls", "layer; #Deltar#phi_{track-cluster}/#sigma_{r#phi}^{clus}", 57, 0, 57, 100, -5, 5); hm->registerHisto(h); return Fun4AllReturnCodes::EVENT_OK; } //____________________________________________________________________________.. -int QAG4SimulationDistortions::InitRun(PHCompositeNode *topNode) +int QAG4SimulationDistortions::InitRun(PHCompositeNode* topNode) { - m_trackMap = findNode::getClass(topNode,"SvtxSiliconMMTrackMap"); + m_trackMap = findNode::getClass(topNode, "SvtxSiliconMMTrackMap"); m_clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); - if(not m_trackMap or not m_clusterContainer or not m_tGeometry) - { - std::cout << PHWHERE << "Necessary distortion container not on node tree. Bailing." - << std::endl; + if (not m_trackMap or not m_clusterContainer or not m_tGeometry) + { + std::cout << PHWHERE << "Necessary distortion container not on node tree. Bailing." + << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + return Fun4AllReturnCodes::ABORTRUN; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -143,171 +153,174 @@ int QAG4SimulationDistortions::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int QAG4SimulationDistortions::process_event(PHCompositeNode*) { - Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager(); + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); assert(hm); - + auto h_beta = dynamic_cast(hm->getHisto(get_histo_prefix() + "betadz")); assert(h_beta); - + auto h_alpha = dynamic_cast(hm->getHisto(get_histo_prefix() + "alphardphi")); assert(h_alpha); - + auto h_rphiResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "rphiResid")); assert(h_rphiResid); - + auto h_zResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResid")); assert(h_zResid); - + auto h_etaResid = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResid")); assert(h_etaResid); - + auto h_etaResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "etaResidLayer")); assert(h_etaResidLayer); - + auto h_zResidLayer = dynamic_cast(hm->getHisto(get_histo_prefix() + "zResidLayer")); assert(h_zResidLayer); - + auto h_deltarphi_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltarphi_layer")); assert(h_deltarphi_layer); - + auto h_deltaz_layer = dynamic_cast(hm->getHisto(get_histo_prefix() + "deltaz_layer")); assert(h_deltaz_layer); - + auto h_statez_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "statez_pulls")); assert(h_statez_pulls); - + auto h_staterphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "staterphi_pulls")); assert(h_staterphi_pulls); - + auto h_clusz_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusz_pulls")); assert(h_clusz_pulls); - + auto h_clusrphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusrphi_pulls")); assert(h_clusrphi_pulls); - - std::cout << "track map size " << m_trackMap->size() << std::endl; - for(const auto& [key, track] : *m_trackMap) + for (const auto& [key, track] : *m_trackMap) + { + if (!checkTrack(track)) { - if(!checkTrack(track)) - { continue; } - auto tpcSeed = track->get_tpc_seed(); - auto siliconSeed = track->get_silicon_seed(); - - /// Should have never been added to the map... - if(not tpcSeed or not siliconSeed) - { - continue; - } - - for(auto iter = track->begin_states(); iter!= track->end_states(); ++iter) - { - auto state = iter->second; - - /// If the state name wasn't set to the ckey, it wasn't analyzed - /// in PHTpcResiduals (i.e. it isn't in the tpc) - if((state->get_name()).find("UNKNOWN") != std::string::npos) - { - continue; - } - - TrkrDefs::cluskey key = std::stoll(state->get_name()); - - auto cluster = m_clusterContainer->findCluster(key); - - const auto clusGlobPosition = m_tGeometry->getGlobalPosition(key, cluster); - - const float clusR = get_r(clusGlobPosition(0), clusGlobPosition(1)); - const float clusPhi = std::atan2(clusGlobPosition(1), clusGlobPosition(0)); - const float clusZ = clusGlobPosition(2); - - // cluster errors - const float clusRPhiErr = cluster->getRPhiError(); - const float clusZErr = cluster->getZError(); - - const Acts::Vector3 stateGlobPosition = Acts::Vector3(state->get_x(), - state->get_y(), - state->get_z()); - const Acts::Vector3 stateGlobMom = Acts::Vector3(state->get_px(), - state->get_py(), - state->get_pz()); - - const float stateRPhiErr = state->get_rphi_error(); - const float stateZErr = state->get_z_error(); - - const float stateR = get_r(stateGlobPosition(0), stateGlobPosition(1)); - - const auto dr = clusR - stateR; - const auto trackDrDt = (stateGlobPosition(0) * stateGlobMom(0) + stateGlobPosition(1) * stateGlobMom(1)) / stateR; - const auto trackDxDr = stateGlobMom(0) / trackDrDt; - const auto trackDyDr = stateGlobMom(1) / trackDrDt; - const auto trackDzDr = stateGlobMom(2) / trackDrDt; - - const auto trackX = stateGlobPosition(0) + dr * trackDxDr; - const auto trackY = stateGlobPosition(1) + dr * trackDyDr; - const auto trackZ = stateGlobPosition(2) + dr * trackDzDr; - const float statePhi = std::atan2(trackY, trackX); - const float stateZ = trackZ; - - // Calculate residuals - const float drphi = clusR * deltaPhi(clusPhi - statePhi); - const float dz = clusZ - stateZ; - - const auto trackPPhi = -stateGlobMom(0) * std::sin(statePhi) + stateGlobMom(1) * std::cos(statePhi); - const auto trackPR = stateGlobMom(0) * std::cos(statePhi) + stateGlobMom(1) * std::sin(statePhi); - const auto trackPZ = stateGlobMom(2); - - const auto trackAlpha = -trackPPhi / trackPR; - const auto trackBeta = -trackPZ / trackPR; - const auto trackEta = std::atanh(stateGlobMom(2) / stateGlobMom.norm()); - const auto clusEta = std::atanh(clusZ / clusGlobPosition.norm()); - - h_alpha->Fill(trackAlpha, drphi); - h_beta->Fill(trackBeta, dz); - h_rphiResid->Fill(clusR , drphi); - h_zResid->Fill(stateZ , dz); - h_etaResid->Fill(trackEta, clusEta - trackEta); - h_zResidLayer->Fill(clusR , dz); - h_etaResidLayer->Fill(clusR , clusEta - trackEta); - - const auto layer = TrkrDefs::getLayer(key); - h_deltarphi_layer->Fill( layer, drphi ); - h_deltaz_layer->Fill( layer, dz ); - - h_statez_pulls->Fill(layer, dz/stateZErr); - h_staterphi_pulls->Fill(layer, drphi/stateRPhiErr); - h_clusz_pulls->Fill(layer, dz/clusZErr); - h_clusrphi_pulls->Fill(layer, drphi/clusRPhiErr); - } + continue; + } + auto tpcSeed = track->get_tpc_seed(); + auto siliconSeed = track->get_silicon_seed(); + /// Should have never been added to the map... + if (not tpcSeed or not siliconSeed) + { + continue; } + + for (auto iter = track->begin_states(); iter != track->end_states(); ++iter) + { + auto state = iter->second; + + /// If the state name wasn't set to the ckey, it wasn't analyzed + /// in PHTpcResiduals (i.e. it isn't in the tpc) + if ((state->get_name()).find("UNKNOWN") != std::string::npos) + { + continue; + } + + TrkrDefs::cluskey key = std::stoll(state->get_name()); + + auto cluster = m_clusterContainer->findCluster(key); + + const auto clusGlobPosition = m_tGeometry->getGlobalPosition(key, cluster); + + const float clusR = get_r(clusGlobPosition(0), clusGlobPosition(1)); + const float clusPhi = std::atan2(clusGlobPosition(1), clusGlobPosition(0)); + const float clusZ = clusGlobPosition(2); + + // cluster errors + const float clusRPhiErr = cluster->getRPhiError(); + const float clusZErr = cluster->getZError(); + + const Acts::Vector3 stateGlobPosition = Acts::Vector3(state->get_x(), + state->get_y(), + state->get_z()); + const Acts::Vector3 stateGlobMom = Acts::Vector3(state->get_px(), + state->get_py(), + state->get_pz()); + + const float stateRPhiErr = state->get_rphi_error(); + const float stateZErr = state->get_z_error(); + + const float stateR = get_r(stateGlobPosition(0), stateGlobPosition(1)); + + const auto dr = clusR - stateR; + const auto trackDrDt = (stateGlobPosition(0) * stateGlobMom(0) + stateGlobPosition(1) * stateGlobMom(1)) / stateR; + const auto trackDxDr = stateGlobMom(0) / trackDrDt; + const auto trackDyDr = stateGlobMom(1) / trackDrDt; + const auto trackDzDr = stateGlobMom(2) / trackDrDt; + + const auto trackX = stateGlobPosition(0) + dr * trackDxDr; + const auto trackY = stateGlobPosition(1) + dr * trackDyDr; + const auto trackZ = stateGlobPosition(2) + dr * trackDzDr; + const float statePhi = std::atan2(trackY, trackX); + const float stateZ = trackZ; + + // Calculate residuals + const float drphi = clusR * deltaPhi(clusPhi - statePhi); + const float dz = clusZ - stateZ; + + const auto trackPPhi = -stateGlobMom(0) * std::sin(statePhi) + stateGlobMom(1) * std::cos(statePhi); + const auto trackPR = stateGlobMom(0) * std::cos(statePhi) + stateGlobMom(1) * std::sin(statePhi); + const auto trackPZ = stateGlobMom(2); + + const auto trackAlpha = -trackPPhi / trackPR; + const auto trackBeta = -trackPZ / trackPR; + const auto trackEta = std::atanh(stateGlobMom(2) / stateGlobMom.norm()); + const auto clusEta = std::atanh(clusZ / clusGlobPosition.norm()); + + h_alpha->Fill(trackAlpha, drphi); + h_beta->Fill(trackBeta, dz); + h_rphiResid->Fill(clusR, drphi); + h_zResid->Fill(stateZ, dz); + h_etaResid->Fill(trackEta, clusEta - trackEta); + h_zResidLayer->Fill(clusR, dz); + h_etaResidLayer->Fill(clusR, clusEta - trackEta); + + const auto layer = TrkrDefs::getLayer(key); + h_deltarphi_layer->Fill(layer, drphi); + h_deltaz_layer->Fill(layer, dz); + + h_statez_pulls->Fill(layer, dz / stateZErr); + h_staterphi_pulls->Fill(layer, drphi / stateRPhiErr); + h_clusz_pulls->Fill(layer, dz / clusZErr); + h_clusrphi_pulls->Fill(layer, drphi / clusRPhiErr); + } + } return Fun4AllReturnCodes::EVENT_OK; } bool QAG4SimulationDistortions::checkTrack(SvtxTrack* track) { - if(track->get_pt() < 0.5) - { return false; } + if (track->get_pt() < 0.5) + { + return false; + } // ignore tracks with too few mvtx, intt and micromegas hits - const auto cluster_keys( get_cluster_keys( track ) ); - if( count_clusters(cluster_keys) < 2 ) return false; - if( count_clusters(cluster_keys) < 2 ) return false; - if( count_clusters(cluster_keys) < 2 ) { return false; } - + const auto cluster_keys(get_cluster_keys(track)); + if (count_clusters(cluster_keys) < 2) return false; + if (count_clusters(cluster_keys) < 2) return false; + if (count_clusters(cluster_keys) < 2) + { + return false; + } return true; - } -std::vector QAG4SimulationDistortions::get_cluster_keys( SvtxTrack* track ) +std::vector QAG4SimulationDistortions::get_cluster_keys(SvtxTrack* track) { std::vector out; - for( const auto& seed: { track->get_silicon_seed(), track->get_tpc_seed() } ) + for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (seed) { - if( seed ) - { std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter( out ) ); } + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); } + } return out; } - diff --git a/offline/QA/modules/QAG4SimulationDistortions.h b/offline/QA/modules/QAG4SimulationDistortions.h index c01dd254fb..9ae705bd4a 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.h +++ b/offline/QA/modules/QAG4SimulationDistortions.h @@ -17,23 +17,20 @@ class ActsGeometry; class QAG4SimulationDistortions : public SubsysReco { public: - - QAG4SimulationDistortions(const std::string &name = "QAG4SimulationDistortions"); + QAG4SimulationDistortions(const std::string& name = "QAG4SimulationDistortions"); ~QAG4SimulationDistortions() override; - int Init(PHCompositeNode*) override; - int InitRun(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode*) override; private: - std::string get_histo_prefix() - { - return std::string("h_") + Name() + std::string("_"); - } - + { + return std::string("h_") + Name() + std::string("_"); + } + std::vector get_cluster_keys(SvtxTrack* track); bool checkTrack(SvtxTrack* track); SvtxTrackMap* m_trackMap = nullptr; @@ -41,4 +38,4 @@ class QAG4SimulationDistortions : public SubsysReco ActsGeometry* m_tGeometry = nullptr; }; -#endif // QAG4SIMULATIONDISTORTIONS_H +#endif // QAG4SIMULATIONDISTORTIONS_H diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 0ee0be65aa..90f81724ac 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -605,7 +605,7 @@ void PHTpcResiduals::addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, flo { state.set_error(i, j, globalCov(i,j)); } state.set_name(std::to_string((TrkrDefs::cluskey) key)); - std::cout << "set to " << state.get_name() << std::endl; + track->insert_state(&state); } From b6f699b7b258ebb43a43e233af88ee714b13a949 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 6 Apr 2023 15:59:48 -0400 Subject: [PATCH 145/468] a silly space to trigger a new git thing --- offline/packages/CaloBase/TowerInfoDefs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloBase/TowerInfoDefs.cc b/offline/packages/CaloBase/TowerInfoDefs.cc index e0edc6062c..03f58138ea 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.cc +++ b/offline/packages/CaloBase/TowerInfoDefs.cc @@ -7,7 +7,7 @@ #include #include - + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static const int emcadc[8][8] = { From ae176c372d5d34c92c63016f823a8d545783d4b8 Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Thu, 6 Apr 2023 16:16:09 -0400 Subject: [PATCH 146/468] making it compatible to towerinfo --- .../packages/particleflow/ParticleFlowReco.cc | 339 +++++++++--------- 1 file changed, 162 insertions(+), 177 deletions(-) diff --git a/offline/packages/particleflow/ParticleFlowReco.cc b/offline/packages/particleflow/ParticleFlowReco.cc index 7aeec627a3..e79933f212 100644 --- a/offline/packages/particleflow/ParticleFlowReco.cc +++ b/offline/packages/particleflow/ParticleFlowReco.cc @@ -8,8 +8,6 @@ #include #include -#include -#include #include #include #include @@ -34,10 +32,10 @@ #include // examine second value of std::pair, sort by smallest -bool sort_by_pair_second_lowest( const std::pair &a, const std::pair &b) -{ - return (a.second < b.second); -} +bool sort_by_pair_second_lowest( const std::pair &a, const std::pair &b) +{ + return (a.second < b.second); +} float ParticleFlowReco::calculate_dR( float eta1, float eta2, float phi1, float phi2 ) { @@ -50,7 +48,7 @@ float ParticleFlowReco::calculate_dR( float eta1, float eta2, float phi1, float } std::pair ParticleFlowReco::get_expected_signature( int trk ) { - + float response = ( 0.553437 + 0.0572246 * log( _pflow_TRK_p[ trk ] ) ) * _pflow_TRK_p[ trk ]; float resolution = sqrt( pow( 0.119123 , 2 ) + pow( 0.312361 , 2 ) / _pflow_TRK_p[ trk ] ) * _pflow_TRK_p[ trk ] ; @@ -101,16 +99,6 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // used for indexing PFlow elements in container int global_pflow_index = 0; - - // read in towers - RawTowerContainer *towersEM = findNode::getClass(topNode, "TOWER_CALIB_CEMC"); - RawTowerContainer *towersIH = findNode::getClass(topNode, "TOWER_CALIB_HCALIN"); - RawTowerContainer *towersOH = findNode::getClass(topNode, "TOWER_CALIB_HCALOUT"); - - if ( !towersEM || !towersIH || !towersOH ) { - std::cout << "ParticleFlowReco::process_event : FATAL ERROR, cannot find tower containers" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } // read in tower geometries RawTowerGeomContainer *geomEM = findNode::getClass(topNode, "TOWERGEOM_CEMC"); @@ -122,7 +110,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - // read in clusters + // read in clusters RawClusterContainer *clustersEM = findNode::getClass(topNode, "TOPOCLUSTER_EMCAL"); RawClusterContainer *clustersHAD = findNode::getClass(topNode, "TOPOCLUSTER_HCAL"); @@ -177,13 +165,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } } - if ( Verbosity() > 2 ) + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : initial population of TRK, EM, HAD objects " << std::endl; // read in tracks with > 0.5 GeV { SvtxTrackMap* trackmap = findNode::getClass(topNode, _track_map_name); - + float cemcradius = geomEM->get_radius(); float ohcalradius = geomOH->get_radius(); @@ -200,7 +188,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if(Verbosity() > 2) { std::cout << "Track with p= " << track->get_p() <<", eta / phi = " - << track->get_eta() << " / " << track->get_phi() + << track->get_eta() << " / " << track->get_phi() << std::endl; } @@ -211,7 +199,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_TRK_match_EM.push_back( std::vector() ); _pflow_TRK_match_HAD.push_back( std::vector() ); _pflow_TRK_addtl_match_EM.push_back( std::vector< std::pair >() ); - + SvtxTrackState* cemcstate = track->get_state(cemcradius); SvtxTrackState* ohstate = track->get_state(ohcalradius); /// Get the track projections. If they failed for some reason, just use the track @@ -220,8 +208,8 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) { _pflow_TRK_EMproj_phi.push_back(atan2(cemcstate->get_y(), cemcstate->get_x())); _pflow_TRK_EMproj_eta.push_back(asinh(cemcstate->get_z()/sqrt(cemcstate->get_x()*cemcstate->get_x() + cemcstate->get_y()*cemcstate->get_y()))); - } - else { + } + else { _pflow_TRK_EMproj_phi.push_back(track->get_phi()); _pflow_TRK_EMproj_eta.push_back(track->get_eta()); } @@ -230,15 +218,15 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_TRK_HADproj_phi.push_back(atan2(ohstate->get_py(), ohstate->get_px())); _pflow_TRK_HADproj_eta.push_back(asinh(ohstate->get_pz()/ohstate->get_pt())); } - else { + else { _pflow_TRK_HADproj_phi.push_back(track->get_phi()); _pflow_TRK_HADproj_eta.push_back(track->get_eta()); } } - } // + } // + - // read in EMCal topoClusters with E > 0.2 GeV { @@ -247,12 +235,12 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) { float cluster_E = hiter->second->get_energy(); if ( cluster_E < 0.2 ) continue; - + float cluster_phi = hiter->second->get_phi(); /// default assume at vx_z = 0 float cluster_theta = M_PI / 2.0 - atan2( hiter->second->get_z() , hiter->second->get_r() ); float cluster_eta = -1 * log( tan( cluster_theta / 2.0 ) ); - + if(vertex) { cluster_eta = RawClusterUtility::GetPseudorapidity(*(hiter->second),CLHEP::Hep3Vector(vertex->get_x(), vertex->get_y(), vertex->get_z())); @@ -264,36 +252,35 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_EM_cluster.push_back(hiter->second); _pflow_EM_match_HAD.push_back( std::vector() ); _pflow_EM_match_TRK.push_back( std::vector() ); - - if ( Verbosity() > 5 && cluster_E > 0.2 ) + + if ( Verbosity() > 5 && cluster_E > 0.2 ) std::cout << " EM topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl; - + std::vector this_cluster_tower_eta; std::vector this_cluster_tower_phi; - + // read in towers RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers(); for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter) { - + if ( RawTowerDefs::decode_caloid( iter->first ) == RawTowerDefs::CalorimeterId::CEMC ) { - RawTower* tower = towersEM->getTower(iter->first); - RawTowerGeom *tower_geom = geomEM->get_tower_geometry(tower->get_key()); - + RawTowerGeom *tower_geom = geomEM->get_tower_geometry(iter->first); + this_cluster_tower_phi.push_back( tower_geom->get_phi() ); this_cluster_tower_eta.push_back( tower_geom->get_eta() ); } else { std::cout << "ParticleFlowReco::process_event : FATAL ERROR , EM topoClusters seem to contain HCal towers" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; - } + } } // close tower loop - + _pflow_EM_tower_eta.push_back( this_cluster_tower_eta ); _pflow_EM_tower_phi.push_back( this_cluster_tower_phi ); - + } // close cluster loop - - } // close + + } // close // read in HCal topoClusters with E > 0.2 GeV { @@ -302,7 +289,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) { float cluster_E = hiter->second->get_energy(); if ( cluster_E < 0.2 ) continue; - + float cluster_phi = hiter->second->get_phi(); // for now, assume event at vx_z = 0 float cluster_theta = M_PI / 2.0 - atan2( hiter->second->get_z() , hiter->second->get_r() ); @@ -319,69 +306,67 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_HAD_match_EM.push_back( std::vector() ); _pflow_HAD_match_TRK.push_back( std::vector() ); - - if ( Verbosity() > 5 && cluster_E > 0.2 ) + + if ( Verbosity() > 5 && cluster_E > 0.2 ) std::cout << " HAD topoCluster with E = " << cluster_E << ", eta / phi = " << cluster_eta << " / " << cluster_phi << " , nTow = " << hiter->second->getNTowers() << std::endl; - + std::vector this_cluster_tower_eta; std::vector this_cluster_tower_phi; - + // read in towers RawCluster::TowerConstRange begin_end_towers = hiter->second->get_towers(); for (RawCluster::TowerConstIterator iter = begin_end_towers.first; iter != begin_end_towers.second; ++iter) { - + if ( RawTowerDefs::decode_caloid( iter->first ) == RawTowerDefs::CalorimeterId::HCALIN ) { - RawTower* tower = towersIH->getTower(iter->first); - RawTowerGeom *tower_geom = geomIH->get_tower_geometry(tower->get_key()); - + RawTowerGeom *tower_geom = geomIH->get_tower_geometry(iter->first); + this_cluster_tower_phi.push_back( tower_geom->get_phi() ); this_cluster_tower_eta.push_back( tower_geom->get_eta() ); } else if ( RawTowerDefs::decode_caloid( iter->first ) == RawTowerDefs::CalorimeterId::HCALOUT ) { - RawTower* tower = towersOH->getTower(iter->first); - RawTowerGeom *tower_geom = geomOH->get_tower_geometry(tower->get_key()); - + RawTowerGeom *tower_geom = geomOH->get_tower_geometry(iter->first); + this_cluster_tower_phi.push_back( tower_geom->get_phi() ); this_cluster_tower_eta.push_back( tower_geom->get_eta() ); } else { std::cout << "ParticleFlowReco::process_event : FATAL ERROR , HCal topoClusters seem to contain EM towers" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - - + + } // close tower loop - + _pflow_HAD_tower_eta.push_back( this_cluster_tower_eta ); _pflow_HAD_tower_phi.push_back( this_cluster_tower_phi ); - + } // close cluster loop - - } // close + + } // close // BEGIN LINKING STEP // Link TRK -> EM (best match, but keep reserve of others), and TRK -> HAD (best match) - if ( Verbosity() > 2 ) + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : TRK -> EM and TRK -> HAD linking " << std::endl; for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) { - + if ( Verbosity() > 10 ) std::cout << " TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p[ trk ] << " / " << _pflow_TRK_eta[ trk ] << " / " << _pflow_TRK_phi[ trk ] << std::endl; // TRK -> EM link float min_em_dR = 0.2; int min_em_index = -1; - + for (unsigned int em = 0 ; em < _pflow_EM_E.size() ; em++) { float dR = calculate_dR( _pflow_TRK_EMproj_eta[ trk ] , _pflow_EM_eta[ em ] , _pflow_TRK_EMproj_phi[ trk ] , _pflow_EM_phi[ em ] ); - + if ( dR > 0.2 ) continue; - + bool has_overlap = false; for (unsigned int tow = 0; tow < _pflow_EM_tower_eta.at( em ).size() ; tow++) { @@ -403,21 +388,21 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( has_overlap ) { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> possible match to EM " << em << " with dR = " << dR << std::endl; _pflow_TRK_addtl_match_EM.at( trk ).push_back( std::pair( em, dR ) ); } else { - - if ( Verbosity() > 5 ) + + if ( Verbosity() > 5 ) std::cout << " -> no match to EM " << em << " (even though dR = " << dR << " )" << std::endl; - + } } - // sort possible matches + // sort possible matches std::sort( _pflow_TRK_addtl_match_EM.at( trk ).begin(), _pflow_TRK_addtl_match_EM.at( trk ).end(), sort_by_pair_second_lowest ); if ( Verbosity() > 10 ) { @@ -425,7 +410,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) std::cout << " -> sorted list of matches, EM / dR = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first << " / " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second << std::endl; } } - + if ( _pflow_TRK_addtl_match_EM.at( trk ).size() > 0 ) { min_em_index = _pflow_TRK_addtl_match_EM.at( trk ).at( 0 ).first; min_em_dR = _pflow_TRK_addtl_match_EM.at( trk ).at( 0 ).second; @@ -442,13 +427,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) std::cout << " -> matched EM " << min_em_index << " with pt / eta / phi = " << _pflow_EM_E.at( min_em_index ) << " / " << _pflow_EM_eta.at( min_em_index ) << " / " << _pflow_EM_phi.at( min_em_index ) << ", dR = " << min_em_dR; std::cout << " ( " << _pflow_TRK_addtl_match_EM.at( trk ).size() << " other possible matches ) " << std::endl; } - + } else { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> no EM match! ( best dR = " << min_em_dR << " ) " << std::endl; } - + // TRK -> HAD link float min_had_dR = 0.2; int min_had_index = -1; @@ -458,9 +443,9 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) for (unsigned int had = 0 ; had < _pflow_HAD_E.size() ; had++) { float dR = calculate_dR( _pflow_TRK_HADproj_eta[ trk ] , _pflow_HAD_eta[ had ] , _pflow_TRK_HADproj_phi[ trk ] , _pflow_HAD_phi[ had ] ); - + if ( dR > 0.5 ) continue; - + bool has_overlap = false; for (unsigned int tow = 0; tow < _pflow_HAD_tower_eta.at( had ).size() ; tow++) { @@ -482,7 +467,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( has_overlap ) { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl; if ( _pflow_HAD_E.at( had ) > max_had_pt ) { @@ -492,10 +477,10 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } } else { - - if ( Verbosity() > 5 ) + + if ( Verbosity() > 5 ) std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl; - + } } @@ -504,11 +489,11 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_HAD_match_TRK.at( min_had_index ).push_back( trk ); _pflow_TRK_match_HAD.at( trk ).push_back( min_had_index ); - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> matched HAD " << min_had_index << " with pt / eta / phi = " << _pflow_HAD_E.at( min_had_index ) << " / " << _pflow_HAD_eta.at( min_had_index ) << " / " << _pflow_HAD_phi.at( min_had_index ) << ", dR = " << min_had_dR << std::endl; - + } else { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl; } @@ -516,20 +501,20 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } - // EM->HAD linking - if ( Verbosity() > 2 ) + // EM->HAD linking + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : EM -> HAD linking " << std::endl; for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) { - + if ( Verbosity() > 10 ) std::cout << " EM with E / eta / phi = " << _pflow_EM_E[ em ] << " / " << _pflow_EM_eta[ em ] << " / " << _pflow_EM_phi[ em ] << std::endl; - + // TRK -> HAD link float min_had_dR = 0.2; int min_had_index = -1; float max_had_pt = 0; - + for (unsigned int had = 0 ; had < _pflow_HAD_E.size() ; had++) { float dR = calculate_dR( _pflow_EM_eta[ em ] , _pflow_HAD_eta[ had ] , _pflow_EM_phi[ em ] , _pflow_HAD_phi[ had ] ); @@ -556,7 +541,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( has_overlap ) { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> possible match to HAD " << had << " with dR = " << dR << std::endl; if ( _pflow_HAD_E.at( had ) > max_had_pt ) { @@ -566,10 +551,10 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } } else { - - if ( Verbosity() > 5 ) + + if ( Verbosity() > 5 ) std::cout << " -> no match to HAD " << had << " (even though dR = " << dR << " )" << std::endl; - + } } @@ -578,19 +563,19 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) _pflow_HAD_match_EM.at( min_had_index ).push_back( em ); _pflow_EM_match_HAD.at( em ).push_back( min_had_index ); - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> matched HAD with E / eta / phi = " << _pflow_HAD_E.at( min_had_index ) << " / " << _pflow_HAD_eta.at( min_had_index ) << " / " << _pflow_HAD_phi.at( min_had_index ) << ", dR = " << min_had_dR << std::endl; - + } else { - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> no HAD match! ( best dR = " << min_had_dR << " ) " << std::endl; } } - // SEQUENTIAL MATCHING: if TRK -> EM and EM -> HAD, ensure that TRK -> HAD - if ( Verbosity() > 2 ) + // SEQUENTIAL MATCHING: if TRK -> EM and EM -> HAD, ensure that TRK -> HAD + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : sequential TRK -> EM && EM -> HAD ==> TRK -> HAD matching " << std::endl; for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) { @@ -610,8 +595,8 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) for (unsigned int k = 0; k < _pflow_TRK_match_HAD.at( trk ).size(); k++) { int existing_had = _pflow_TRK_match_HAD.at( trk ).at( k ); if ( had == existing_had ) is_trk_matched_to_HAD = true; - } - + } + // if this is the case, create TRK->HAD link if ( ! is_trk_matched_to_HAD ) { _pflow_TRK_match_HAD.at( trk ).push_back( had ); @@ -631,18 +616,18 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } // close the TRK loop // TRK->EM->HAD removal - if ( Verbosity() > 2 ) + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : resolve TRK(s) + EM(s) -> HAD systems " << std::endl; - + for (unsigned int had = 0; had < _pflow_HAD_E.size() ; had++ ) { - // only consider HAD with matched tracks ... others we will deal with later + // only consider HAD with matched tracks ... others we will deal with later if ( _pflow_HAD_match_TRK.at( had ).size() == 0 ) continue; if ( Verbosity() > 5 ) { std::cout << " HAD " << had << " with E / eta / phi = " << _pflow_HAD_E.at( had ) << " / " << _pflow_HAD_eta.at( had ) << " / " << _pflow_HAD_phi.at( had ) << std::endl; } - + // setup for Sum-pT^trk -> calo prediction float total_TRK_p = 0; float total_expected_E = 0; @@ -653,7 +638,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) std::vector matchedEClusters; - // iterate over the EMs matched to this HAD + // iterate over the EMs matched to this HAD for (unsigned int j = 0; j < _pflow_HAD_match_EM.at( had ).size() ; j++ ) { int em = _pflow_HAD_match_EM.at( had ).at( j ); @@ -661,7 +646,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // ensure there is at least one track matched to this EM if ( _pflow_EM_match_TRK.at( em ).size() == 0 ) continue; - // add it to the total calo E + // add it to the total calo E total_EMHAD_E += _pflow_EM_E.at( em ); matchedEClusters.push_back(_pflow_EM_cluster.at(em)); if ( Verbosity() > 5 ) { @@ -669,7 +654,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } } - + // iterate over the TRKs matched to this HAD for (unsigned int j = 0 ; j < _pflow_HAD_match_TRK.at( had ).size() ; j++) { @@ -678,7 +663,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " -> -> LINKED TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p.at( trk ) << " / " << _pflow_TRK_eta.at( trk ) << " / " << _pflow_TRK_phi.at( trk ) << std::endl; } - + total_TRK_p += _pflow_TRK_p.at( trk ); std::pair expected_signature = get_expected_signature( trk ); @@ -689,16 +674,16 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl; } - + total_expected_E += expected_E_mean; total_expected_E_var += pow( expected_E_sigma , 2 ); // add PFlow element for each track ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume pion mass - TLorentzVector tlv; - tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); + TLorentzVector tlv; + tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); pflow->set_px( tlv.Px() ); pflow->set_py( tlv.Py() ); @@ -709,14 +694,14 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) pflow->set_hcluster(_pflow_HAD_cluster.at(had)); pflow->set_id( global_pflow_index ); pflow->set_type( ParticleFlowElement::PFLOWTYPE::MATCHED_CHARGED_HADRON ); - + pflowContainer->AddParticleFlowElement( global_pflow_index, pflow ); global_pflow_index++; } // Track + E+HCal PF elements are created - - // process compatibility of fit + + // process compatibility of fit float total_expected_E_err = sqrt( total_expected_E_var ); if ( Verbosity() > 5 ) { @@ -726,25 +711,25 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // if Sum pT > calo, add in additional possible matched EMs associated with tracks until that is no longer the case if ( total_expected_E > total_EMHAD_E ) { - - if ( Verbosity() > 5 ) + + if ( Verbosity() > 5 ) std::cout << " -> Expected E > Observed E, looking for additional potential TRK->EM matches" << std::endl; - + std::map additional_EMs; - + for (unsigned int j = 0 ; j < _pflow_HAD_match_TRK.at( had ).size() ; j++) { - + int trk = _pflow_HAD_match_TRK.at( had ).at( j ); int addtl_matches = _pflow_TRK_addtl_match_EM.at( trk ).size(); if ( Verbosity() > 10 ) std::cout << " -> -> TRK " << trk << " has " << addtl_matches << " additional matches! " << std::endl; - + for (unsigned int n = 0 ; n < _pflow_TRK_addtl_match_EM.at( trk ).size() ; n++ ) { if ( Verbosity() > 10 ) std::cout << " -> -> -> additional match to EM = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first << " with dR = " << _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second << std::endl; - + float existing_dR = 0.21; int counts = additional_EMs.count( _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first ); if ( counts > 0 ) { @@ -753,7 +738,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second < existing_dR ) additional_EMs[ _pflow_TRK_addtl_match_EM.at( trk ).at( n ).first ] = _pflow_TRK_addtl_match_EM.at( trk ).at( n ).second; } - + } // map now assured to have only minimal dR values for each possible additional EM @@ -767,7 +752,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) std::sort( additional_EMs_vec.begin(), additional_EMs_vec.end(), sort_by_pair_second_lowest ); - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> Sorting the set of potential additional EMs " << std::endl; // now add in additional EMs until there are none left or it is no longer the case that Sum pT > calo @@ -777,13 +762,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) int new_EM = additional_EMs_vec.at( 0 ).first; - if ( Verbosity() > 5 ) + if ( Verbosity() > 5 ) std::cout << " -> adding EM " << new_EM << " ( dR = " << additional_EMs_vec.at( 0 ).second << " to the system (should not see it as orphan below)" << std::endl; // for now, just make the first HAD-linked track point to this new EM, and vice versa _pflow_EM_match_TRK.at( new_EM ).push_back( _pflow_HAD_match_TRK.at( had ).at( 0 ) ); _pflow_TRK_match_EM.at( _pflow_HAD_match_TRK.at( had ).at( 0 ) ).push_back( new_EM ); - + // add to expected calo total_EMHAD_E += _pflow_EM_E.at( new_EM ); @@ -792,28 +777,28 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) n_EM_added++; } - + if ( Verbosity() > 5) { if ( n_EM_added > 0 ) { std::cout << "After adding N = " << n_EM_added << " any additional EMs : " << std::endl; std::cout << "-> Total track Sum p = " << total_TRK_p << " , expected calo Sum E = " << total_expected_E << " +/- " << total_expected_E_err << " , observed EM+HAD Sum E = " << total_EMHAD_E << std::endl; } - else { + else { std::cout << "No additional EMs found, continuing hypothesis check" << std::endl; } } } - - - + + + if ( total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EMHAD_E ) { - + if ( Verbosity() > 5 ) { std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl; } // PFlow elements already created from tracks above, no more needs to be done - + } else { float residual_energy = total_EMHAD_E - total_expected_E; @@ -824,9 +809,9 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // create additional PFlow element (tracks already created above) ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume no mass, but could update to use K0L mass(?) - TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 ); + TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 ); pflow->set_px( tlv.Px() ); pflow->set_py( tlv.Py() ); @@ -843,13 +828,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } - } // close HAD loop + } // close HAD loop // TRK->EM removal - if ( Verbosity() > 2 ) + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : resolve TRK(s) -> EM(s) ( + no HAD) systems " << std::endl; - + for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) { // only consider EM with matched tracks, but no matched HADs @@ -859,7 +844,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " EM " << em << " with E / eta / phi = " << _pflow_EM_E.at( em ) << " / " << _pflow_EM_eta.at( em ) << " / " << _pflow_EM_phi.at( em ) << std::endl; } - + // setup for Sum-pT^trk -> calo prediction float total_TRK_p = 0; float total_expected_E = 0; @@ -867,7 +852,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // begin with this EM calo energy float total_EM_E = _pflow_EM_E.at( em ); - + // iterate over the TRKs matched to this EM for (unsigned int j = 0 ; j < _pflow_EM_match_TRK.at( em ).size() ; j++) { @@ -876,7 +861,7 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " -> -> LINKED TRK with p / eta / phi = " << _pflow_TRK_p.at( trk ) << " / " << _pflow_TRK_eta.at( trk ) << " / " << _pflow_TRK_phi.at( trk ) << std::endl; } - + total_TRK_p += _pflow_TRK_p.at( trk ); std::pair expected_signature = get_expected_signature( trk ); @@ -887,15 +872,15 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " -> -> -> expected calo signature is " << expected_E_mean << " +/- " << expected_E_sigma << std::endl; } - + total_expected_E += expected_E_mean; total_expected_E_var += pow( expected_E_sigma , 2 ); // add PFlow element for each track ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume pion mass - TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); + TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); std::vector eclus; eclus.push_back(_pflow_EM_cluster.at(em)); @@ -915,21 +900,21 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } - // process compatibility of fit + // process compatibility of fit float total_expected_E_err = sqrt( total_expected_E_var ); if ( Verbosity() > 5 ) { std::cout << " -> Total track Sum p = " << total_TRK_p << " , expected calo Sum E = " << total_expected_E << " +/- " << total_expected_E_err << " , observed EM Sum E = " << total_EM_E << std::endl; } - + if ( total_expected_E + _energy_match_Nsigma * total_expected_E_err > total_EM_E ) { - + if ( Verbosity() > 5 ) { std::cout << " -> -> calo compatible within Nsigma = " << _energy_match_Nsigma << " , remove and keep tracks " << std::endl; } // PFlow elements already created from tracks above, no more needs to be done - + } else { float residual_energy = total_EM_E - total_expected_E; @@ -940,9 +925,9 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) // create additional PFlow element (tracks already created above) ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume no mass, but could update to use K0L mass(?) - TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 ); + TLorentzVector tlv; tlv.SetPtEtaPhiM( residual_energy / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 ); std::vector eclus; eclus.push_back(_pflow_EM_cluster.at(em)); @@ -962,13 +947,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) } - } // close EM loop + } // close EM loop // now remove unmatched elements - if ( Verbosity() > 2 ) + if ( Verbosity() > 2 ) std::cout << "ParticleFlowReco::process_event : remove TRK-unlinked EMs and HADs " << std::endl; - + for (unsigned int em = 0; em < _pflow_EM_E.size() ; em++ ) { // only consider EMs withOUT matched tracks ... we have dealt with the matched cases above @@ -977,13 +962,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " unmatched EM " << em << " with E / eta / phi = " << _pflow_EM_E.at( em ) << " / " << _pflow_EM_eta.at( em ) << " / " << _pflow_EM_phi.at( em ) << std::endl; } - - // add PFlow element for this EM + + // add PFlow element for this EM ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume massless, could be updated to use K0L - TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_EM_E[ em ] / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 ); - + TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_EM_E[ em ] / cosh( _pflow_EM_eta[ em ] ) , _pflow_EM_eta[ em ] , _pflow_EM_phi[ em ] , 0 ); + std::vector eclus; eclus.push_back(_pflow_EM_cluster.at(em)); @@ -999,9 +984,9 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) pflowContainer->AddParticleFlowElement( global_pflow_index, pflow ); global_pflow_index++; - - - } // close EM loop + + + } // close EM loop for (unsigned int had = 0; had < _pflow_HAD_E.size() ; had++ ) { @@ -1011,13 +996,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) if ( Verbosity() > 5 ) { std::cout << " unmatched HAD " << had << " with E / eta / phi = " << _pflow_HAD_E.at( had ) << " / " << _pflow_HAD_eta.at( had ) << " / " << _pflow_HAD_phi.at( had ) << std::endl; } - - // add PFlow element for this HAD + + // add PFlow element for this HAD ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume massless, could be updated to use K0L - TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_HAD_E[ had ] / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 ); - + TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_HAD_E[ had ] / cosh( _pflow_HAD_eta[ had ] ) , _pflow_HAD_eta[ had ] , _pflow_HAD_phi[ had ] , 0 ); + pflow->set_px( tlv.Px() ); pflow->set_py( tlv.Py() ); pflow->set_pz( tlv.Pz() ); @@ -1030,25 +1015,25 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) pflowContainer->AddParticleFlowElement( global_pflow_index, pflow ); global_pflow_index++; - - - } // close HAD loop + + + } // close HAD loop for (unsigned int trk = 0; trk < _pflow_TRK_p.size() ; trk++ ) { - // only consider TRKs withOUT matched EM or HAD + // only consider TRKs withOUT matched EM or HAD if ( _pflow_TRK_match_EM.at( trk ).size() != 0 || _pflow_TRK_match_HAD.at( trk ).size() != 0 ) continue; if ( Verbosity() > 5 ) { std::cout << " unmatched TRK " << trk << " with p / eta / phi = " << _pflow_TRK_p.at( trk ) << " / " << _pflow_TRK_eta.at( trk ) << " / " << _pflow_TRK_phi.at( trk ) << std::endl; } - - // add PFlow element for this TRK + + // add PFlow element for this TRK ParticleFlowElement *pflow = new ParticleFlowElementv1(); - + // assume massless, could be updated to use K0L - TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); - + TLorentzVector tlv; tlv.SetPtEtaPhiM( _pflow_TRK_p[ trk ] / cosh( _pflow_TRK_eta[ trk ] ) , _pflow_TRK_eta[ trk ] , _pflow_TRK_phi[ trk ] , 0.135 ); + pflow->set_px( tlv.Px() ); pflow->set_py( tlv.Py() ); pflow->set_pz( tlv.Pz() ); @@ -1061,13 +1046,13 @@ int ParticleFlowReco::process_event(PHCompositeNode *topNode) pflowContainer->AddParticleFlowElement( global_pflow_index, pflow ); global_pflow_index++; - - } // close TRK loop + + } // close TRK loop // DEBUG: print out all PFLow elements if ( Verbosity() > 5 ) { std::cout << "ParticleFlowReco::process_event: summary of PFlow objects " << std::endl; - + ParticleFlowElementContainer::ConstRange begin_end = pflowContainer->getParticleFlowElements(); for ( ParticleFlowElementContainer::ConstIterator hiter = begin_end.first; hiter != begin_end.second; ++hiter) { hiter->second->identify(); From 0c2ae0e2e793a8d967183fc89de32b3eaeb21eab Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 6 Apr 2023 20:29:55 -0400 Subject: [PATCH 147/468] fix clang build error --- simulation/g4simulation/g4bbc/BbcSimReco.h | 1 - 1 file changed, 1 deletion(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.h b/simulation/g4simulation/g4bbc/BbcSimReco.h index f6b1a7ef3d..471c787fc9 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.h +++ b/simulation/g4simulation/g4bbc/BbcSimReco.h @@ -54,7 +54,6 @@ class BbcSimReco : public SubsysReco void CreateNodes(PHCompositeNode *topNode); // Create all the nodes void GetNodes(PHCompositeNode *); // Get all the needed nodes - Int_t f_evt = 0; Float_t f_vx = NAN; Float_t f_vy = NAN; Float_t f_vz = NAN; From 7db3f0a85690c5a0221b7646b96cc861ad156a4a Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 7 Apr 2023 03:03:05 -0400 Subject: [PATCH 148/468] jenkins retrigger --- offline/packages/trackbase/ClusterErrorPara.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 205b89c51c..9ac4d7f002 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -21,7 +21,6 @@ ClusterErrorPara::ClusterErrorPara() f0 = new TF1("f0","pol1",0,10); f0->SetParameter(0,0.0163943); f0->SetParameter(1,0.0192931); - // f0->SetParameter(2,-5.2042); f1 = new TF1("f1","pol2",0,10); f1->SetParameter(0,0.0119384); From 8de2b38e65514d41a08bf0f4700fb10c24c1293f Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 7 Apr 2023 10:02:52 -0400 Subject: [PATCH 149/468] Removed ecxess cout statements. Removed dynamic cast to CMFlashCluster version and used base class. Removed hard coded r and phi bins for distortion maps --- offline/packages/tpc/TpcClusterizer.cc | 2 +- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 31 ++++++++++--------- .../g4tpc/PHG4TpcCentralMembrane.cc | 1 - 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index a6e66f7d70..90ce0cef57 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -417,7 +417,7 @@ namespace // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) if(my_data.cluster_version==3){ - std::cout << "ver3" << std::endl; + //std::cout << "ver3" << std::endl; // Fill in the cluster details //================ auto clus = new TrkrClusterv3; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index b1c10dd259..e89be37628 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -383,7 +383,7 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) ++cmitr) { const auto& [cmkey, cmclus_orig] = *cmitr; - CMFlashClusterv2 *cmclus = dynamic_cast(cmclus_orig); + CMFlashCluster *cmclus = cmclus_orig; const unsigned int nclus = cmclus->getNclusters(); if(m_useOnly_nClus2 && nclus != 2) continue; @@ -858,12 +858,13 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) m_dcc_out_aggregated.reset( new TpcDistortionCorrectionContainer ); // compute axis limits to include guarding bins, needed for TH2::Interpolate to work - // const float phiMin = m_phiMin - (m_phiMax-m_phiMin)/m_phibins; - // const float phiMax = m_phiMax + (m_phiMax-m_phiMin)/m_phibins; + const float phiMin = m_phiMin - (m_phiMax-m_phiMin)/m_phibins; + const float phiMax = m_phiMax + (m_phiMax-m_phiMin)/m_phibins; - // const float rMin = m_rMin - (m_rMax-m_rMin)/m_rbins; - // const float rMax = m_rMax + (m_rMax-m_rMin)/m_rbins; - + const float rMin = m_rMin - (m_rMax-m_rMin)/m_rbins; + const float rMax = m_rMax + (m_rMax-m_rMin)/m_rbins; + + /* double r_bins_mm[69] = {217.83-2,217.83, 223.83, 229.83, 235.83, 241.83, 247.83, 253.83, 259.83, 265.83, 271.83, 277.83, 283.83, 289.83, 295.83, 301.83, 306.83, 311.05, 317.92, 323.31, 329.27, 334.63, 340.59, 345.95, 351.91, 357.27, 363.23, 368.59, 374.55, 379.91, 385.87, 391.23, 397.19, 402.49, @@ -893,7 +894,7 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) 5.3567, 5.3886, 5.4204, 5.4523, 5.4842, 5.4978, 5.5297, 5.5615, 5.5934, 5.6253, 5.6572, 5.689, 5.7209, 5.7528, 5.7847, 5.8165, 5.8484, 5.8803, 5.9122, 5.944, 5.9759, 6.0078, 6.0214, 6.0533, 6.0851, 6.117, 6.1489, 6.1808, 6.2127, 6.2445, 6.2764, 2 * M_PI}; - + */ // reset all output distortion container so that they match the requested grid size const std::array extension = {{ "_negz", "_posz" }}; @@ -905,16 +906,16 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) // create all histograms for( int i =0; i < 2; ++i ) { - // delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - // delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - // delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - // delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); + delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), m_phibins+2, phiMin, phiMax, m_rbins+2, rMin, rMax ); - delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); - delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); - delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); - delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), 205, phiBins, 68, r_bins); + //delete dcc->m_hDPint[i]; dcc->m_hDPint[i] = new TH2F( Form("hIntDistortionP%s", extension[i].c_str()), Form("hIntDistortionP%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + //delete dcc->m_hDRint[i]; dcc->m_hDRint[i] = new TH2F( Form("hIntDistortionR%s", extension[i].c_str()), Form("hIntDistortionR%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + //delete dcc->m_hDZint[i]; dcc->m_hDZint[i] = new TH2F( Form("hIntDistortionZ%s", extension[i].c_str()), Form("hIntDistortionZ%s", extension[i].c_str()), 205, phiBins, 68, r_bins ); + //delete dcc->m_hentries[i]; dcc->m_hentries[i] = new TH2I( Form("hEntries%s", extension[i].c_str()), Form("hEntries%s", extension[i].c_str()), 205, phiBins, 68, r_bins); } } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc index d2a0dd7749..55e8491f0a 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcCentralMembrane.cc @@ -167,7 +167,6 @@ int PHG4TpcCentralMembrane::process_event(PHCompositeNode* topNode) // load g4hit container auto g4hitcontainer = findNode::getClass(topNode, hitnodename.c_str()); - std::cout << PHWHERE << "hitnodename: " << hitnodename.c_str() << std::endl; if (!g4hitcontainer) { std::cout << PHWHERE << "Could not locate g4 hit node " << hitnodename << std::endl; From 53b3d9078124691e35c98f9e10ee10ae48957eae Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 11:33:39 -0400 Subject: [PATCH 150/468] add type 19 for JS Jet 40GeV, remove test files from printout --- offline/framework/frog/CreateFileList.pl | 31 ++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 3890aa4093..61cf1f4e59 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -28,6 +28,12 @@ unlink $listfile; } } +my %exclude_these = ( + "DST_JOBA" => "Test PanDa", + "DST_MDC2_GLOBAL" => "Test PanDa", + "DST_PASS1_CLUSTERS" => "Test PanDa", + "DST_RECO_CLUSTER" => "Test PanDa" + ); my %proddesc = ( # "1" => "hijing (0-12fm) pileup 0-12fm DELETED", @@ -47,7 +53,8 @@ "15" => "Special Productions", "16" => "HF pythia8 D0 Jets", "17" => "HF pythia8 D0 pi-k Jets ptmin = 5GeV ", - "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV" + "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV", + "19" => "JS pythia8 Jet ptmin = 40GeV" ); my %pileupdesc = ( @@ -322,6 +329,23 @@ } &commonfiletypes(); } + elsif ($prodtype == 19) + { + $embedok = 1; + $filenamestring = "pythia8_Jet40"; + if (! defined $nopileup) + { + if (defined $embed) + { + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $pileupstring); + } + else + { + $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); + } + } + &commonfiletypes(); + } else { print "no production type $prodtype\n"; @@ -371,7 +395,10 @@ print "\navailable file types (choose at least one, --> means: written to):\n"; foreach my $tp (sort keys %dsttype) { - print "$tp --> $dsttype{$tp}\n"; + if (! exists $exclude_these{$tp}) + { + print "$tp --> $dsttype{$tp}\n"; + } } } else From f12ed678c335436779c48026e5aa35b3204c550e Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 7 Apr 2023 11:49:04 -0400 Subject: [PATCH 151/468] middle of edits -- will continue --- simulation/g4simulation/g4intt/Makefile.am | 6 +- .../g4simulation/g4intt/PHG4InttHitReco.cc | 402 ++++++++++++++++- .../g4simulation/g4intt/PHG4InttHitReco.h | 22 + simulation/g4simulation/g4mvtx/Makefile.am | 6 +- .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 414 +++++++++++++++++- .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 33 +- .../g4mvtx/PHG4MvtxTruthClusterizer.cc | 235 ++-------- 7 files changed, 883 insertions(+), 235 deletions(-) diff --git a/simulation/g4simulation/g4intt/Makefile.am b/simulation/g4simulation/g4intt/Makefile.am index b7fa33a614..ee55b8a01b 100644 --- a/simulation/g4simulation/g4intt/Makefile.am +++ b/simulation/g4simulation/g4intt/Makefile.am @@ -29,8 +29,7 @@ pkginclude_HEADERS = \ PHG4InttDefs.h \ PHG4InttDigitizer.h \ PHG4InttHitReco.h \ - PHG4InttSubsystem.h \ - PHG4InttTruthClusterizer.h + PHG4InttSubsystem.h ROOTDICTS = \ InttDeadMap_Dict.cc \ @@ -50,8 +49,7 @@ libg4intt_la_SOURCES = \ PHG4InttFPHXParameterisation.cc \ PHG4InttHitReco.cc \ PHG4InttSteppingAction.cc \ - PHG4InttSubsystem.cc \ - PHG4InttTruthClusterizer.cc + PHG4InttSubsystem.cc libg4intt_la_LIBADD = \ libg4intt_io.la \ diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index ea8a72317e..437cce74e4 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -54,7 +54,7 @@ PHG4InttHitReco::PHG4InttHitReco(const std::string &name) , m_Tmin(NAN) , m_Tmax(NAN) , m_crossingPeriod(NAN) - , m_truthclusterizer { new PHG4InttTruthClusterizer } + , m_truth_hits { new TrkrHitSetContainerv1 } { InitializeParameters(); @@ -71,7 +71,7 @@ PHG4InttHitReco::~PHG4InttHitReco() gsl_vector_free(m_LocalOutVec); gsl_vector_free(m_PathVec); gsl_vector_free(m_SegmentVec); - delete m_truthclusterizer; + delete m_truth_hits; } int PHG4InttHitReco::InitRun(PHCompositeNode *topNode) @@ -179,7 +179,30 @@ int PHG4InttHitReco::InitRun(PHCompositeNode *topNode) m_Tmax = get_double_param("tmax"); m_crossingPeriod = get_double_param("beam_crossing_period"); - m_truthclusterizer->init_run(topNode, Verbosity()); + // get the nodes for the truth clustering + m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + if (!m_truthtracks) + { + PHNodeIterator dstiter(dstNode); + m_truthtracks = new TrkrTruthTrackContainerv1(); + auto newNode = new PHIODataNode(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); + dstNode->addNode(newNode); + } + + m_truthclusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + if (!m_truthclusters) + { + m_truthclusters = new TrkrClusterContainerv4; + auto newNode = new PHIODataNode(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); + dstNode->addNode(newNode); + } + + m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_truthinfo) + { + std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl; + assert(m_truthinfo); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -226,7 +249,7 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) const int sphxlayer = hiter->second->get_detid(); CylinderGeomIntt *layergeom = dynamic_cast(geo->GetLayerGeom(sphxlayer)); - m_truthclusterizer->check_g4hit(hiter->second); + truthcheck_g4hit(g4hit, topNode); // checking ADC timing integration window cut // uses default values for now @@ -446,7 +469,7 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) double hit_energy = venergy[i1].first * TrkrDefs::InttEnergyScaleup; hit->addEnergy(hit_energy); - m_truthclusterizer->addhitset(hitsetkey, hitkey, hit_energy); + addtruthhitset(hitsetkey, hitkey, hit_energy); // Add this hit to the association map hittruthassoc->addAssoc(hitsetkey, hitkey, hiter->first); @@ -466,12 +489,9 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) hittruthassoc->identify(); } - // spit out the truth clusters - if (Verbosity() > 5) m_truthclusterizer->print_clusters(); - m_truthclusterizer->end_of_event(); - + end_event_truthcluster( topNode ); return Fun4AllReturnCodes::EVENT_OK; -} +} // end process_event void PHG4InttHitReco::SetDefaultParameters() { @@ -484,3 +504,365 @@ void PHG4InttHitReco::SetDefaultParameters() return; } + +void PHG4InttHitReco::truthcheck_g4hit(PHG4Hit* hit, PHCompositeNode* topNode) { + int new_trkid = (hit==nullptr) ? -1 : hit->get_trkid(); + bool is_new_track = (new_trkid != m_trkid); + if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl; + if (m_is_emb) { + clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + m_current_track = nullptr; + } + m_trkid = new_trkid; // although m_current_track won't catch up until update_track is called + m_is_emb = m_truthinfo->isEmbeded(m_trkid); + if (m_is_emb) { + m_current_track = m_truthtracks->getTruthTrack(m_trkid, m_truthinfo); + } +} + +void PHG4InttHitReco::end_event_truthcluster ( PHCompositeNode* topNode ) { + if (m_is_emb) { + clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + m_current_track = nullptr; + m_trkid = -1; + m_is_emb = false; + } + m_hitsetkey_cnt.clear(); +} + +void PHG4InttHitReco::addtruthhitset( + TrkrDefs::hitsetkey hitsetkey, + TrkrDefs::hitkey hitkey, + float neffelectrons) +{ + if (!m_is_emb) return; + TrkrHitSetContainer::Iterator hitsetit = m_truth_hits->findOrAddHitSet(hitsetkey); + // See if this hit already exists + TrkrHit *hit = nullptr; + hit = hitsetit->second->getHit(hitkey); + if (!hit) + { + // create a new one + hit = new TrkrHitv2(); + hitsetit->second->addHitSpecificKey(hitkey, hit); + } + // Either way, add the energy to it -- adc values will be added at digitization + hit->addEnergy(neffelectrons); +} + +void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { + // ----------------------------------------------- + // Digitize, adapted from g4intt/PHG4InttDigitizer + // ----------------------------------------------- + // don't use the dead map for truth tracks + TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); + for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; + hitset_iter != hitset_range.second; + ++hitset_iter) + { + // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer + // get the hitset key so we can find the layer + TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; + const int layer = TrkrDefs::getLayer(hitsetkey); + const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); + const int ladder_z = InttDefs::getLadderZId(hitsetkey); + + if (Verbosity() > 1) + { + std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; + } + // get all of the hits from this hitset + TrkrHitSet *hitset = hitset_iter->second; + TrkrHitSet::ConstRange hit_range = hitset->getHits(); + /* std::set dead_hits; // hits on dead channel */ // no dead channels implemented + for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; + hit_iter != hit_range.second; + ++hit_iter) + { + // ++m_nCells; // not really used by PHG4InttDigitizer + + TrkrHit *hit = hit_iter->second; + TrkrDefs::hitkey hitkey = hit_iter->first; + int strip_col = InttDefs::getCol(hitkey); // strip z index + int strip_row = InttDefs::getRow(hitkey); // strip phi index + + // FIXME need energy scales here + if (_energy_scale.count(layer) > 1) + { + assert(!"Error: _energy_scale has two or more keys."); + } + const float mip_e = _energy_scale[layer]; + + std::vector > vadcrange = _max_fphx_adc[layer]; + + int adc = 0; + for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) + { + if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * + (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup + < vadcrange[irange].second * (double) mip_e) + { + adc = (unsigned short) irange; + } + } + hit->setAdc(adc); + + if (Verbosity() > 2) + { + std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi + << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; + } + } // end loop over hits in this hitset + + /* // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC */ + /* for (const auto &key : dead_hits) */ + /* { */ + /* if (Verbosity() > 2) */ + /* { */ + /* std::cout << " PHG4InttDigitizer: remove hit with key: " << key << std::endl; */ + /* } */ + /* hitset->removeHit(key); */ + /* } */ + } // end loop over hitsets + + // ----------------------------------------------- + // Cluster, adapted from intt/InttClusterizer + // ----------------------------------------------- + if (Verbosity() > 0) + std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl; + + //---------- + // Get Nodes + //---------- + + // get the geometry node + PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + if (!geom_container) return; + + //----------- + // Clustering + //----------- + + // loop over the InttHitSet objects + TrkrHitSetContainer::ConstRange hitsetrange = + m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); // from TruthClusterizerBase + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor + TrkrHitSet *hitset = hitsetitr->second; + + // cluster this hitset; all pixels in it are, by definition, part of the same clusters + + if(Verbosity() > 1) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl; + if (Verbosity() > 2) + hitset->identify(); + + // we have a single hitset, get the info that identifies the sensor + int layer = TrkrDefs::getLayer(hitsetitr->first); + int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first); + + // we will need the geometry object for this layer to get the global position + CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); + float pitch = geom->get_strip_y_spacing(); + float length = geom->get_strip_z_spacing(); + + /* // fill a vector of hits to make things easier - gets every hit in the hitset */ + /* std::vector > hitvec; */ + /* TrkrHitSet::ConstRange hitrangei = hitset->getHits(); */ + /* for (TrkrHitSet::ConstIterator hitr = hitrangei.first; */ + /* hitr != hitrangei.second; */ + /* ++hitr) */ + /* { */ + /* hitvec.push_back(std::make_pair(hitr->first, hitr->second)); */ + /* } */ + /* if (Verbosity() > 2) */ + /* std::cout << "hitvec.size(): " << hitvec.size() << std::endl; */ + + /* typedef adjacency_list Graph; */ + /* Graph G; */ + + /* // Find adjacent strips */ + /* for (unsigned int i = 0; i < hitvec.size(); i++) */ + /* { */ + /* for (unsigned int j = i + 1; j < hitvec.size(); j++) */ + /* { */ + /* if (_C__ladder_are_adjacent(hitvec[i], hitvec[j], layer)) */ + /* { */ + /* add_edge(i, j, G); */ + /* } */ + /* } */ + + /* add_edge(i, i, G); */ + /* } */ + + /* // Find the connections between the vertices of the graph (vertices are the rawhits, */ + /* // connections are made when they are adjacent to one another) */ + /* std::vector component(num_vertices(G)); */ + + /* // this is the actual clustering, performed by boost */ + /* connected_components(G, &component[0]); */ + + /* // Loop over the components(hit cells) compiling a list of the */ + /* // unique connected groups (ie. clusters). */ + /* std::set cluster_ids; // unique components */ + + /* std::multimap > clusters; */ + /* for (unsigned int i = 0; i < component.size(); i++) */ + /* { */ + /* cluster_ids.insert(component[i]); // one entry per unique cluster id */ + /* clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id */ + /* } */ + + /* // loop over the cluster ID's and make the clusters from the connected hits */ + /* for (std::set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) */ + /* { */ + /* int clusid = *clusiter; */ + //cout << " intt clustering: add cluster number " << clusid << std::endl; + // get all hits for this cluster ID only + /* std::pair>::iterator, */ + /* std::multimap>::iterator> clusrange = clusters.equal_range(clusid); */ + /* std::multimap>::iterator mapiter = clusrange.first; */ + + // make the cluster directly in the node tree + auto hitsetkey = hitset->getHitSetKey(); + TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitsetkey, clusid); + + if (Verbosity() > 2) + std::cout << "Filling cluster with key " << ckey << std::endl; + + // get the bunch crossing number from the hitsetkey + /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */ + + // determine the size of the cluster in phi and z, useful for track fitting the cluster + std::set phibins; + std::set zbins; + + // determine the cluster position... + double xlocalsum = 0.0; + double ylocalsum = 0.0; + double zlocalsum = 0.0; + unsigned int clus_energy = 0.0; + /* unsigned int clus_maxadc = 0.0; */ + unsigned nhits = 0; + + // aggregate the adc values + double sum_energy {0}; + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) + sum_energy += ihit->getEnergy(); + } + + // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes + // as the SvtxTrack clusters + const double threshold = sum_energy * m_truth_pixelthreshold; + + //std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl; + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) + /* for (mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) */ + { + if (ihit->getEnergy() < threshold) continue; + // mapiter->second.first is the hit key + //cout << " adding hitkey " << mapiter->second.first << std::endl; + int col = InttDefs::getCol( ihit->first); + int row = InttDefs::getRow( (ihit->first); + zbins.insert(col); + phibins.insert(row); + + // mapiter->second.second is the hit + unsigned int hit_adc = ihit->second->getAdc(); + + // now get the positions from the geometry + double local_hit_location[3] = {0., 0., 0.}; + geom->find_strip_center_localcoords(ladder_z_index, row, col, local_hit_location); + + // NOTE: + /* if (_make_e_weights[layer]) */ + /* if ( false ) // the current implementation of the code does not weight by adc values */ + /* // therefore the default here is to use use adc to cut the outliers and nothing else */ + /* { */ + /* xlocalsum += local_hit_location[0] * (double) hit_adc; */ + /* ylocalsum += local_hit_location[1] * (double) hit_adc; */ + /* zlocalsum += local_hit_location[2] * (double) hit_adc; */ + /* } */ + /* else */ + /* { */ + xlocalsum += local_hit_location[0]; + ylocalsum += local_hit_location[1]; + zlocalsum += local_hit_location[2]; + /* } */ + /* if(hit_adc > clus_maxadc) clus_maxadc = hit_adc; */ + clus_energy += hit_adc; + ++nhits; + + // add this cluster-hit association to the association map of (clusterkey,hitkey) + if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl; + if (Verbosity() > 2) + { + std::cout << " From geometry object: hit x " << local_hit_location[0] + << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl; + std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " + << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl; + } + } + + /* static const float invsqrt12 = 1./sqrt(12); */ + // scale factors (phi direction) + /* + they corresponds to clusters of size 1 and 2 in phi + other clusters, which are very few and pathological, get a scale factor of 1 + These scale factors are applied to produce cluster pulls with width unity + */ + + /* float phierror = pitch * invsqrt12; */ + + /* static constexpr std::array scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; */ + /* if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; */ + /* else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; */ + /* else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; */ + /* // z error. All clusters have a z-size of 1. */ + /* const float zerror = length * invsqrt12; */ + + double cluslocaly = NAN; + double cluslocalz = NAN; + + if (_make_e_weights[layer]) + { + cluslocaly = ylocalsum / (double) clus_adc; + cluslocalz = zlocalsum / (double) clus_adc; + } + else + { + cluslocaly = ylocalsum / nhits; + cluslocalz = zlocalsum / nhits; + } + if ( m_cluster_version==4 ){ + auto clus = std::make_unique(); + // Fill the cluster fields + clus->setAdc(clus_adc); + clus->setPhiSize(phibins.size()); + clus->setZSize(1); + + if(Verbosity() > 10) clus->identify(); + + clus->setLocalX(cluslocaly); + clus->setLocalY(cluslocalz); + // silicon has a 1-1 map between hitsetkey and surfaces. So set to + // 0 + clus->setSubSurfKey(0); + + m_hitsetkey_cnt.try_emplace(hitsetkey,0); + unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; + ckey = TrkrDefs::genClusKey(hitsetkey, cnt); + m_truthclusters->addClusterSpecifyKey(ckey, clus.release()); + m_current_track->addCluster(ckey); + ++cnt; + /* m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); */ + + } + } // end loop over hitsets + + return; +} diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.h b/simulation/g4simulation/g4intt/PHG4InttHitReco.h index c2fc804def..d4b8250345 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.h +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.h @@ -56,6 +56,28 @@ class PHG4InttHitReco : public SubsysReco, public PHParameterInterface gsl_vector *m_LocalOutVec = nullptr; gsl_vector *m_PathVec = nullptr; gsl_vector *m_SegmentVec = nullptr; + + // needed for clustering truth tracks + private: + TrkrTruthTrackContainer* m_truthtracks { nullptr }; // output truth tracks + TrkrClusterContainer* m_truthclusters { nullptr }; // output clusters indexed to TrkrDefs::cluskeys in m_truthtracks + PHG4TruthInfoContainer* m_truthinfo { nullptr }; + int m_trkid { -1 }; + bool m_is_emb { false }; + TrkrTruthTrack* m_current_track { nullptr }; + const int m_cluster_version { 4 }; + TrkrHitSetContainer* m_truth_hits; // generate and delete a container for each truth track + std::map m_hitsetkey_cnt {}; // counter for making ckeys form hitsetkeys + + void truthcheck_g4hit ( PHG4Hit*, PHCompositeNode* topNode ); + void addtruthhitset ( TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons ); + void clusterize_truthtrack ( PHCompositeNode* topNode ); + void end_event_truthcluster ( PHCompositeNode* topNode ); + + double m_truth_pixelthreshold { 0.01 }; + public: + void set_truth_pixelthreshold (double val) { m_truth_pixelthreshold = val; }; + }; #endif diff --git a/simulation/g4simulation/g4mvtx/Makefile.am b/simulation/g4simulation/g4mvtx/Makefile.am index d624f7d609..bbaed214b8 100644 --- a/simulation/g4simulation/g4mvtx/Makefile.am +++ b/simulation/g4simulation/g4mvtx/Makefile.am @@ -31,8 +31,7 @@ pkginclude_HEADERS = \ PHG4MvtxHitReco.h \ PHG4MvtxSubsystem.h \ PHG4EICMvtxSubsystem.h \ - PHG4MvtxDigitizer.h \ - PHG4MvtxTruthClusterizer.h + PHG4MvtxDigitizer.h libg4mvtx_la_SOURCES = \ PHG4MvtxHitReco.cc \ @@ -46,8 +45,7 @@ libg4mvtx_la_SOURCES = \ PHG4MvtxDigitizer.cc \ PHG4MvtxCable.cc \ PHG4MvtxServiceStructure.cc \ - PHG4MvtxSupport.cc \ - PHG4MvtxTruthClusterizer.cc + PHG4MvtxSupport.cc ################################################ # linking tests diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 43f2de2b50..1aacf987cf 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -16,10 +16,12 @@ #include #include // for TrkrHit -#include -#include +#include #include #include +#include +#include +#include #include // for PHG4CylinderGeom #include @@ -51,6 +53,7 @@ #include #include // for allocator_tra... #include // for vector +#include // for vector PHG4MvtxHitReco::PHG4MvtxHitReco(const std::string &name, const std::string &detector) : SubsysReco(name) @@ -60,7 +63,7 @@ PHG4MvtxHitReco::PHG4MvtxHitReco(const std::string &name, const std::string &det , m_tmax(5000.) , m_strobe_width(5.) , m_strobe_separation(0.) - , m_truthclusterizer { new PHG4MvtxTruthClusterizer } + , m_truth_hits { new TrkrHitSetContainerv1 } { if (Verbosity()) { @@ -149,7 +152,30 @@ int PHG4MvtxHitReco::InitRun(PHCompositeNode *topNode) trkrnode->addNode(newNode); } - m_truthclusterizer->init_run(topNode, Verbosity()); + // get the nodes for the truth clustering + m_truthtracks = findNode::getClass(topNode, "TRKR_TRUTHTRACKCONTAINER"); + if (!m_truthtracks) + { + PHNodeIterator dstiter(dstNode); + m_truthtracks = new TrkrTruthTrackContainerv1(); + auto newNode = new PHIODataNode(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject"); + dstNode->addNode(newNode); + } + + m_truthclusters = findNode::getClass(topNode, "TRKR_TRUTHCLUSTERCONTAINER"); + if (!m_truthclusters) + { + m_truthclusters = new TrkrClusterContainerv4; + auto newNode = new PHIODataNode(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject"); + dstNode->addNode(newNode); + } + + m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_truthinfo) + { + std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl; + assert(m_truthinfo); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -226,7 +252,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) // get hit auto g4hit = g4hit_it->second; - m_truthclusterizer->check_g4hit(g4hit); + truthcheck_g4hit(g4hit, topNode); //cout << "From PHG4MvtxHitReco: Call hit print method: " << std::endl; if (Verbosity() > 4) @@ -604,7 +630,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) double hitenergy = venergy[i1].first * TrkrDefs::MvtxEnergyScaleup; hit->addEnergy(hitenergy); - m_truthclusterizer->addhitset(hitsetkey, hitkey, hitenergy); + addtruthhitset(hitsetkey, hitkey, hitenergy); if (Verbosity() > 0) std::cout << " added hit " << hitkey << " to hitset " << hitsetkey << " with strobe id " << strobe << " in layer " << layer @@ -634,8 +660,38 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) // spit out the truth clusters - if (Verbosity() > 5) m_truthclusterizer->print_clusters(); - m_truthclusterizer->end_of_event(); + end_event_truthcluster(topNode); + + // FIXME + if (true) { + /* if (Verbosity() > 3) { */ + int nclusprint = -1; + std::cout << PHWHERE << ": content of clusters " << std::endl; + auto& tmap = m_truthtracks->getMap(); + std::cout << " Number of tracks: " << tmap.size() << std::endl; + for (auto& _pair : tmap) { + auto& track = _pair.second; + + printf("id(%2i) phi:eta:pt(", (int)track->getTrackid()); + std::cout << "phi:eta:pt("; + printf("%5.2f:%5.2f:%5.2f", track->getPhi(), track->getPseudoRapidity(), track->getPt()); + /* Form("%5.2:%5.2:%5.2", track->getPhi(), track->getPseudoRapidity(), track->getPt()) */ + //<getPhi()<<":"<getPseudoRapidity()<<":"<getPt() + std::cout << ") nclusters(" << track->getClusters().size() <<") "; + int nclus = 0; + for (auto cluskey : track->getClusters()) { + std::cout << " " + << ((int) TrkrDefs::getHitSetKeyFromClusKey(cluskey)) <<":index(" << + ((int) TrkrDefs::getClusIndex(cluskey)) << ")" << std::endl; + ++nclus; + if (nclusprint > 0 && nclus >= nclusprint) { + std::cout << " ... "; + break; + } + } + } + std::cout << PHWHERE << " ----- end of clusters " << std::endl; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -705,5 +761,345 @@ TrkrDefs::hitsetkey PHG4MvtxHitReco::zero_strobe_bits(TrkrDefs::hitsetkey hitset } PHG4MvtxHitReco::~PHG4MvtxHitReco() { - delete m_truthclusterizer; + delete m_truth_hits; +} + +void PHG4MvtxHitReco::truthcheck_g4hit(PHG4Hit* hit, PHCompositeNode* topNode) { + int new_trkid = (hit==nullptr) ? -1 : hit->get_trkid(); + bool is_new_track = (new_trkid != m_trkid); + if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl; + if (m_is_emb) { + clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + m_current_track = nullptr; + } + m_trkid = new_trkid; // although m_current_track won't catch up until update_track is called + m_is_emb = m_truthinfo->isEmbeded(m_trkid); + if (m_is_emb) { + m_current_track = m_truthtracks->getTruthTrack(m_trkid, m_truthinfo); + } +} + +void PHG4MvtxHitReco::end_event_truthcluster ( PHCompositeNode* topNode ) { + if (m_is_emb) { + clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + m_current_track = nullptr; + m_trkid = -1; + m_is_emb = false; + } + m_hitsetkey_cnt.clear(); +} + +void PHG4MvtxHitReco::addtruthhitset( + TrkrDefs::hitsetkey hitsetkey, + TrkrDefs::hitkey hitkey, + float neffelectrons) +{ + if (!m_is_emb) return; + TrkrHitSetContainer::Iterator hitsetit = m_truth_hits->findOrAddHitSet(hitsetkey); + // See if this hit already exists + TrkrHit *hit = nullptr; + hit = hitsetit->second->getHit(hitkey); + if (!hit) + { + // create a new one + hit = new TrkrHitv2(); + hitsetit->second->addHitSpecificKey(hitkey, hit); + } + // Either way, add the energy to it -- adc values will be added at digitization + hit->addEnergy(neffelectrons); +} + +void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { + // clusterize the mvtx hits in m_truth_hits, put them in m_truthclusters, and put the id's in m_current_track + // ---------------------------------------------------------------------------------------------------- + // Digitization -- simplified from g4mvtx/PHG4MvtxDigitizer -- + // ---------------------------------------------------------------------------------------------------- + + /* // We want all hitsets for the Mvtx */ + /* TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); */ + /* for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; */ + /* hitset_iter != hitset_range.second; */ + /* ++hitset_iter) */ + /* { */ + /* // we have an iterator to one TrkrHitSet for the mvtx from the trkrHitSetContainer */ + /* // get the hitset key so we can find the layer */ + /* TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; */ + /* int layer = TrkrDefs::getLayer(hitsetkey); */ + /* // FIXME */ + /* /1* if (Verbosity() > 1) std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; *1/ */ + /* std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; */ + + /* // get all of the hits from this hitset */ + /* TrkrHitSet *hitset = hitset_iter->second; */ + /* TrkrHitSet::ConstRange hit_range = hitset->getHits(); */ + /* std::set hits_rm; */ + /* for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; */ + /* hit_iter != hit_range.second; */ + /* ++hit_iter) */ + /* { */ + /* TrkrHit *hit = hit_iter->second; */ + + /* // Convert the signal value to an ADC value and write that to the hit */ + /* // Unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); */ + /* if (Verbosity() > 0) */ + /* std::cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; */ + /* // Remove the hits with energy under threshold */ + /* bool rm_hit = false; */ + /* // FIXME: */ + /* double _energy_threshold = 0.; // FIXME */ + /* const double dummy_pixel_thickness = 0.001; */ + /* const double mip_e = 0.003876; */ + /* double _energy_scale = mip_e * dummy_pixel_thickness; // FIXME: note: this doesn't actually */ + /* // matter either here or for the Svtx Tracks -- the energy is digital -- either the hit is there or it isn't */ + /* double _max_adc = 255; */ + /* if ((hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup) < _energy_threshold) */ + /* { */ + /* if (Verbosity() > 0) std::cout << " remove hit, below energy threshold of " << _energy_threshold << std::endl; */ + /* rm_hit = true; */ + /* } */ + /* unsigned short adc = (unsigned short) (hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup * _energy_scale)); */ + /* if (adc > _max_adc) adc = _max_adc; */ + /* hit->setAdc(adc); */ + + /* if (rm_hit) hits_rm.insert(hit_iter->first); */ + /* } */ + + /* for (const auto &key : hits_rm) */ + /* { */ + /* if (Verbosity() > 0) std::cout << " PHG4MvtxDigitizer: remove hit with key: " << key << std::endl; */ + /* hitset->removeHit(key); */ + /* } */ + /* } */ + + // ---------------------------------------------------------------------------------------------------- + // Prune hits -- simplified from mvtx/MvtxHitReco + // ---------------------------------------------------------------------------------------------------- + std::multimap hitset_multimap; // will map (bare hitset, hitset with strobe) + std::set bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero) + + TrkrHitSetContainer::ConstRange hitsetrange = m_truth_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); // actually m_truth_hits can only have MVTX hits at this point... + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + auto hitsetkey = hitsetitr->first; + + // get the hitsetkey value for strobe 0 + unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); + unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first); + unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); + auto bare_hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, 0); + + hitset_multimap.insert(std::make_pair(bare_hitsetkey, hitsetkey)); + bare_hitset_set.insert(bare_hitsetkey); + + if(Verbosity() > 0) std::cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; + } + + // Now consolidate all hits into the hitset with strobe 0, and delete the other hitsets + //============================================================== + for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it) + { + auto bare_hitsetkey = *bare_it; + TrkrHitSet* bare_hitset = (m_truth_hits->findOrAddHitSet(bare_hitsetkey))->second; + if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl; + + auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey); + for(auto it = bare_hitsetrange.first; it != bare_hitsetrange.second; ++ it) + { + auto hitsetkey = it->second; + + int strobe = MvtxDefs::getStrobeId(hitsetkey); + if(strobe != 0) + { + if(Verbosity() > 0) std::cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; + + // copy all hits to the hitset with strobe 0 + TrkrHitSet* hitset = m_truth_hits->findHitSet(hitsetkey); + + if(Verbosity() > 0) + std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl; + + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + auto hitkey = hitr->first; + if(Verbosity() > 0) std::cout << " found hitkey " << hitkey << std::endl; + // if it is already there, leave it alone, this is a duplicate hit + auto tmp_hit = bare_hitset->getHit(hitkey); + if(tmp_hit) + { + if(Verbosity() > 0) std::cout << " hitkey " << hitkey << " is already in bare hitsest, do not copy" << std::endl; + continue; + } + + // otherwise copy the hit over + if(Verbosity() > 0) std::cout << " copying over hitkey " << hitkey << std::endl; + auto old_hit = hitr->second; + TrkrHit *new_hit = new TrkrHitv2(); + new_hit->setAdc(old_hit->getAdc()); + bare_hitset->addHitSpecificKey(hitkey, new_hit); + } + + // all hits are copied over to the strobe zero hitset, remove this hitset + m_truth_hits->removeHitSet(hitsetkey); + } + } + } + + // ---------------------------------------------------------------------------------------------------- + // cluster hits -- simplified from mvtx/MvtxClusterizer + // ---------------------------------------------------------------------------------------------------- + PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_MVTX"); + if (!geom_container) { + std::cout << PHWHERE << std::endl; + std::cout << "WARNING: cannot find the geometry CYLINDERGEOM_MVTX" << std::endl; + m_truth_hits->Reset(); + return; + } + + //----------- + // Clustering + //----------- + + // loop over each MvtxHitSet object (chip) + hitsetrange = m_truth_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { // hitsetitr : pair(TrkrDefs::hitsetkey, TrkrHitSet>; TrkrHitSet : map + TrkrHitSet *hitset = hitsetitr->second; // hitset : map + + // FIXME + /* if(Verbosity() > 0) */ + if (true) + { + unsigned int layer = TrkrDefs::getLayer (hitsetitr ->first); + unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first); + unsigned int chip = MvtxDefs::getChipId (hitsetitr ->first); + unsigned int strobe = MvtxDefs::getStrobeId (hitsetitr ->first); + std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << std::endl; + } + + if (Verbosity() > 2) + hitset->identify(); + + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + + auto hitsetkey = hitset->getHitSetKey(); + auto ckey = TrkrDefs::genClusKey(hitsetkey, 0); // there is only one cluster made per cluskey + + // determine the size of the cluster in phi and z + std::set phibins; + std::set zbins; + + // determine the cluster position... + double locxsum = 0.; + double loczsum = 0.; + + double locclusx = NAN; + double locclusz = NAN; + + // we need the geometry object for this layer to get the global positions + int layer = TrkrDefs::getLayer(ckey); + auto layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); + if (!layergeom) + exit(1); + + + // make a tunable threshhold for energy in a given hit + // -- percentage of someting? (total cluster energy) + double sum_energy; + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { + sum_energy += ihit->second->getEnergy(); + } + const double threshhold = sum_energy / 100.; //FIXME -- tune this as needed + /* const unsigned int npixels = std::distance( hitrangei.first, hitrangei.second ); */ + // to tune this parameter: run a bunch of tracks and compare truth sizes and reco sizes, + // should come out the same + double npixels {0.}; + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) + { + if (ihit->getEnergy()first); + int row = MvtxDefs::getRow( ihit->first); + zbins.insert(col); + phibins.insert(row); + + // get local coordinates, in stave reference frame, for hit + auto local_coords = layergeom->get_local_coords_from_pixel(row,col); + + /* + manually offset position along y (thickness of the sensor), + to account for effective hit position in the sensor, resulting from diffusion. + Effective position corresponds to 1um above the middle of the sensor + */ + local_coords.SetY( 1e-4 ); + + // update cluster position + locxsum += local_coords.X(); + loczsum += local_coords.Z(); + // add the association between this cluster key and this hitkey to the table + } //mapiter + + // This is the local position + locclusx = locxsum / npixels; + locclusz = loczsum / npixels; + + const double pitch = layergeom->get_pixel_x(); + const double length = layergeom->get_pixel_z(); + const double phisize = phibins.size() * pitch; + const double zsize = zbins.size() * length; + + // FIXME + if (true) { + /* if(Verbosity() > 0) { */ + std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " << zsize + << " local x " << locclusx << " local y " << locclusz + << std::endl; + } + + // ok force it use use cluster version v4 for now (Valgrind is not happy with application of v5) + /* if (m_cluster_version==4){ */ + if (m_cluster_version == 4) { + auto clus = std::make_unique(); + clus->setAdc(pixels); + clus->setLocalX(locclusx); + clus->setLocalY(locclusz); + + clus->setPhiSize(phibins.size()); + clus->setZSize(zbins.size()); + // All silicon surfaces have a 1-1 map to hitsetkey. + // So set subsurface key to 0 + clus->setSubSurfKey(0); + + //FIXME + if (true) + /* if (Verbosity() > 2) */ + clus->identify(); + + // get the count of how many clusters have allready been added to this hitsetkey (possibly from other embedded tracks tracks) + m_hitsetkey_cnt.try_emplace(hitsetkey,0); + unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; + ckey = TrkrDefs::genClusKey(hitsetkey, cnt); + //FIXME + if (true) std::cout << " Adding key PLUM to hitsetkey("< 4) std::cout << " Adding key PLUM to hitsetkey("<addClusterSpecifyKey(ckey, clus.release()); + m_current_track->addCluster(ckey); + ++cnt; + } else { + std::cout << PHWHERE << std::endl; + std::cout << "Error: only cluster version 4 allowed." << std::endl; + } // loop over hitsets + } + m_truth_hits->Reset(); + return; } diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 09a152c70e..76cc4870ce 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -12,11 +12,14 @@ #include // for unique_ptr #include -class PHG4MvtxTruthClusterizer; class PHCompositeNode; -class TrkrTruthTrackContainer; +class PHG4MvtxTruthClusterizer; +class PHG4TruthInfoContainer; class TrkrClusterContainer; -class MvtxHitPruner; +class TrkrHitSetContainer; +class TrkrTruthTrack; +class TrkrTruthTrackContainer; +class PHG4Hit; class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface { @@ -42,12 +45,7 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface //! parameters void SetDefaultParameters() override; - //void set_HitPruner(MvtxHitPruner* - void set_HitPruner(MvtxHitPruner* _) { m_hit_pruner = _; }; - private: - MvtxHitPruner* m_hit_pruner { nullptr }; - std::pair generate_alpide_pulse(const double energy_deposited); double generate_strobe_zero_tm_start(); @@ -67,8 +65,6 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface bool m_in_sphenix_srdo = false; - PHG4MvtxTruthClusterizer *m_truthclusterizer { nullptr }; - class Deleter { public: @@ -77,6 +73,23 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface }; std::unique_ptr m_rng; + + // needed for clustering truth tracks + private: + TrkrTruthTrackContainer* m_truthtracks { nullptr }; // output truth tracks + TrkrClusterContainer* m_truthclusters { nullptr }; // output clusters indexed to TrkrDefs::cluskeys in m_truthtracks + PHG4TruthInfoContainer* m_truthinfo { nullptr }; + int m_trkid { -1 }; + bool m_is_emb { false }; + TrkrTruthTrack* m_current_track { nullptr }; + const int m_cluster_version { 4 }; + TrkrHitSetContainer* m_truth_hits; // generate and delete a container for each truth track + std::map m_hitsetkey_cnt {}; // counter for making ckeys form hitsetkeys + + void truthcheck_g4hit ( PHG4Hit*, PHCompositeNode* topNode ); + void addtruthhitset ( TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons ); + void clusterize_truthtrack ( PHCompositeNode* topNode ); + void end_event_truthcluster ( PHCompositeNode* topNode ); }; #endif diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc index c40e8bf7b1..0dc7ded5d9 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc @@ -24,35 +24,14 @@ #include #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#pragma GCC diagnostic ignored "-Wshadow" -#include -#include -#pragma GCC diagnostic pop - -using boost::add_edge; -using boost::concepts::Graph; -using boost::concepts::Graph; -using boost::connected_components; -using boost::num_vertices; -using boost::undirectedS; -using boost::adjacency_list; -using boost::vecS; - -using std::cout; -using std::endl; -using std::make_pair; using std::set; using std::map; using std::multimap; -using std::vector; -using std::make_pair; int PHG4MvtxTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) { + // turn m_hits into clusters, filled into clusters std::cout << " clusters " << (clusters == nullptr) << std::endl; - // digitize MVTX _D__DigitizeMvtxLadderCells(); // adapted from PHG4MvtxDigitizer _P__MvtxHitPruner(); // adapted from mvtx/MvtxHitPruner _C__ClusterMvtx(clusters); // adapted from mvtx/MvtxClusterizer @@ -73,17 +52,17 @@ void PHG4MvtxTruthClusterizer::init_run(PHCompositeNode*& _topNode, int _verbosi } void PHG4MvtxTruthClusterizer::check_g4hit(PHG4Hit* hit) { - if (m_verbosity>10) std::cout << " -> Checking PHG4Hit" << std::endl; + if (Verbosity()>10) std::cout << " -> Checking PHG4Hit" << std::endl; check_g4hit_status(hit); if (m_was_emb) { - if (m_verbosity>3) { + if (Verbosity()>3) { std::cout << PHWHERE << std::endl << " -> Pre clustering " << (int) m_hits->size() << " hits" << std::endl; } TrkrClusterContainerv4 clusters{}; clusterize_hits (&clusters); transfer_clusters (&clusters); - if (m_verbosity>3) { + if (Verbosity()>3) { std::cout << PHWHERE << std::endl << " -> Clustered " << (int) clusters.size() << " clusters" << std::endl; } @@ -94,7 +73,7 @@ void PHG4MvtxTruthClusterizer::check_g4hit(PHG4Hit* hit) { void PHG4MvtxTruthClusterizer::end_of_event() { check_g4hit(nullptr); // flush out last data if ended in truth track m_hitsetkey_cnt.clear(); - if (m_verbosity>2) { + if (Verbosity()>2) { std::cout << PHWHERE << " :: tracks with clusters after clustering in MVTX" << std::endl; for (auto& track : m_truthtracks->getMap()) { std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); @@ -115,7 +94,7 @@ int PHG4MvtxTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { - cout << PHWHERE << "DST Node missing, doing nothing." << endl; + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; return Fun4AllReturnCodes::ABORTRUN; } @@ -127,16 +106,16 @@ int PHG4MvtxTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { - cout << "====================== PHG4MvtxTruthClusterizer copy of PHG4MvtxDigitizer::InitRun() =====================" << endl; + std::cout << "====================== PHG4MvtxTruthClusterizer copy of PHG4MvtxDigitizer::InitRun() =====================" << std::endl; for (auto &miter : _max_adc) { - cout << " Max ADC in Layer #" << miter.first << " = " << miter.second << endl; + std::cout << " Max ADC in Layer #" << miter.first << " = " << miter.second << std::endl; } for (auto &miter : _energy_scale) { - cout << " Energy per ADC in Layer #" << miter.first << " = " << 1.0e6 * miter.second << " keV" << endl; + std::cout << " Energy per ADC in Layer #" << miter.first << " = " << 1.0e6 * miter.second << " keV" << std::endl; } - cout << "===========================================================================" << endl; + std::cout << "===========================================================================" << std::endl; } return Fun4AllReturnCodes::EVENT_OK; @@ -149,7 +128,7 @@ void PHG4MvtxTruthClusterizer::_D__CalculateMvtxLadderCellADCScale(PHCompositeNo if (!geom_container) return; - if (Verbosity()) cout << "Found CYLINDERGEOM_MVTX node" << endl; + if (Verbosity()) std::cout << "Found CYLINDERGEOM_MVTX node" << std::endl; PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end(); for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first; @@ -167,7 +146,7 @@ void PHG4MvtxTruthClusterizer::_D__CalculateMvtxLadderCellADCScale(PHCompositeNo float mip_e = 0.003876 * minpath; if (Verbosity()) - cout << "mip_e = " << mip_e << endl; + std::cout << "mip_e = " << mip_e << std::endl; if (_max_adc.find(layer) == _max_adc.end()) { @@ -194,11 +173,11 @@ void PHG4MvtxTruthClusterizer::_D__DigitizeMvtxLadderCells() { hitset_iter != hitset_range.second; ++hitset_iter) { - // we have an itrator to one TrkrHitSet for the mvtx from the trkrHitSetContainer + // we have an iterator to one TrkrHitSet for the mvtx from the trkrHitSetContainer // get the hitset key so we can find the layer TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; int layer = TrkrDefs::getLayer(hitsetkey); - if (Verbosity() > 1) cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << endl; + if (Verbosity() > 1) std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; // get all of the hits from this hitset TrkrHitSet *hitset = hitset_iter->second; @@ -211,9 +190,9 @@ void PHG4MvtxTruthClusterizer::_D__DigitizeMvtxLadderCells() { TrkrHit *hit = hit_iter->second; // Convert the signal value to an ADC value and write that to the hit - //unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); + // Unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); if (Verbosity() > 0) - cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; + std::cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; // Remove the hits with energy under threshold bool rm_hit = false; if ((hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup) < _energy_threshold) @@ -230,7 +209,7 @@ void PHG4MvtxTruthClusterizer::_D__DigitizeMvtxLadderCells() { for (const auto &key : hits_rm) { - if (Verbosity() > 0) cout << " PHG4MvtxDigitizer: remove hit with key: " << key << endl; + if (Verbosity() > 0) std::cout << " PHG4MvtxDigitizer: remove hit with key: " << key << std::endl; hitset->removeHit(key); } } @@ -261,7 +240,7 @@ int PHG4MvtxTruthClusterizer::_P__MvtxHitPruner() { hitset_multimap.insert(std::make_pair(bare_hitsetkey, hitsetkey)); bare_hitset_set.insert(bare_hitsetkey); - if(Verbosity() > 0) cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; + if(Verbosity() > 0) std::cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; } // Now consolidate all hits into the hitset with strobe 0, and delete the other hitsets @@ -280,7 +259,7 @@ int PHG4MvtxTruthClusterizer::_P__MvtxHitPruner() { int strobe = MvtxDefs::getStrobeId(hitsetkey); if(strobe != 0) { - if(Verbosity() > 0) cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << endl; + if(Verbosity() > 0) std::cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; // copy all hits to the hitset with strobe 0 TrkrHitSet* hitset = m_hits->findHitSet(hitsetkey); @@ -323,37 +302,10 @@ int PHG4MvtxTruthClusterizer::_P__MvtxHitPruner() { // --------------------------------------- // mvtx/MvtxClusterizer _C__ // --------------------------------------- -bool PHG4MvtxTruthClusterizer::_C__are_adjacent(const std::pair &lhs, const std::pair &rhs) -{ - if (GetZClustering()) - { - // column is first, row is second - if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) <= 1) - { - if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) - { - return true; - } - } - } - else - { - if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) == 0) - { - if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1) - { - return true; - } - } - } - - return false; -} - void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterlist) { // already inherit m_hits from class if (Verbosity() > 0) - cout << "Entering PHG4MvtxTruthClusterizer::_C__ MvtxClusterizer::ClusterMvtx " << endl; + std::cout << "Entering PHG4MvtxTruthClusterizer::_C__ MvtxClusterizer::ClusterMvtx " << std::endl; PHG4CylinderGeomContainer* geom_container = findNode::getClass(m_topNode, "CYLINDERGEOM_MVTX"); if (!geom_container) return; @@ -368,8 +320,8 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr) - { - TrkrHitSet *hitset = hitsetitr->second; + { // hitsetitr : pair(TrkrDefs::hitsetkey, TrkrHitSet>; TrkrHitSet : map + TrkrHitSet *hitset = hitsetitr->second; // hitset : map if(Verbosity() > 0) { @@ -377,77 +329,15 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first); unsigned int chip = MvtxDefs::getChipId (hitsetitr ->first); unsigned int strobe = MvtxDefs::getStrobeId (hitsetitr ->first); - cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << endl; + std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << std::endl; } if (Verbosity() > 2) hitset->identify(); - // fill a vector of hits to make things easier - std::vector > hitvec; - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - hitvec.push_back(make_pair(hitr->first, hitr->second)); - } - if (Verbosity() > 2) cout << "hitvec.size(): " << hitvec.size() << endl; - - if(Verbosity() > 0) - { - for (unsigned int i = 0; i < hitvec.size(); i++) - { - auto hitkey = hitvec[i].first; - auto row = MvtxDefs::getRow(hitkey); - auto col = MvtxDefs::getCol(hitkey); - std::cout << " hitkey " << hitkey << " row " << row << " col " << col << std::endl; - } - } - - // do the clustering - typedef adjacency_list Graph; - Graph G; - - // loop over hits in this chip - for (unsigned int i = 0; i < hitvec.size(); i++) - { - for (unsigned int j = 0; j < hitvec.size(); j++) - { - if (_C__are_adjacent(hitvec[i], hitvec[j])) - add_edge(i, j, G); - } - } - - // Find the connections between the vertices of the graph (vertices are the rawhits, - // connections are made when they are adjacent to one another) - vector component(num_vertices(G)); - - // this is the actual clustering, performed by boost - connected_components(G, &component[0]); - - // Loop over the components(hits) compiling a list of the - // unique connected groups (ie. clusters). - set cluster_ids; // unique components - //multimap clusters; - multimap > clusters; - for (unsigned int i = 0; i < component.size(); i++) - { - cluster_ids.insert(component[i]); - clusters.insert(make_pair(component[i], hitvec[i])); - } - int total_clusters = 0; - for (set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) - { - int clusid = *clusiter; - auto clusrange = clusters.equal_range(clusid); - - if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl; - - ++total_clusters; - auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); + auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), 0); // there is only one cluster made per cluskey // determine the size of the cluster in phi and z set phibins; @@ -456,7 +346,6 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli // determine the cluster position... double locxsum = 0.; double loczsum = 0.; - const unsigned int nhits = std::distance( clusrange.first, clusrange.second ); double locclusx = NAN; double locclusz = NAN; @@ -467,15 +356,16 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli if (!layergeom) exit(1); - for ( auto mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) + const unsigned int nhits = std::distance( hitrangei.first, hitrangei.second ); + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { // size - int col = MvtxDefs::getCol( (mapiter->second).first); - int row = MvtxDefs::getRow( (mapiter->second).first); + int col = MvtxDefs::getCol( ihit->first); + int row = MvtxDefs::getRow( ihit->first); zbins.insert(col); phibins.insert(row); - // get local coordinates, in stae reference frame, for hit + // get local coordinates, in stave reference frame, for hit auto local_coords = layergeom->get_local_coords_from_pixel(row,col); /* @@ -500,44 +390,12 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli const double phisize = phibins.size() * pitch; const double zsize = zbins.size() * length; - /* static const double invsqrt12 = 1./std::sqrt(12); */ - - // scale factors (phi direction) - /* - they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in phi and z - other clusters, which are very few and pathological, get a scale factor of 1 - These scale factors are applied to produce cluster pulls with width unity - */ - - /* double phierror = pitch * invsqrt12; */ - - /* static constexpr std::array scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }}; */ - /* if ( phibins.size() == 1 && zbins.size() == 1 ) phierror*=scalefactors_phi[0]; */ - /* else if( phibins.size() == 2 && zbins.size() == 1 ) phierror*=scalefactors_phi[1]; */ - /* else if( phibins.size() == 1 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; */ - /* else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0]; */ - /* else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1]; */ - /* else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2]; */ - /* else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3]; */ - - - // scale factors (z direction) - /* - they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z and phi - other clusters, which are very few and pathological, get a scale factor of 1 - */ - /* static constexpr std::array scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }}; */ - /* double zerror = length*invsqrt12; */ - /* if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0]; */ - /* else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1]; */ - /* else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2]; */ - /* else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3]; */ - - if(Verbosity() > 0) - cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize + if(Verbosity() > 0) { + std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize << " zbins " << zbins.size() << " length " << length << " zsize " << zsize << " local x " << locclusx << " local y " << locclusz - << endl; + << std::endl; + } // ok force it use use cluster version v4 for now (Valgrind is not happy with application of v5) /* if (m_cluster_version==4){ */ @@ -557,30 +415,11 @@ void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterli clus->identify(); m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - } - /* }else if(m_cluster_version==5){ */ - /* auto clus = std::make_unique(); */ - /* clus->setAdc(nhits); */ - /* clus->setMaxAdc(1); */ - /* clus->setLocalX(locclusx); */ - /* clus->setLocalY(locclusz); */ - /* clus->setPhiError(phierror); */ - /* clus->setZError(zerror); */ - /* clus->setPhiSize(phibins.size()); */ - /* clus->setZSize(zbins.size()); */ - /* // All silicon surfaces have a 1-1 map to hitsetkey. */ - /* // So set subsurface key to 0 */ - /* clus->setSubSurfKey(0); */ - - /* if (Verbosity() > 2) */ - /* clus->identify(); */ - - /* m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); */ - /* } */ - } // clusitr loop + } else { + std::cout << PHWHERE << std::endl; + std::cout << "Error: only cluster version 4 allowed." << std::endl; } // loop over hitsets - + } return; - } From 1adeeb719ab7961303bb8b3c92987e029bf44535 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Fri, 7 Apr 2023 12:17:18 -0400 Subject: [PATCH 152/468] Small commit to code -- efficiency of lookup in adc value --- .../g4simulation/g4intt/PHG4InttDigitizer.cc | 27 +++++++------------ .../g4simulation/g4intt/PHG4InttDigitizer.h | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index 816c6ffa0b..36585dbb3b 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -264,16 +264,14 @@ void PHG4InttDigitizer::DigitizeLadderCells(PHCompositeNode *topNode) } const float mip_e = _energy_scale[layer]; - std::vector > vadcrange = _max_fphx_adc[layer]; + std::vector& vadcrange = _max_fphx_adc[layer]; + + // c++ upper_bound finds the bin location above the test value (or vadcrange.end() if there isn't one) + auto irange = std::upper_bound(vadcrange.begin(), vadcrange.end(), + hit->getEnergy() / TrkrDefs::InttEnergyScaleup * (double) mip_e); + int adc = (irange-vadcrange.begin())-1; + if (adc == -1) adc = 0; - int adc = 0; - for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) - { - if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup < vadcrange[irange].second * (double) mip_e) - { - adc = (unsigned short) irange; - } - } hit->setAdc(adc); if (Verbosity() > 2) @@ -343,17 +341,10 @@ void PHG4InttDigitizer::set_adc_scale(const int &layer, const std::vector > vadcrange; + std::vector vadcrange; for (unsigned int irange = 0; irange < userrange.size(); ++irange) { - if (irange == userrange.size() - 1) - { - vadcrange.push_back(std::make_pair(userrange[irange], FLT_MAX)); - } - else - { - vadcrange.push_back(std::make_pair(userrange[irange], userrange[irange + 1])); - } + vadcrange.push_back(userrange[irange]); } _max_fphx_adc.insert(std::make_pair(layer, vadcrange)); } diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.h b/simulation/g4simulation/g4intt/PHG4InttDigitizer.h index a2b1de81c0..e9774da632 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.h +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.h @@ -57,7 +57,7 @@ class PHG4InttDigitizer : public SubsysReco, public PHParameterInterface //SvtxHitMap *_hitmap; const unsigned int nadcbins = 8; - std::map > > _max_fphx_adc; + std::map> _max_fphx_adc; unsigned int m_nCells = 0; unsigned int m_nDeadCells = 0; From 6bdfd516fc72eed7ec497c847e7db392b6a6c7af Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 13:35:17 -0400 Subject: [PATCH 153/468] allow uniform magnetic field in outer hcal --- .../g4simulation/g4ohcal/PHG4OHCalDetector.cc | 19 ++++++++++++++----- .../g4ohcal/PHG4OHCalFieldSetup.cc | 3 ++- .../g4ohcal/PHG4OHCalFieldSetup.h | 3 ++- .../g4ohcal/PHG4OHCalSteppingAction.cc | 17 +++++++---------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc index bb969705bb..bc01887ca2 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc @@ -11,6 +11,10 @@ #include #include +#include +#include + +#include #include #include @@ -47,11 +51,9 @@ #include #include #include // for unique_ptr -#include // for __decay_and_strip<>::_... #include // for pair, make_pair #include // for vector, vector<>::iter... -class G4Material; class PHCompositeNode; PHG4OHCalDetector::PHG4OHCalDetector(PHG4Subsystem *subsys, PHCompositeNode *Node, PHParameters *parames, const std::string &dnam) @@ -68,7 +70,9 @@ PHG4OHCalDetector::PHG4OHCalDetector(PHG4Subsystem *subsys, PHCompositeNode *Nod { gdml_config = PHG4GDMLUtility::GetOrMakeConfigNode(Node); assert(gdml_config); - + PHFieldConfig *fieldconf = findNode::getClass(Node, PHFieldUtility::GetDSTConfigNodeName()); + if (fieldconf->get_field_config() != PHFieldConfig::kFieldUniform) + { m_FieldSetup = new PHG4OHCalFieldSetup( m_Params->get_string_param("IronFieldMapPath"), m_Params->get_double_param("IronFieldMapScale"), @@ -76,6 +80,7 @@ PHG4OHCalDetector::PHG4OHCalDetector(PHG4Subsystem *subsys, PHCompositeNode *Nod m_OuterRadius + 10*cm, // add 10 cm to make sure fieldmap with 2x2 grid covers it m_SizeZ/2. + 10*cm // div by 2 bc G4 convention ); + } } PHG4OHCalDetector::~PHG4OHCalDetector() @@ -124,8 +129,9 @@ void PHG4OHCalDetector::ConstructMe(G4LogicalVolume *logicWorld) // allow installing new G4 subsystem installed inside the HCal envelope via macros, in particular its support rings. PHG4Subsystem *mysys = GetMySubsystem(); if (mysys) + { mysys->SetLogicalVolume(hcal_envelope_log); - + } // disable GDML export for HCal geometries for memory saving and compatibility issues assert(gdml_config); gdml_config->exclude_physical_vol(mothervol); @@ -226,13 +232,16 @@ int PHG4OHCalDetector::ConstructOHCal(G4LogicalVolume *hcalenvelope) for (auto & logical_vol : m_SteelAbsorberLogVolSet) { - logical_vol->SetFieldManager(m_FieldSetup->get_Field_Manager_Iron(), true); + if (m_FieldSetup) // only if we have a field defined for the steel absorber + { + logical_vol->SetFieldManager(m_FieldSetup->get_Field_Manager_Iron(), true); if (m_Params->get_int_param("field_check")) { std::cout <<__PRETTY_FUNCTION__<<" : setup Field_Manager_Iron for LV " <GetName()<<" w/ # of daughter "<< logical_vol->GetNoDaughters()< #include +#include // for PHFieldConfig, PHFieldCo... #include #include @@ -23,9 +24,9 @@ #include #include #include +#include // for G4int #include -#include PHG4OHCalFieldSetup::PHG4OHCalFieldSetup(const std::string &iron_fieldmap_path, const double scale, const double inner_radius, const double outer_radius, const double size_z) : fMinStep(0.005 * mm) diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h index 8f4395aab6..3e2be07d41 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h @@ -15,6 +15,7 @@ #include // for G4double, G4int +#include // for numeric_limits #include class G4ChordFinder; @@ -67,7 +68,7 @@ class PHG4OHCalFieldSetup G4ChordFinder* fChordFinderIron = nullptr; G4MagneticField* fEMfieldIron = nullptr; G4MagIntegratorStepper* fStepperIron = nullptr; - G4double fMinStep = NAN; + G4double fMinStep = std::numeric_limits::quiet_NaN(); }; #endif /* G4OHCAL_PHG4OHCALFIELDSETUP_H */ diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc index 75424149ca..5ed79aef5a 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc @@ -1,5 +1,3 @@ - -// local headers in quotes (that is important when using include subdirs!) #include "PHG4OHCalSteppingAction.h" #include "PHG4OHCalDetector.h" @@ -11,8 +9,6 @@ #include -#include - #include #include #include @@ -20,7 +16,10 @@ #include // for PHG4SteppingAction #include +#include + #include +#include // Root headers #include // for TAxis @@ -34,6 +33,7 @@ #include // for G4AffineTransform #include #include +#include // for G4LogicalVolume #include // for G4NavigationHistory #include // for G4ParticleDefinition #include @@ -56,7 +56,6 @@ // finally system headers #include #include // for isfinite, sqrt -#include #include #include #include // for operator<<, string @@ -494,7 +493,7 @@ void PHG4OHCalSteppingAction::FieldChecker(const G4Step* aStep) static const std::string h_field_name = "hOHCalField"; - if (not se->isHistoRegistered(h_field_name)) + if (! se->isHistoRegistered(h_field_name)) { TH2F* h = new TH2F(h_field_name.c_str(), "Magnetic field (Tesla) in HCal;X (cm);Y (cm)", 2400, -300, 300, 2400, -300, 300); @@ -531,12 +530,10 @@ void PHG4OHCalSteppingAction::FieldChecker(const G4Step* aStep) if (h->GetBinContent(binx, binx) == 0) { // only fille unfilled bins - G4TransportationManager* transportMgr = - G4TransportationManager::GetTransportationManager(); + G4TransportationManager* transportMgr = G4TransportationManager::GetTransportationManager(); assert(transportMgr); - G4PropagatorInField* fFieldPropagator = - transportMgr->GetPropagatorInField(); + G4PropagatorInField* fFieldPropagator = transportMgr->GetPropagatorInField(); assert(fFieldPropagator); G4FieldManager* fieldMgr = fFieldPropagator->FindAndSetFieldManager(volume); From 926fe496e8745dcf92b0ad6d048eff8d961e21d4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 13:35:56 -0400 Subject: [PATCH 154/468] clang-format --- .../g4simulation/g4ohcal/PHG4OHCalDetector.cc | 48 +++++++++---------- .../g4ohcal/PHG4OHCalFieldSetup.cc | 10 ++-- .../g4ohcal/PHG4OHCalFieldSetup.h | 6 +-- .../g4ohcal/PHG4OHCalSteppingAction.cc | 12 ++--- .../g4ohcal/PHG4OHCalSubsystem.cc | 30 ++++++------ .../g4simulation/g4ohcal/PHG4OHCalSubsystem.h | 2 +- 6 files changed, 53 insertions(+), 55 deletions(-) diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc index bc01887ca2..17eb36f5e1 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc @@ -11,8 +11,8 @@ #include #include -#include #include +#include #include #include @@ -50,9 +50,9 @@ #include #include #include -#include // for unique_ptr -#include // for pair, make_pair -#include // for vector, vector<>::iter... +#include // for unique_ptr +#include // for pair, make_pair +#include // for vector, vector<>::iter... class PHCompositeNode; @@ -73,12 +73,12 @@ PHG4OHCalDetector::PHG4OHCalDetector(PHG4Subsystem *subsys, PHCompositeNode *Nod PHFieldConfig *fieldconf = findNode::getClass(Node, PHFieldUtility::GetDSTConfigNodeName()); if (fieldconf->get_field_config() != PHFieldConfig::kFieldUniform) { - m_FieldSetup = - new PHG4OHCalFieldSetup( - m_Params->get_string_param("IronFieldMapPath"), m_Params->get_double_param("IronFieldMapScale"), - m_InnerRadius - 10*cm, // subtract 10 cm to make sure fieldmap with 2x2 grid covers it - m_OuterRadius + 10*cm, // add 10 cm to make sure fieldmap with 2x2 grid covers it - m_SizeZ/2. + 10*cm // div by 2 bc G4 convention + m_FieldSetup = + new PHG4OHCalFieldSetup( + m_Params->get_string_param("IronFieldMapPath"), m_Params->get_double_param("IronFieldMapScale"), + m_InnerRadius - 10 * cm, // subtract 10 cm to make sure fieldmap with 2x2 grid covers it + m_OuterRadius + 10 * cm, // add 10 cm to make sure fieldmap with 2x2 grid covers it + m_SizeZ / 2. + 10 * cm // div by 2 bc G4 convention ); } } @@ -126,9 +126,9 @@ void PHG4OHCalDetector::ConstructMe(G4LogicalVolume *logicWorld) m_DisplayAction->SetMyTopVolume(mothervol); ConstructOHCal(hcal_envelope_log); - // allow installing new G4 subsystem installed inside the HCal envelope via macros, in particular its support rings. + // allow installing new G4 subsystem installed inside the HCal envelope via macros, in particular its support rings. PHG4Subsystem *mysys = GetMySubsystem(); - if (mysys) + if (mysys) { mysys->SetLogicalVolume(hcal_envelope_log); } @@ -162,8 +162,8 @@ int PHG4OHCalDetector::ConstructOHCal(G4LogicalVolume *hcalenvelope) gdmlParser.SetOverlapCheck(OverlapCheck()); gdmlParser.Read(m_GDMPath, false); - G4AssemblyVolume *abs_asym = reader->GetAssembly("sector"); //absorber - m_ScintiMotherAssembly = reader->GetAssembly("tileAssembly24_90"); //tiles + G4AssemblyVolume *abs_asym = reader->GetAssembly("sector"); // absorber + m_ScintiMotherAssembly = reader->GetAssembly("tileAssembly24_90"); // tiles // this loop is inefficient but the assignment of the scintillator id's is much simpler when having the hcal sector std::vector::iterator it1 = abs_asym->GetVolumesIterator(); @@ -194,8 +194,8 @@ int PHG4OHCalDetector::ConstructOHCal(G4LogicalVolume *hcalenvelope) ++it1; } // Chimney assemblies - G4AssemblyVolume *chimAbs_asym = reader->GetAssembly("sectorChimney"); //absorber - m_ChimScintiMotherAssembly = reader->GetAssembly("tileAssembly24chimney_90"); //chimney tiles + G4AssemblyVolume *chimAbs_asym = reader->GetAssembly("sectorChimney"); // absorber + m_ChimScintiMotherAssembly = reader->GetAssembly("tileAssembly24chimney_90"); // chimney tiles std::vector::iterator it2 = chimAbs_asym->GetVolumesIterator(); // order sector 30,31,29 @@ -230,17 +230,17 @@ int PHG4OHCalDetector::ConstructOHCal(G4LogicalVolume *hcalenvelope) ++it2; } - for (auto & logical_vol : m_SteelAbsorberLogVolSet) + for (auto &logical_vol : m_SteelAbsorberLogVolSet) { - if (m_FieldSetup) // only if we have a field defined for the steel absorber + if (m_FieldSetup) // only if we have a field defined for the steel absorber { logical_vol->SetFieldManager(m_FieldSetup->get_Field_Manager_Iron(), true); - if (m_Params->get_int_param("field_check")) - { - std::cout <<__PRETTY_FUNCTION__<<" : setup Field_Manager_Iron for LV " - <GetName()<<" w/ # of daughter "<< logical_vol->GetNoDaughters()<get_int_param("field_check")) + { + std::cout << __PRETTY_FUNCTION__ << " : setup Field_Manager_Iron for LV " + << logical_vol->GetName() << " w/ # of daughter " << logical_vol->GetNoDaughters() << std::endl; + } } } @@ -458,7 +458,7 @@ int PHG4OHCalDetector::map_layerid(const unsigned int isector, const int layer_i { rowid = layer_id + 95; } - else /* if (layer_id >= 225) */ + else /* if (layer_id >= 225) */ { rowid = layer_id - 225; } diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.cc index f950c6e98e..42cd4da003 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.cc @@ -2,7 +2,7 @@ /*! * \file PHG4OHCalFieldSetup.cc - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ @@ -12,9 +12,9 @@ #include -#include +#include // for PHFieldConfig, PHFieldCo... #include -#include // for PHFieldConfig, PHFieldCo... +#include #include #include @@ -24,7 +24,7 @@ #include #include #include -#include // for G4int +#include // for G4int #include @@ -34,7 +34,7 @@ PHG4OHCalFieldSetup::PHG4OHCalFieldSetup(const std::string &iron_fieldmap_path, static const G4int nvar = 8; // the new HCal expect 3D magnetic field - PHFieldConfigv1 field_config (PHFieldConfig::Field3DCartesian, iron_fieldmap_path, scale); + PHFieldConfigv1 field_config(PHFieldConfig::Field3DCartesian, iron_fieldmap_path, scale); fEMfieldIron = new PHG4MagneticField(PHFieldUtility::BuildFieldMap(&field_config, inner_radius, outer_radius, size_z)); assert(fEMfieldIron); diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h index 3e2be07d41..a53774a5bf 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalFieldSetup.h @@ -4,7 +4,7 @@ /*! * \file PHG4OHCalFieldSetup.h - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ @@ -15,7 +15,7 @@ #include // for G4double, G4int -#include // for numeric_limits +#include // for numeric_limits #include class G4ChordFinder; @@ -30,7 +30,7 @@ class G4MagneticField; class PHG4OHCalFieldSetup { public: - PHG4OHCalFieldSetup(const std::string & iron_fieldmap_path, const double scale = 1., const double inner_radius = 0., const double outer_radius = 1.e10, const double size_z = 1.e10); + PHG4OHCalFieldSetup(const std::string& iron_fieldmap_path, const double scale = 1., const double inner_radius = 0., const double outer_radius = 1.e10, const double size_z = 1.e10); // delete copy ctor and assignment opertor (cppcheck) explicit PHG4OHCalFieldSetup(const PHG4OHCalFieldSetup&) = delete; diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc index 5ed79aef5a..b06f101c2e 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc @@ -33,7 +33,7 @@ #include // for G4AffineTransform #include #include -#include // for G4LogicalVolume +#include // for G4LogicalVolume #include // for G4NavigationHistory #include // for G4ParticleDefinition #include @@ -272,17 +272,17 @@ bool PHG4OHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was { m_Hit = new PHG4Hitv1(); } - //here we set the entrance values in cm + // here we set the entrance values in cm m_Hit->set_x(0, prePoint->GetPosition().x() / cm); m_Hit->set_y(0, prePoint->GetPosition().y() / cm); m_Hit->set_z(0, prePoint->GetPosition().z() / cm); // time in ns m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond); - //set the track ID + // set the track ID m_Hit->set_trkid(aTrack->GetTrackID()); m_SaveTrackId = aTrack->GetTrackID(); - //set the initial energy deposit + // set the initial energy deposit m_Hit->set_edep(0); if (whichactive > 0) // return of IsInOHCalDetector, > 0 hit in scintillator, < 0 hit in absorber { @@ -351,7 +351,7 @@ bool PHG4OHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond); - //sum up the energy to get total deposited + // sum up the energy to get total deposited m_Hit->set_edep(m_Hit->get_edep() + edep); if (whichactive > 0) @@ -493,7 +493,7 @@ void PHG4OHCalSteppingAction::FieldChecker(const G4Step* aStep) static const std::string h_field_name = "hOHCalField"; - if (! se->isHistoRegistered(h_field_name)) + if (!se->isHistoRegistered(h_field_name)) { TH2F* h = new TH2F(h_field_name.c_str(), "Magnetic field (Tesla) in HCal;X (cm);Y (cm)", 2400, -300, 300, 2400, -300, 300); diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc index 7b127d71b6..d9f44be414 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc @@ -21,9 +21,9 @@ #include #include // for NAN +#include // for getenv #include // for operator<<, basic_ostream #include // for set -#include // for getenv class PHG4Detector; //_______________________________________________________________________ @@ -48,13 +48,12 @@ int PHG4OHCalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) // create display settings before detector m_DisplayAction = new PHG4OHCalDisplayAction(Name()); - if (get_string_param("IronFieldMapPath") == "DefaultParameters-InvadPath" ) + if (get_string_param("IronFieldMapPath") == "DefaultParameters-InvadPath") { - std::cout <<__PRETTY_FUNCTION__<<": invalid string parameter IronFieldMapPath, where we expect a 3D field map"<SuperDetector(SuperDetector()); @@ -155,12 +154,12 @@ void PHG4OHCalSubsystem::SetLightCorrection(const double inner_radius, const dou void PHG4OHCalSubsystem::SetDefaultParameters() { - set_default_double_param("inner_radius", 182.423 - 5); + set_default_double_param("inner_radius", 182.423 - 5); set_default_double_param("light_balance_inner_corr", NAN); set_default_double_param("light_balance_inner_radius", NAN); set_default_double_param("light_balance_outer_corr", NAN); set_default_double_param("light_balance_outer_radius", NAN); - set_default_double_param("outer_radius", 269.317 + 5 ); + set_default_double_param("outer_radius", 269.317 + 5); set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); @@ -178,21 +177,20 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); std::string defaultmapfilename; - const char* Calibroot = getenv("CALIBRATIONROOT"); + const char *Calibroot = getenv("CALIBRATIONROOT"); if (Calibroot) - { - defaultmapfilename = Calibroot; - defaultmapfilename += "/HCALOUT/tilemap/ohcalgdmlmapfiles102022.root"; - } + { + defaultmapfilename = Calibroot; + defaultmapfilename += "/HCALOUT/tilemap/ohcalgdmlmapfiles102022.root"; + } set_default_string_param("MapFileName", defaultmapfilename); set_default_string_param("MapHistoName", "ohcal_mephi_map_towerid_"); - + if (!Calibroot) { - std::cout<<__PRETTY_FUNCTION__ << ": no CALIBRATIONROOT environment variable" << std::endl; + std::cout << __PRETTY_FUNCTION__ << ": no CALIBRATIONROOT environment variable" << std::endl; exit(1); } - set_default_string_param("IronFieldMapPath", std::string(Calibroot) + "/Field/Map/sphenix3dbigmapxyz_steel_rebuild.root" ); + set_default_string_param("IronFieldMapPath", std::string(Calibroot) + "/Field/Map/sphenix3dbigmapxyz_steel_rebuild.root"); set_default_double_param("IronFieldMapScale", 1.); - } diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.h b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.h index f447f9061b..625b718ca4 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.h @@ -49,7 +49,7 @@ class PHG4OHCalSubsystem : public PHG4DetectorSubsystem // Subsystems which can be mothervolume need to implement this // and return true bool CanBeMotherSubsystem() const override { return true; } - + private: void SetDefaultParameters() override; From 2c7e6eb30cd4804ae0a0e99082b7f571113d60a5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 13:46:29 -0400 Subject: [PATCH 155/468] remove obsolete pragmas, remove using namespace std --- offline/packages/PHField/PHField2D.cc | 86 ++++++------- .../packages/PHField/PHField3DCartesian.cc | 4 - .../packages/PHField/PHField3DCylindrical.cc | 118 +++++++++--------- offline/packages/PHField/PHFieldUtility.cc | 3 - 4 files changed, 96 insertions(+), 115 deletions(-) diff --git a/offline/packages/PHField/PHField2D.cc b/offline/packages/PHField/PHField2D.cc index fae8e159d4..e99f8718a9 100644 --- a/offline/packages/PHField/PHField2D.cc +++ b/offline/packages/PHField/PHField2D.cc @@ -3,12 +3,8 @@ //root framework #include #include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" #include #include -#pragma GCC diagnostic pop #include @@ -22,9 +18,7 @@ #include #include -using namespace std; - -PHField2D::PHField2D(const string &filename, const int verb, const float magfield_rescale) +PHField2D::PHField2D(const std::string &filename, const int verb, const float magfield_rescale) : PHField(verb) , r_index0_cache(0) , r_index1_cache(0) @@ -33,19 +27,19 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel { if (Verbosity() > 0) { - cout << " ------------- PHField2D::PHField2D() ------------------" << endl; + std::cout << " ------------- PHField2D::PHField2D() ------------------" << std::endl; } // open file TFile *rootinput = TFile::Open(filename.c_str()); if (!rootinput) { - cout << " could not open " << filename << " exiting now" << endl; + std::cout << " could not open " << filename << " exiting now" << std::endl; gSystem->Exit(1); exit(1); } if (Verbosity() > 0) { - cout << " Field grid file: " << filename << endl; + std::cout << " Field grid file: " << filename << std::endl; } rootinput->cd(); @@ -62,7 +56,7 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel field_map = (TNtuple *) gDirectory->Get("map"); if (!field_map) { - cout << "PHField2D: could not locate ntuple of name map or fieldmap, exiting now" << endl; + std::cout << "PHField2D: could not locate ntuple of name map or fieldmap, exiting now" << std::endl; exit(1); } magfield_unit = gauss; @@ -81,21 +75,21 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel // run checks on entries if (Verbosity() > 0) { - cout << " The field grid contained " << NENTRIES << " entries" << endl; + std::cout << " The field grid contained " << NENTRIES << " entries" << std::endl; } if (Verbosity() > 1) { - cout << "\n NENTRIES should be the same as the following values:" + std::cout << "\n NENTRIES should be the same as the following values:" << "\n [ Number of values r,z: " - << nr << " " << nz << " ]! " << endl; + << nr << " " << nz << " ]! " << std::endl; } if (nz != nr) { - cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << "\n The file you entered is not a \"table\" of values" << "\n Something very likely went oh so wrong" - << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; } // Keep track of the unique z, r, phi values in the grid using sets @@ -108,7 +102,7 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel // phi. if (Verbosity() > 1) { - cout << " --> Sorting Entries..." << endl; + std::cout << " --> Sorting Entries..." << std::endl; } std::map sorted_map; for (int i = 0; i < field_map->GetEntries(); i++) @@ -122,10 +116,10 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel r_set.insert(ROOT_R * cm); } - // couts for assurance + // std::couts for assurance if (Verbosity() > 4) { - map::iterator it = sorted_map.begin(); + std::map::iterator it = sorted_map.begin(); print_map(it); float last_z = it->first.get<0>(); for (it = sorted_map.begin(); it != sorted_map.end(); ++it) @@ -140,7 +134,7 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel if (Verbosity() > 1) { - cout << " --> Putting entries into containers... " << endl; + std::cout << " --> Putting entries into containers... " << std::endl; } // grab the minimum and maximum z values @@ -159,12 +153,12 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel std::copy(r_set.begin(), r_set.end(), r_map_.begin()); // initialize the field map vectors to the correct sizes - BFieldR_.resize(nz, vector(nr, 0)); - BFieldZ_.resize(nz, vector(nr, 0)); + BFieldR_.resize(nz, std::vector(nr, 0)); + BFieldZ_.resize(nz, std::vector(nr, 0)); // all of this assumes that z_prev < z , i.e. the table is ordered (as of right now) unsigned int ir = 0, iz = 0; // useful indexes to keep track of - map::iterator iter = sorted_map.begin(); + std::map::iterator iter = sorted_map.begin(); for (; iter != sorted_map.end(); ++iter) { // equivalent to ->GetEntry(iter) @@ -196,7 +190,7 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel // shouldn't happen if (iz > 0 && z < z_map_[iz - 1]) { - cout << "!!!!!!!!! Your map isn't ordered.... z: " << z << " zprev: " << z_map_[iz - 1] << endl; + std::cout << "!!!!!!!!! Your map isn't ordered.... z: " << z << " zprev: " << z_map_[iz - 1] << std::endl; } BFieldR_[iz][ir] = Br * magfield_rescale; @@ -204,16 +198,16 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel // you can change this to check table values for correctness // print_map prints the values in the root table, and the - // couts print the values entered into the vectors + // std::couts print the values entered into the vectors if (fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) { print_map(iter); - cout << " B(" + std::cout << " B(" << r_map_[ir] << ", " << z_map_[iz] << "): (" << BFieldR_[iz][ir] << ", " - << BFieldZ_[iz][ir] << ")" << endl; + << BFieldZ_[iz][ir] << ")" << std::endl; } } // end loop over root field map file @@ -222,16 +216,16 @@ PHField2D::PHField2D(const string &filename, const int verb, const float magfiel if (Verbosity() > 0) { - cout << " Mag field z boundaries (min,max): (" << minz_ / cm << ", " << maxz_ / cm << ") cm" << endl; + std::cout << " Mag field z boundaries (min,max): (" << minz_ / cm << ", " << maxz_ / cm << ") cm" << std::endl; } if (Verbosity() > 0) { - cout << " Mag field r max boundary: " << r_map_.back() / cm << " cm" << endl; + std::cout << " Mag field r max boundary: " << r_map_.back() / cm << " cm" << std::endl; } if (Verbosity() > 0) { - cout << " -----------------------------------------------------------" << endl; + std::cout << " -----------------------------------------------------------" << std::endl; } } @@ -239,7 +233,7 @@ void PHField2D::GetFieldValue(const double point[4], double *Bfield) const { if (Verbosity() > 2) { - cout << "\nPHField2D::GetFieldValue" << endl; + std::cout << "\nPHField2D::GetFieldValue" << std::endl; } double x = point[0]; double y = point[1]; @@ -277,15 +271,15 @@ void PHField2D::GetFieldValue(const double point[4], double *Bfield) const Bfield[2] = 0.0; if (Verbosity() > 2) { - cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << endl; + std::cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << std::endl; } } if (Verbosity() > 2) { - cout << "END PHField2D::GetFieldValue\n" + std::cout << "END PHField2D::GetFieldValue\n" << " ---> {Bx, By, Bz} : " - << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << endl; + << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; } return; @@ -302,14 +296,14 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const if (Verbosity() > 2) { - cout << "GetFieldCyl@ : {" << z << "," << r << "}" << endl; + std::cout << "GetFieldCyl@ : {" << z << "," << r << "}" << std::endl; } if (z < z_map_[0] || z > z_map_[z_map_.size() - 1]) { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } @@ -324,13 +318,13 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const if (!((r > r_map_[r_index0]) && (r < r_map_[r_index1]))) { // if miss cached r values, search through the lookup table - vector::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r); + std::vector::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r); r_index0 = distance(r_map_.begin(), riter) - 1; if (r_index0 >= r_map_.size()) { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } @@ -340,7 +334,7 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } @@ -356,14 +350,14 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const if (!((z > z_map_[z_index0]) && (z < z_map_[z_index1]))) { // if miss cached z values, search through the lookup table - vector::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z); + std::vector::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z); z_index0 = distance(z_map_.begin(), ziter) - 1; z_index1 = z_index0 + 1; if (z_index1 >= z_map_.size()) { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (z too large in specific r-plane)" << endl; + std::cout << "!!!! Point not in defined region (z too large in specific r-plane)" << std::endl; } return; } @@ -410,22 +404,22 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const if (Verbosity() > 2) { - cout << "End GFCyl Call: : {" + std::cout << "End GFCyl Call: : {" << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" - << endl; + << std::endl; } return; } // debug function to print key/value pairs in map -void PHField2D::print_map(map::iterator &it) const +void PHField2D::print_map(std::map::iterator &it) const { - cout << " Key: <" + std::cout << " Key: <" << it->first.get<0>() / cm << "," << it->first.get<1>() / cm << ">" << " Value: <" << it->second.get<0>() / magfield_unit << "," - << it->second.get<1>() / magfield_unit << ">\n"; + << it->second.get<1>() / magfield_unit << ">" << std::endl; } diff --git a/offline/packages/PHField/PHField3DCartesian.cc b/offline/packages/PHField/PHField3DCartesian.cc index 0686ede794..59c85da661 100644 --- a/offline/packages/PHField/PHField3DCartesian.cc +++ b/offline/packages/PHField/PHField3DCartesian.cc @@ -4,12 +4,8 @@ #include // for TDirectory, gDirectory #include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" #include #include -#pragma GCC diagnostic pop #include diff --git a/offline/packages/PHField/PHField3DCylindrical.cc b/offline/packages/PHField/PHField3DCylindrical.cc index 53e5fd3689..11c58bc591 100644 --- a/offline/packages/PHField/PHField3DCylindrical.cc +++ b/offline/packages/PHField/PHField3DCylindrical.cc @@ -2,11 +2,7 @@ #include // for TDirectory, gDirectory #include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" #include -#pragma GCC diagnostic pop #include @@ -21,13 +17,11 @@ #include #include -using namespace std; - -PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int verb, const float magfield_rescale) +PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const int verb, const float magfield_rescale) : PHField(verb) { - cout << "\n================ Begin Construct Mag Field =====================" << endl; - cout << "\n-----------------------------------------------------------" + std::cout << "\n================ Begin Construct Mag Field =====================" << std::endl; + std::cout << "\n-----------------------------------------------------------" << "\n Magnetic field Module - Verbosity:" << Verbosity() << "\n-----------------------------------------------------------"; @@ -35,12 +29,12 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver TFile *rootinput = TFile::Open(filename.c_str()); if (!rootinput) { - cout << "\n could not open " << filename << " exiting now" << endl; + std::cout << "\n could not open " << filename << " exiting now" << std::endl; exit(1); } - cout << "\n ---> " + std::cout << "\n ---> " "Reading the field grid from " - << filename << " ... " << endl; + << filename << " ... " << std::endl; rootinput->cd(); // get root NTuple objects @@ -62,20 +56,20 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver static const int NENTRIES = field_map->GetEntries(); // run checks on entries - cout << " ---> The field grid contained " << NENTRIES << " entries" << endl; + std::cout << " ---> The field grid contained " << NENTRIES << " entries" << std::endl; if (Verbosity() > 0) { - cout << "\n NENTRIES should be the same as the following values:" + std::cout << "\n NENTRIES should be the same as the following values:" << "\n [ Number of values r,phi,z: " - << nr << " " << nphi << " " << nz << " ]! " << endl; + << nr << " " << nphi << " " << nz << " ]! " << std::endl; } if (nz != nr || nz != nphi || nr != nphi) { - cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << "\n The file you entered is not a \"table\" of values" << "\n Something very likely went oh so wrong" - << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; } // Keep track of the unique z, r, phi values in the grid using sets @@ -88,7 +82,7 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver // phi. if (Verbosity() > 0) { - cout << " --> Sorting Entries..." << endl; + std::cout << " --> Sorting Entries..." << std::endl; } std::map sorted_map; for (int i = 0; i < field_map->GetEntries(); i++) @@ -103,10 +97,10 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver phi_set.insert(ROOT_PHI * deg); } - // couts for assurance + // std::couts for assurance if (Verbosity() > 4) { - map::iterator it = sorted_map.begin(); + std::map::iterator it = sorted_map.begin(); print_map(it); float last_z = it->first.get<0>(); for (it = sorted_map.begin(); it != sorted_map.end(); ++it) @@ -121,7 +115,7 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver if (Verbosity() > 0) { - cout << " --> Putting entries into containers... " << endl; + std::cout << " --> Putting entries into containers... " << std::endl; } // grab the minimum and maximum z values @@ -143,13 +137,13 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver std::copy(r_set.begin(), r_set.end(), r_map_.begin()); // initialize the field map vectors to the correct sizes - BFieldR_.resize(nz, vector >(nr, vector(nphi, 0))); - BFieldPHI_.resize(nz, vector >(nr, vector(nphi, 0))); - BFieldZ_.resize(nz, vector >(nr, vector(nphi, 0))); + BFieldR_.resize(nz, std::vector >(nr, std::vector(nphi, 0))); + BFieldPHI_.resize(nz, std::vector >(nr, std::vector(nphi, 0))); + BFieldZ_.resize(nz, std::vector >(nr, std::vector(nphi, 0))); // all of this assumes that z_prev < z , i.e. the table is ordered (as of right now) unsigned int ir = 0, iphi = 0, iz = 0; // useful indexes to keep track of - map::iterator iter = sorted_map.begin(); + std::map::iterator iter = sorted_map.begin(); for (; iter != sorted_map.end(); ++iter) { // equivalent to ->GetEntry(iter) @@ -189,7 +183,7 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver // shouldn't happen if (iz > 0 && z < z_map_[iz - 1]) { - cout << "!!!!!!!!! Your map isn't ordered.... z: " << z << " zprev: " << z_map_[iz - 1] << endl; + std::cout << "!!!!!!!!! Your map isn't ordered.... z: " << z << " zprev: " << z_map_[iz - 1] << std::endl; } BFieldR_[iz][ir][iphi] = Br * magfield_rescale; @@ -198,37 +192,37 @@ PHField3DCylindrical::PHField3DCylindrical(const string &filename, const int ver // you can change this to check table values for correctness // print_map prints the values in the root table, and the - // couts print the values entered into the vectors + // std::couts print the values entered into the vectors if (fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) { print_map(iter); - cout << " B(" + std::cout << " B(" << r_map_[ir] << ", " << phi_map_[iphi] << ", " << z_map_[iz] << "): (" << BFieldR_[iz][ir][iphi] << ", " << BFieldPHI_[iz][ir][iphi] << ", " - << BFieldZ_[iz][ir][iphi] << ")" << endl; + << BFieldZ_[iz][ir][iphi] << ")" << std::endl; } } // end loop over root field map file rootinput->Close(); - cout << "\n ---> ... read file successfully " + std::cout << "\n ---> ... read file successfully " << "\n ---> Z Boundaries ~ zlow, zhigh: " - << minz_ / cm << "," << maxz_ / cm << " cm " << endl; + << minz_ / cm << "," << maxz_ / cm << " cm " << std::endl; - cout << "\n================= End Construct Mag Field ======================\n" - << endl; + std::cout << "\n================= End Construct Mag Field ======================\n" + << std::endl; } void PHField3DCylindrical::GetFieldValue(const double point[4], double *Bfield) const { if (Verbosity() > 2) { - cout << "\nPHField3DCylindrical::GetFieldValue" << endl; + std::cout << "\nPHField3DCylindrical::GetFieldValue" << std::endl; } double x = point[0]; double y = point[1]; @@ -274,15 +268,15 @@ void PHField3DCylindrical::GetFieldValue(const double point[4], double *Bfield) Bfield[2] = 0.0; if (Verbosity() > 2) { - cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << endl; + std::cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << std::endl; } } if (Verbosity() > 2) { - cout << "END PHField3DCylindrical::GetFieldValue\n" + std::cout << "END PHField3DCylindrical::GetFieldValue\n" << " ---> {Bx, By, Bz} : " - << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << endl; + << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; } return; @@ -300,14 +294,14 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC if (Verbosity() > 2) { - cout << "GetFieldCyl@ : {" << z << "," << r << "," << phi << "}" << endl; + std::cout << "GetFieldCyl@ : {" << z << "," << r << "," << phi << "}" << std::endl; } if (z <= z_map_[0] || z >= z_map_[z_map_.size() - 1]) { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (|z| too large)" << endl; + std::cout << "!!!! Point not in defined region (|z| too large)" << std::endl; } return; } @@ -316,7 +310,7 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC r = r_map_[0]; if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too small in specific z-plane). Use min radius" << endl; + std::cout << "!!!! Point not in defined region (radius too small in specific z-plane). Use min radius" << std::endl; } // return; } @@ -324,12 +318,12 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } - vector::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z); + std::vector::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z); int z_index0 = distance(z_map_.begin(), ziter) - 1; int z_index1 = z_index0 + 1; @@ -338,13 +332,13 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC assert(z_index0 < (int) z_map_.size()); assert(z_index1 < (int) z_map_.size()); - vector::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r); + std::vector::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r); int r_index0 = distance(r_map_.begin(), riter) - 1; if (r_index0 >= (int) r_map_.size()) { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } @@ -354,7 +348,7 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC { if (Verbosity() > 2) { - cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << endl; + std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl; } return; } @@ -362,7 +356,7 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC assert(r_index0 >= 0); assert(r_index1 >= 0); - vector::const_iterator phiiter = upper_bound(phi_map_.begin(), phi_map_.end(), phi); + std::vector::const_iterator phiiter = upper_bound(phi_map_.begin(), phi_map_.end(), phi); int phi_index0 = distance(phi_map_.begin(), phiiter) - 1; int phi_index1 = phi_index0 + 1; if (phi_index1 >= (int) phi_map_.size()) @@ -438,22 +432,22 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC zweight * ((1 - rweight) * ((1 - phiweight) * Bphi100 + phiweight * Bphi101) + rweight * ((1 - phiweight) * Bphi110 + phiweight * Bphi111)); - // cout << "wr: " << rweight << " wz: " << zweight << " wphi: " << phiweight << endl; - // cout << "Bz000: " << Bz000 << endl - // << "Bz001: " << Bz001 << endl - // << "Bz010: " << Bz010 << endl - // << "Bz011: " << Bz011 << endl - // << "Bz100: " << Bz100 << endl - // << "Bz101: " << Bz101 << endl - // << "Bz110: " << Bz110 << endl - // << "Bz111: " << Bz111 << endl - // << "Bz: " << BfieldCyl[0] << endl << endl; + // std::cout << "wr: " << rweight << " wz: " << zweight << " wphi: " << phiweight << std::endl; + // std::cout << "Bz000: " << Bz000 << std::endl + // << "Bz001: " << Bz001 << std::endl + // << "Bz010: " << Bz010 << std::endl + // << "Bz011: " << Bz011 << std::endl + // << "Bz100: " << Bz100 << std::endl + // << "Bz101: " << Bz101 << std::endl + // << "Bz110: " << Bz110 << std::endl + // << "Bz111: " << Bz111 << std::endl + // << "Bz: " << BfieldCyl[0] << std::endl << std::endl; if (Verbosity() > 2) { - cout << "End GFCyl Call: : {" + std::cout << "End GFCyl Call: : {" << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" - << endl; + << std::endl; } return; @@ -461,7 +455,7 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC // a binary search algorithm that puts the location that "key" would be, into index... // it returns true if key was found, and false if not. -bool PHField3DCylindrical::bin_search(const vector &vec, unsigned start, unsigned end, const float &key, unsigned &index) const +bool PHField3DCylindrical::bin_search(const std::vector &vec, unsigned start, unsigned end, const float &key, unsigned &index) const { // Termination condition: start index greater than end index if (start > end) @@ -487,9 +481,9 @@ bool PHField3DCylindrical::bin_search(const vector &vec, unsigned start, } // debug function to print key/value pairs in map -void PHField3DCylindrical::print_map(map::iterator &it) const +void PHField3DCylindrical::print_map(std::map::iterator &it) const { - cout << " Key: <" + std::cout << " Key: <" << it->first.get<0>() * cm << "," << it->first.get<1>() * cm << "," << it->first.get<2>() * deg << ">" @@ -497,5 +491,5 @@ void PHField3DCylindrical::print_map(map::iterator &it) const << " Value: <" << it->second.get<0>() * gauss << "," << it->second.get<1>() * gauss << "," - << it->second.get<2>() * gauss << ">\n"; + << it->second.get<2>() * gauss << ">" << std::endl; } diff --git a/offline/packages/PHField/PHFieldUtility.cc b/offline/packages/PHField/PHFieldUtility.cc index 5d61b0ca26..7de68bfbc8 100644 --- a/offline/packages/PHField/PHFieldUtility.cc +++ b/offline/packages/PHField/PHFieldUtility.cc @@ -18,10 +18,7 @@ #include #include // for PHWHERE -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" #include -#pragma GCC diagnostic pop #include #include // for getenv From 4be584f7dce96c315dd7911f3d6c734b6ab3899e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 14:16:31 -0400 Subject: [PATCH 156/468] replace boost tuple by std tuple --- offline/packages/PHField/PHField2D.cc | 2 +- offline/packages/PHField/PHField3DCartesian.cc | 16 ++++++++-------- offline/packages/PHField/PHField3DCartesian.h | 8 +++----- offline/packages/PHField/PHField3DCylindrical.cc | 2 +- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/offline/packages/PHField/PHField2D.cc b/offline/packages/PHField/PHField2D.cc index e99f8718a9..59ea2ef47f 100644 --- a/offline/packages/PHField/PHField2D.cc +++ b/offline/packages/PHField/PHField2D.cc @@ -199,7 +199,7 @@ PHField2D::PHField2D(const std::string &filename, const int verb, const float ma // you can change this to check table values for correctness // print_map prints the values in the root table, and the // std::couts print the values entered into the vectors - if (fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) + if (std::fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) { print_map(iter); diff --git a/offline/packages/PHField/PHField3DCartesian.cc b/offline/packages/PHField/PHField3DCartesian.cc index 59c85da661..5f3f04c19e 100644 --- a/offline/packages/PHField/PHField3DCartesian.cc +++ b/offline/packages/PHField/PHField3DCartesian.cc @@ -234,7 +234,7 @@ void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) co ykey_save = ykey[0]; zkey_save = zkey[0]; - std::map, boost::tuple >::const_iterator magval; + std::map, std::tuple >::const_iterator magval; trio key; for (int i = 0; i < 2; i++) { @@ -242,7 +242,7 @@ void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) co { for (int k = 0; k < 2; k++) { - key = boost::make_tuple(xkey[i], ykey[j], zkey[k]); + key = std::make_tuple(xkey[i], ykey[j], zkey[k]); magval = fieldmap.find(key); if (magval == fieldmap.end()) { @@ -252,12 +252,12 @@ void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) co << ", z: " << zkey[k] / cm << std::endl; return; } - xyz[i][j][k][0] = (magval->first).get<0>(); - xyz[i][j][k][1] = (magval->first).get<1>(); - xyz[i][j][k][2] = (magval->first).get<2>(); - bf[i][j][k][0] = (magval->second).get<0>(); - bf[i][j][k][1] = (magval->second).get<1>(); - bf[i][j][k][2] = (magval->second).get<2>(); + xyz[i][j][k][0] = std::get<0>(magval->first); + xyz[i][j][k][1] = std::get<1>(magval->first); + xyz[i][j][k][2] = std::get<2>(magval->first); + bf[i][j][k][0] = std::get<0>(magval->second); + bf[i][j][k][1] = std::get<1>(magval->second); + bf[i][j][k][2] = std::get<2>(magval->second); if (Verbosity() > 0) { std::cout << "read x/y/z: " << xyz[i][j][k][0] / cm << "/" diff --git a/offline/packages/PHField/PHField3DCartesian.h b/offline/packages/PHField/PHField3DCartesian.h index 2521ae6e3f..ae1fa9a6de 100644 --- a/offline/packages/PHField/PHField3DCartesian.h +++ b/offline/packages/PHField/PHField3DCartesian.h @@ -3,13 +3,11 @@ #include "PHField.h" -#include -#include - #include #include #include #include +#include class PHField3DCartesian : public PHField { @@ -44,8 +42,8 @@ explicit PHField3DCartesian(const std::string &fname, const float magfield_resca mutable int cache_hits = 0; mutable int cache_misses = 0; - typedef boost::tuple trio; - std::map, boost::tuple > fieldmap; + typedef std::tuple trio; + std::map, std::tuple > fieldmap; std::set xvals; std::set yvals; std::set zvals; diff --git a/offline/packages/PHField/PHField3DCylindrical.cc b/offline/packages/PHField/PHField3DCylindrical.cc index 11c58bc591..b19a3bb14b 100644 --- a/offline/packages/PHField/PHField3DCylindrical.cc +++ b/offline/packages/PHField/PHField3DCylindrical.cc @@ -193,7 +193,7 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in // you can change this to check table values for correctness // print_map prints the values in the root table, and the // std::couts print the values entered into the vectors - if (fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) + if (std::fabs(z) < 10 && ir < 10 /*&& iphi==2*/ && Verbosity() > 3) { print_map(iter); From 3bc356cf9f4128accdad76986865b203b4657977 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 14:23:32 -0400 Subject: [PATCH 157/468] replace boost tuple by std tuple for PHField3DCylindrical --- .../packages/PHField/PHField3DCylindrical.cc | 32 +++++++++---------- .../packages/PHField/PHField3DCylindrical.h | 5 ++- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/offline/packages/PHField/PHField3DCylindrical.cc b/offline/packages/PHField/PHField3DCylindrical.cc index b19a3bb14b..9dce27304a 100644 --- a/offline/packages/PHField/PHField3DCylindrical.cc +++ b/offline/packages/PHField/PHField3DCylindrical.cc @@ -6,8 +6,6 @@ #include -#include - #include #include #include @@ -102,12 +100,12 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in { std::map::iterator it = sorted_map.begin(); print_map(it); - float last_z = it->first.get<0>(); + float last_z = std::get<0>(it->first); for (it = sorted_map.begin(); it != sorted_map.end(); ++it) { - if (it->first.get<0>() != last_z) + if (std::get<0>(it->first) != last_z) { - last_z = it->first.get<0>(); + last_z = std::get<0>(it->first); print_map(it); } } @@ -147,12 +145,12 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in for (; iter != sorted_map.end(); ++iter) { // equivalent to ->GetEntry(iter) - float z = iter->first.get<0>() * cm; - float r = iter->first.get<1>() * cm; - float phi = iter->first.get<2>() * deg; - float Bz = iter->second.get<0>() * gauss; - float Br = iter->second.get<1>() * gauss; - float Bphi = iter->second.get<2>() * gauss; + float z = std::get<0>(iter->first) * cm; + float r = std::get<1>(iter->first) * cm; + float phi = std::get<2>(iter->first) * deg; + float Bz = std::get<0>(iter->second) * gauss; + float Br = std::get<1>(iter->second) * gauss; + float Bphi = std::get<2>(iter->second) * gauss; if (z > maxz_) { @@ -484,12 +482,12 @@ bool PHField3DCylindrical::bin_search(const std::vector &vec, unsigned st void PHField3DCylindrical::print_map(std::map::iterator &it) const { std::cout << " Key: <" - << it->first.get<0>() * cm << "," - << it->first.get<1>() * cm << "," - << it->first.get<2>() * deg << ">" + << std::get<0>(it->first) * cm << "," + << std::get<1>(it->first) * cm << "," + << std::get<2>(it->first) * deg << ">" << " Value: <" - << it->second.get<0>() * gauss << "," - << it->second.get<1>() * gauss << "," - << it->second.get<2>() * gauss << ">" << std::endl; + << std::get<0>(it->second) * gauss << "," + << std::get<1>(it->second) * gauss << "," + << std::get<2>(it->second) * gauss << ">" << std::endl; } diff --git a/offline/packages/PHField/PHField3DCylindrical.h b/offline/packages/PHField/PHField3DCylindrical.h index 015356d77d..31b824441f 100644 --- a/offline/packages/PHField/PHField3DCylindrical.h +++ b/offline/packages/PHField/PHField3DCylindrical.h @@ -22,15 +22,14 @@ #include "PHField.h" -#include - #include #include +#include #include class PHField3DCylindrical : public PHField { - typedef boost::tuple trio; + typedef std::tuple trio; public: PHField3DCylindrical(const std::string& filename, int verb = 0, const float magfield_rescale = 1.0); From 171e3e7cf1648c71f06e8984e4bb88f46d3da01e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 14:26:36 -0400 Subject: [PATCH 158/468] replace boost tuple by std tuple for PHField2D --- offline/packages/PHField/PHField2D.cc | 24 +++++++++++------------- offline/packages/PHField/PHField2D.h | 5 ++--- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/offline/packages/PHField/PHField2D.cc b/offline/packages/PHField/PHField2D.cc index 59ea2ef47f..75b4b5d2d5 100644 --- a/offline/packages/PHField/PHField2D.cc +++ b/offline/packages/PHField/PHField2D.cc @@ -8,8 +8,6 @@ #include -#include - #include #include #include @@ -121,12 +119,12 @@ PHField2D::PHField2D(const std::string &filename, const int verb, const float ma { std::map::iterator it = sorted_map.begin(); print_map(it); - float last_z = it->first.get<0>(); + float last_z = std::get<0>(it->first); for (it = sorted_map.begin(); it != sorted_map.end(); ++it) { - if (it->first.get<0>() != last_z) + if (std::get<0>(it->first) != last_z) { - last_z = it->first.get<0>(); + last_z = std::get<0>(it->first); print_map(it); } } @@ -162,10 +160,10 @@ PHField2D::PHField2D(const std::string &filename, const int verb, const float ma for (; iter != sorted_map.end(); ++iter) { // equivalent to ->GetEntry(iter) - float z = iter->first.get<0>() * cm; - float r = iter->first.get<1>() * cm; - float Bz = iter->second.get<0>() * magfield_unit; - float Br = iter->second.get<1>() * magfield_unit; + float z = std::get<0>(iter->first) * cm; + float r = std::get<1>(iter->first) * cm; + float Bz = std::get<0>(iter->second) * magfield_unit; + float Br = std::get<1>(iter->second) * magfield_unit; if (z > maxz_) { @@ -416,10 +414,10 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const void PHField2D::print_map(std::map::iterator &it) const { std::cout << " Key: <" - << it->first.get<0>() / cm << "," - << it->first.get<1>() / cm << ">" + << std::get<0>(it->first) / cm << "," + << std::get<1>(it->first) / cm << ">" << " Value: <" - << it->second.get<0>() / magfield_unit << "," - << it->second.get<1>() / magfield_unit << ">" << std::endl; + << std::get<0>(it->second) / magfield_unit << "," + << std::get<1>(it->second) / magfield_unit << ">" << std::endl; } diff --git a/offline/packages/PHField/PHField2D.h b/offline/packages/PHField/PHField2D.h index aead61ff51..62794a9db1 100644 --- a/offline/packages/PHField/PHField2D.h +++ b/offline/packages/PHField/PHField2D.h @@ -4,15 +4,14 @@ #include "PHField.h" -#include - #include #include +#include #include class PHField2D : public PHField { - typedef boost::tuple trio; + typedef std::tuple trio; public: PHField2D(const std::string &filename, const int verb = 0, const float magfield_rescale = 1.0); From 309b7bf83788dc3fcaf5cf7811c8a5a225b50bf2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 7 Apr 2023 14:29:07 -0400 Subject: [PATCH 159/468] clang-format --- offline/packages/PHField/PHField2D.cc | 38 ++++++------ .../packages/PHField/PHField3DCartesian.cc | 27 ++++----- offline/packages/PHField/PHField3DCartesian.h | 2 +- .../packages/PHField/PHField3DCylindrical.cc | 60 +++++++++---------- offline/packages/PHField/PHFieldConfig.cc | 2 +- offline/packages/PHField/PHFieldConfig.h | 2 +- offline/packages/PHField/PHFieldConfigv1.cc | 2 +- offline/packages/PHField/PHFieldConfigv1.h | 5 +- offline/packages/PHField/PHFieldConfigv2.cc | 2 +- offline/packages/PHField/PHFieldConfigv2.h | 5 +- offline/packages/PHField/PHFieldUniform.cc | 2 +- offline/packages/PHField/PHFieldUtility.cc | 4 +- offline/packages/PHField/PHFieldUtility.h | 2 +- 13 files changed, 75 insertions(+), 78 deletions(-) diff --git a/offline/packages/PHField/PHField2D.cc b/offline/packages/PHField/PHField2D.cc index 75b4b5d2d5..15570a3f0d 100644 --- a/offline/packages/PHField/PHField2D.cc +++ b/offline/packages/PHField/PHField2D.cc @@ -1,6 +1,6 @@ #include "PHField2D.h" -//root framework +// root framework #include #include #include @@ -78,16 +78,16 @@ PHField2D::PHField2D(const std::string &filename, const int verb, const float ma if (Verbosity() > 1) { std::cout << "\n NENTRIES should be the same as the following values:" - << "\n [ Number of values r,z: " - << nr << " " << nz << " ]! " << std::endl; + << "\n [ Number of values r,z: " + << nr << " " << nz << " ]! " << std::endl; } if (nz != nr) { std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - << "\n The file you entered is not a \"table\" of values" - << "\n Something very likely went oh so wrong" - << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + << "\n The file you entered is not a \"table\" of values" + << "\n Something very likely went oh so wrong" + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; } // Keep track of the unique z, r, phi values in the grid using sets @@ -202,10 +202,10 @@ PHField2D::PHField2D(const std::string &filename, const int verb, const float ma print_map(iter); std::cout << " B(" - << r_map_[ir] << ", " - << z_map_[iz] << "): (" - << BFieldR_[iz][ir] << ", " - << BFieldZ_[iz][ir] << ")" << std::endl; + << r_map_[ir] << ", " + << z_map_[iz] << "): (" + << BFieldR_[iz][ir] << ", " + << BFieldZ_[iz][ir] << ")" << std::endl; } } // end loop over root field map file @@ -276,8 +276,8 @@ void PHField2D::GetFieldValue(const double point[4], double *Bfield) const if (Verbosity() > 2) { std::cout << "END PHField2D::GetFieldValue\n" - << " ---> {Bx, By, Bz} : " - << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; + << " ---> {Bx, By, Bz} : " + << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; } return; @@ -403,8 +403,8 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const if (Verbosity() > 2) { std::cout << "End GFCyl Call: : {" - << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" - << std::endl; + << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" + << std::endl; } return; @@ -414,10 +414,10 @@ void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const void PHField2D::print_map(std::map::iterator &it) const { std::cout << " Key: <" - << std::get<0>(it->first) / cm << "," - << std::get<1>(it->first) / cm << ">" + << std::get<0>(it->first) / cm << "," + << std::get<1>(it->first) / cm << ">" - << " Value: <" - << std::get<0>(it->second) / magfield_unit << "," - << std::get<1>(it->second) / magfield_unit << ">" << std::endl; + << " Value: <" + << std::get<0>(it->second) / magfield_unit << "," + << std::get<1>(it->second) / magfield_unit << ">" << std::endl; } diff --git a/offline/packages/PHField/PHField3DCartesian.cc b/offline/packages/PHField/PHField3DCartesian.cc index 5f3f04c19e..389f1ab833 100644 --- a/offline/packages/PHField/PHField3DCartesian.cc +++ b/offline/packages/PHField/PHField3DCartesian.cc @@ -23,7 +23,6 @@ #include #include - PHField3DCartesian::PHField3DCartesian(const std::string &fname, const float magfield_rescale, const float innerradius, const float outerradius, const float size_z) : filename(fname) { @@ -64,7 +63,7 @@ PHField3DCartesian::PHField3DCartesian(const std::string &fname, const float mag if (field_map == nullptr) { std::cout << PHWHERE << " Could not load fieldmap ntuple from " - << filename << " exiting now" << std::endl; + << filename << " exiting now" << std::endl; gSystem->Exit(1); exit(1); } @@ -85,8 +84,8 @@ PHField3DCartesian::PHField3DCartesian(const std::string &fname, const float mag yvals.insert(ROOT_Y * cm); zvals.insert(ROOT_Z * cm); if ((std::sqrt(ROOT_X * cm * ROOT_X * cm + ROOT_Y * cm * ROOT_Y * cm) >= innerradius && - std::sqrt(ROOT_X * cm * ROOT_X * cm + ROOT_Y * cm * ROOT_Y * cm) <= outerradius) || - std::abs(ROOT_Z * cm) > size_z ) + std::sqrt(ROOT_X * cm * ROOT_X * cm + ROOT_Y * cm * ROOT_Y * cm) <= outerradius) || + std::abs(ROOT_Z * cm) > size_z) { fieldmap[coord_key] = field_val; } @@ -247,7 +246,7 @@ void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) co if (magval == fieldmap.end()) { std::cout << PHWHERE << " could not locate key in " << filename - << " value: x: " << xkey[i] / cm + << " value: x: " << xkey[i] / cm << ", y: " << ykey[j] / cm << ", z: " << zkey[k] / cm << std::endl; return; @@ -293,15 +292,15 @@ void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) co // linear extrapolation in cube: - //Vxyz = - //V000 * x * y * z + - //V100 * (1 - x) * y * z + - //V010 * x * (1 - y) * z + - //V001 * x y * (1 - z) + - //V101 * (1 - x) * y * (1 - z) + - //V011 * x * (1 - y) * (1 - z) + - //V110 * (1 - x) * (1 - y) * z + - //V111 * (1 - x) * (1 - y) * (1 - z) + // Vxyz = + // V000 * x * y * z + + // V100 * (1 - x) * y * z + + // V010 * x * (1 - y) * z + + // V001 * x y * (1 - z) + + // V101 * (1 - x) * y * (1 - z) + + // V011 * x * (1 - y) * (1 - z) + + // V110 * (1 - x) * (1 - y) * z + + // V111 * (1 - x) * (1 - y) * (1 - z) for (int i = 0; i < 3; i++) { diff --git a/offline/packages/PHField/PHField3DCartesian.h b/offline/packages/PHField/PHField3DCartesian.h index ae1fa9a6de..23d61e3ee9 100644 --- a/offline/packages/PHField/PHField3DCartesian.h +++ b/offline/packages/PHField/PHField3DCartesian.h @@ -12,7 +12,7 @@ class PHField3DCartesian : public PHField { public: -explicit PHField3DCartesian(const std::string &fname, const float magfield_rescale = 1.0, const float innerradius = 0, const float outerradius = 1.e10, const float size_z = 1.e10); + explicit PHField3DCartesian(const std::string &fname, const float magfield_rescale = 1.0, const float innerradius = 0, const float outerradius = 1.e10, const float size_z = 1.e10); ~PHField3DCartesian() override; //! access field value diff --git a/offline/packages/PHField/PHField3DCylindrical.cc b/offline/packages/PHField/PHField3DCylindrical.cc index 9dce27304a..c91ab1c204 100644 --- a/offline/packages/PHField/PHField3DCylindrical.cc +++ b/offline/packages/PHField/PHField3DCylindrical.cc @@ -20,8 +20,8 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in { std::cout << "\n================ Begin Construct Mag Field =====================" << std::endl; std::cout << "\n-----------------------------------------------------------" - << "\n Magnetic field Module - Verbosity:" << Verbosity() - << "\n-----------------------------------------------------------"; + << "\n Magnetic field Module - Verbosity:" << Verbosity() + << "\n-----------------------------------------------------------"; // open file TFile *rootinput = TFile::Open(filename.c_str()); @@ -31,8 +31,8 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in exit(1); } std::cout << "\n ---> " - "Reading the field grid from " - << filename << " ... " << std::endl; + "Reading the field grid from " + << filename << " ... " << std::endl; rootinput->cd(); // get root NTuple objects @@ -58,16 +58,16 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in if (Verbosity() > 0) { std::cout << "\n NENTRIES should be the same as the following values:" - << "\n [ Number of values r,phi,z: " - << nr << " " << nphi << " " << nz << " ]! " << std::endl; + << "\n [ Number of values r,phi,z: " + << nr << " " << nphi << " " << nz << " ]! " << std::endl; } if (nz != nr || nz != nphi || nr != nphi) { std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" - << "\n The file you entered is not a \"table\" of values" - << "\n Something very likely went oh so wrong" - << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + << "\n The file you entered is not a \"table\" of values" + << "\n Something very likely went oh so wrong" + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; } // Keep track of the unique z, r, phi values in the grid using sets @@ -196,12 +196,12 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in print_map(iter); std::cout << " B(" - << r_map_[ir] << ", " - << phi_map_[iphi] << ", " - << z_map_[iz] << "): (" - << BFieldR_[iz][ir][iphi] << ", " - << BFieldPHI_[iz][ir][iphi] << ", " - << BFieldZ_[iz][ir][iphi] << ")" << std::endl; + << r_map_[ir] << ", " + << phi_map_[iphi] << ", " + << z_map_[iz] << "): (" + << BFieldR_[iz][ir][iphi] << ", " + << BFieldPHI_[iz][ir][iphi] << ", " + << BFieldZ_[iz][ir][iphi] << ")" << std::endl; } } // end loop over root field map file @@ -209,11 +209,11 @@ PHField3DCylindrical::PHField3DCylindrical(const std::string &filename, const in rootinput->Close(); std::cout << "\n ---> ... read file successfully " - << "\n ---> Z Boundaries ~ zlow, zhigh: " - << minz_ / cm << "," << maxz_ / cm << " cm " << std::endl; + << "\n ---> Z Boundaries ~ zlow, zhigh: " + << minz_ / cm << "," << maxz_ / cm << " cm " << std::endl; std::cout << "\n================= End Construct Mag Field ======================\n" - << std::endl; + << std::endl; } void PHField3DCylindrical::GetFieldValue(const double point[4], double *Bfield) const @@ -273,8 +273,8 @@ void PHField3DCylindrical::GetFieldValue(const double point[4], double *Bfield) if (Verbosity() > 2) { std::cout << "END PHField3DCylindrical::GetFieldValue\n" - << " ---> {Bx, By, Bz} : " - << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; + << " ---> {Bx, By, Bz} : " + << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl; } return; @@ -444,8 +444,8 @@ void PHField3DCylindrical::GetFieldCyl(const double CylPoint[4], double *BfieldC if (Verbosity() > 2) { std::cout << "End GFCyl Call: : {" - << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" - << std::endl; + << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}" + << std::endl; } return; @@ -482,12 +482,12 @@ bool PHField3DCylindrical::bin_search(const std::vector &vec, unsigned st void PHField3DCylindrical::print_map(std::map::iterator &it) const { std::cout << " Key: <" - << std::get<0>(it->first) * cm << "," - << std::get<1>(it->first) * cm << "," - << std::get<2>(it->first) * deg << ">" - - << " Value: <" - << std::get<0>(it->second) * gauss << "," - << std::get<1>(it->second) * gauss << "," - << std::get<2>(it->second) * gauss << ">" << std::endl; + << std::get<0>(it->first) * cm << "," + << std::get<1>(it->first) * cm << "," + << std::get<2>(it->first) * deg << ">" + + << " Value: <" + << std::get<0>(it->second) * gauss << "," + << std::get<1>(it->second) * gauss << "," + << std::get<2>(it->second) * gauss << ">" << std::endl; } diff --git a/offline/packages/PHField/PHFieldConfig.cc b/offline/packages/PHField/PHFieldConfig.cc index f79411aed0..cea9da01b8 100644 --- a/offline/packages/PHField/PHFieldConfig.cc +++ b/offline/packages/PHField/PHFieldConfig.cc @@ -1,7 +1,7 @@ /*! * \file PHFieldConfig.cc - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ diff --git a/offline/packages/PHField/PHFieldConfig.h b/offline/packages/PHField/PHFieldConfig.h index d52363ff86..c17bd4592f 100644 --- a/offline/packages/PHField/PHFieldConfig.h +++ b/offline/packages/PHField/PHFieldConfig.h @@ -1,6 +1,6 @@ /*! * \file PHFieldConfig.h - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ diff --git a/offline/packages/PHField/PHFieldConfigv1.cc b/offline/packages/PHField/PHFieldConfigv1.cc index a4080bf789..4f0a622d66 100644 --- a/offline/packages/PHField/PHFieldConfigv1.cc +++ b/offline/packages/PHField/PHFieldConfigv1.cc @@ -2,7 +2,7 @@ /*! * \file PHFieldConfigv1.cc - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ diff --git a/offline/packages/PHField/PHFieldConfigv1.h b/offline/packages/PHField/PHFieldConfigv1.h index 6da742ae4b..3478e1dbc6 100644 --- a/offline/packages/PHField/PHFieldConfigv1.h +++ b/offline/packages/PHField/PHFieldConfigv1.h @@ -2,7 +2,7 @@ /*! * \file PHFieldConfig_v1.h - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ @@ -49,8 +49,7 @@ class PHFieldConfigv1 : public PHFieldConfig void Reset() override {} /// isValid returns non zero if object contains vailid data - int - isValid() const override; + int isValid() const override; FieldConfigTypes get_field_config() const override { diff --git a/offline/packages/PHField/PHFieldConfigv2.cc b/offline/packages/PHField/PHFieldConfigv2.cc index ccb06912e3..f28a22356c 100644 --- a/offline/packages/PHField/PHFieldConfigv2.cc +++ b/offline/packages/PHField/PHFieldConfigv2.cc @@ -2,7 +2,7 @@ /*! * \file PHFieldConfigv2.cc - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ diff --git a/offline/packages/PHField/PHFieldConfigv2.h b/offline/packages/PHField/PHFieldConfigv2.h index eb0d5affb0..677d3a0417 100644 --- a/offline/packages/PHField/PHFieldConfigv2.h +++ b/offline/packages/PHField/PHFieldConfigv2.h @@ -2,7 +2,7 @@ /*! * \file PHFieldConfigv2.h - * \brief + * \brief * \author Jin Huang * \version $Revision: $ * \date $Date: $ @@ -49,8 +49,7 @@ class PHFieldConfigv2 : public PHFieldConfig void Reset() override {} /// isValid returns non zero if object contains vailid data - int - isValid() const override { return 3; } + int isValid() const override { return 3; } FieldConfigTypes get_field_config() const override { diff --git a/offline/packages/PHField/PHFieldUniform.cc b/offline/packages/PHField/PHFieldUniform.cc index 8c9c0b5ed4..2b04ffc18e 100644 --- a/offline/packages/PHField/PHFieldUniform.cc +++ b/offline/packages/PHField/PHFieldUniform.cc @@ -12,7 +12,7 @@ PHFieldUniform::PHFieldUniform( { } -void PHFieldUniform::GetFieldValue(const double /*point*/ [4], double *Bfield) const +void PHFieldUniform::GetFieldValue(const double /*point*/[4], double *Bfield) const { Bfield[0] = field_mag_x_; Bfield[1] = field_mag_y_; diff --git a/offline/packages/PHField/PHFieldUtility.cc b/offline/packages/PHField/PHFieldUtility.cc index 7de68bfbc8..7742532947 100644 --- a/offline/packages/PHField/PHFieldUtility.cc +++ b/offline/packages/PHField/PHFieldUtility.cc @@ -69,8 +69,8 @@ PHFieldUtility::BuildFieldMap(const PHFieldConfig *field_config, float inner_rad field = new PHField3DCartesian( field_config->get_filename(), field_config->get_magfield_rescale(), - inner_radius, - outer_radius, + inner_radius, + outer_radius, size_z); break; diff --git a/offline/packages/PHField/PHFieldUtility.h b/offline/packages/PHField/PHFieldUtility.h index bd6943cd83..fd80e9f19e 100644 --- a/offline/packages/PHField/PHFieldUtility.h +++ b/offline/packages/PHField/PHFieldUtility.h @@ -31,7 +31,7 @@ class PHFieldUtility //! Build or build field map with a configuration object static PHField * - BuildFieldMap(const PHFieldConfig *field_config, float inner_radius = 0., float outer_radius = 1.e10, float size_z = 1.e10, const int verbosity = 0); + BuildFieldMap(const PHFieldConfig *field_config, float inner_radius = 0., float outer_radius = 1.e10, float size_z = 1.e10, const int verbosity = 0); //! DST node name for RunTime field map object static std::string From e382c07bd86b4e081eced2663e9529f1880b64c9 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Fri, 7 Apr 2023 16:38:24 -0400 Subject: [PATCH 160/468] Simplified AlignmentTransformation procedure. Modified HelicalFitter local derivative calculation to be more straightforward. --- .../HelicalFitter.cc | 272 ++++++++++++++---- .../TrackerMillepedeAlignment/HelicalFitter.h | 22 +- .../trackbase/AlignmentTransformation.cc | 94 +++++- .../trackbase/AlignmentTransformation.h | 3 + offline/packages/trackbase/TrackFitUtils.cc | 6 + 5 files changed, 334 insertions(+), 63 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index e3bb89aa27..111d8bc130 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -99,8 +99,8 @@ int HelicalFitter::process_event(PHCompositeNode*) if(Verbosity() > 0) cout << PHWHERE - << " TPC track map size " << _track_map_tpc->size() - << " Silicon track map size " << _track_map_silicon->size() + << " TPC seed map size " << _track_map_tpc->size() + << " Silicon seed map size " << _track_map_silicon->size() << endl; if(_track_map_silicon->size() == 0 && _track_map_tpc->size() == 0) @@ -135,7 +135,7 @@ int HelicalFitter::process_event(PHCompositeNode*) if(fitpars.size() == 0) continue; // discard this track, not enough clusters to fit - if(Verbosity() > 0) + if(Verbosity() > 1) { std::cout << " Track " << trackid << " radius " << fitpars[0] << " X0 " << fitpars[1]<< " Y0 " << fitpars[2] << " zslope " << fitpars[3] << " Z0 " << fitpars[4] << std::endl; } @@ -153,7 +153,7 @@ int HelicalFitter::process_event(PHCompositeNode*) fitpars = TrackFitUtils::fitClusters(global_vec, cluskey_vec); // do helical fit if(fitpars.size() == 0) continue; // discard this track, fit failed - if(Verbosity() > 0) + if(Verbosity() > 1) { std::cout << " Full track " << trackid << " radius " << fitpars[0] << " X0 " << fitpars[1]<< " Y0 " << fitpars[2] << " zslope " << fitpars[3] << " Z0 " << fitpars[4] << std::endl; } } @@ -169,11 +169,22 @@ int HelicalFitter::process_event(PHCompositeNode*) // PCA of helix to cluster global position ////Acts::Vector3 pca = get_helix_pca(fitpars, global); Acts::Vector3 pca = TrackFitUtils::get_helix_pca(fitpars, global); - if(Verbosity() > 0) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) + if(Verbosity() > 1) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) << " pca " << pca(0) << " " << pca(1) << " " << pca(2) << std::endl;} // capture residuals in the form of (data - fit) auto residual = global - pca; + + unsigned int layer = TrkrDefs::getLayer(cluskey_vec[ivec]); + if(layer < 2) + { + std::cout << " layer " << layer << " phi " << atan2(global(1), global(0)) + << " dx " << global(0) - pca(0) + << " dy " << global(1) - pca(1) + << std::endl; + + } + // need standard deviation of measurements Acts::Vector3 clus_sigma = getClusterError(cluster, cluskey, global); if(isnan(clus_sigma(0)) || isnan(clus_sigma(1)) || isnan(clus_sigma(2))) { continue; } @@ -187,31 +198,31 @@ int HelicalFitter::process_event(PHCompositeNode*) unsigned int crossing = 0; // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster, surf, crossing); + std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster, surf, crossing); // Add the measurement separately for each coordinate direction to Mille // set the derivatives non-zero only for parameters we want to be optimized - unsigned int layer = TrkrDefs::getLayer(cluskey_vec[ivec]); getLocalDerivativesX(pca, fitpars, lcl_derivative); - getGlobalDerivativesX(angleDerivs, glbl_derivative, layer); + getGlobalDerivativesX(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters - { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), clus_sigma(0));} + { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} getLocalDerivativesY(pca, fitpars, lcl_derivative); - getGlobalDerivativesY(angleDerivs, glbl_derivative, layer); + getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " Y buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if( !isnan(residual(1)) && clus_sigma(1) < 1.0) // discards crazy clusters - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), clus_sigma(1));} + {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} unsigned int trkrid = TrkrDefs::getTrkrId(cluskey); - getLocalDerivativesZ(pca, lcl_derivative); - getGlobalDerivativesZ(angleDerivs, glbl_derivative, layer); + getLocalDerivativesZ(pca, fitpars, lcl_derivative); + getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(2, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if(!isnan(residual(2)) && clus_sigma(2) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(2), clus_sigma(2));} + {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(2), _error_inflation*clus_sigma(2));} } // close out this track @@ -298,6 +309,95 @@ Acts::Vector2 HelicalFitter::get_circle_point_pca(float radius, float x0, float return pca; } +std::vector HelicalFitter::getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing) +{ + // The value of global is from the geocontext transformation + // we add to that transformation a small rotation around the relevant axis in the surface frame + + std::vector derivs_vector; + + // get the transformation from the geocontext + Acts::Transform3 transform = surface->transform(_tGeometry->geometry().getGeoContext()); + + // Make an additional transform that applies a small rotation angle in the surface frame + for(unsigned int itrans = 0; itrans < 3; ++itrans) + { + // creates transform that adds a perturbation translation along one axis, uses it to estimate derivative wrt perturbation translation + + unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); + unsigned int layer = TrkrDefs::getLayer(cluster_key); + + Acts::Vector3 derivs(0,0,0); + Eigen::Vector3d theseTransl(0,0,0); + theseTransl[itrans] = sensorTransl[itrans]; // set the one we want to be non-zero + + Acts::Vector3 keeper(0,0,0); + for(int ip = 0; ip < 2; ++ip) + { + if(ip == 1) { theseTransl[itrans] *= -1; } // test both sides of zero + + if(Verbosity() > 1) + { std::cout << " trkrId " << trkrId << " layer " << layer << " cluster_key " << cluster_key + << " sensorTransl " << theseTransl[0] << " " << theseTransl[1] << " " << theseTransl[2] << std::endl; } + + Acts::Transform3 perturbationTranslation = makePerturbationTranslation(theseTransl); + Acts::Transform3 overallTransformation = perturbationTranslation * transform; + + // transform the cluster local position to global coords with this additional translation added + auto x = cluster->getLocalX() * 10; // mm + auto y = cluster->getLocalY() * 10; + if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } + + Eigen::Vector3d clusterLocalPosition (x,y,0); // follows the convention for the acts transform of local = (x,z,y) + Eigen::Vector3d finalCoords = overallTransformation*clusterLocalPosition; // result in mm + finalCoords /= 10.0; // convert mm back to cm + + // have to add corrections for TPC clusters after transformation to global + if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } + + // note that global cancels out here + if(ip == 0) + { + keeper(0) = (finalCoords(0) - global(0)); + keeper(1) = (finalCoords(1) - global(1)); + keeper(2) = (finalCoords(2) - global(2)); + } + else + { + keeper(0) -= (finalCoords(0) - global(0)); + keeper(1) -= (finalCoords(1) - global(1)); + keeper(2) -= (finalCoords(2) - global(2)); + } + + if(Verbosity() > 1) + { + std::cout << " finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " + << finalCoords(1) << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) + << " global(2) " << global(2) << std::endl; + std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " + << keeper(2) << std::endl; + } + } + + // derivs vector contains: + // (dx/dx, dy/dx, dz/dx) (for itrans = 0) + // (dx/dy, dy/dy, dz/dy) (for itrans = 1) + // (dx/dz, dy/dz, dz/dz) (for itrans = 2) + + // Average the changes to get the estimate of the derivative + derivs(0) = keeper(0) / (2.0 * 0.1 * fabs(theseTransl[itrans])); // convert theseTransl to cm + if( isnan(derivs(0)) ) { derivs(0) = 0; } + derivs(1) = keeper(1) / (2.0 * 0.1 * fabs(theseTransl[itrans])); + if( isnan(derivs(1)) ) { derivs(1) = 0; } + derivs(2) = keeper(2) / (2.0 * 0.1 * fabs(theseTransl[itrans])); + if( isnan(derivs(2)) ) { derivs(2) = 0; } + derivs_vector.push_back(derivs); + + if(Verbosity() > 1) { std::cout << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } + } + return derivs_vector; +} + std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing) { // The value of global is from the geocontext transformation @@ -386,9 +486,26 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve return derivs_vector; } + Acts::Transform3 HelicalFitter::makePerturbationTranslation(Acts::Vector3 translations) + { + // combine unit rotation and perturbation translation into an affine matrix + Acts::Transform3 perturbationTransformation; + + Eigen::AngleAxisd alpha(0.0, Eigen::Vector3d::UnitX()); + Eigen::AngleAxisd beta(0.0, Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(0.0, Eigen::Vector3d::UnitZ()); + Eigen::Quaternion q = gamma*beta*alpha; + Eigen::Matrix3d perturbationRotation = q.matrix(); + perturbationTransformation.linear() = perturbationRotation; + + perturbationTransformation.translation() = translations; + + return perturbationTransformation; + } + Acts::Transform3 HelicalFitter::makePerturbationTransformation(Acts::Vector3 angles) { - // Note: Here beta is apllied to the z axis and gamma is applied to the y axis because the geocontext transform + // Note: Here beta is applied to the z axis and gamma is applied to the y axis because the geocontext transform // will flip those axes when transforming to global coordinates Eigen::AngleAxisd alpha(angles(0), Eigen::Vector3d::UnitX()); Eigen::AngleAxisd beta(angles(2), Eigen::Vector3d::UnitY()); @@ -608,20 +725,37 @@ void HelicalFitter::getLocalDerivativesX(Acts::Vector3& pca, std::vector& float radius = fitpars[0]; float x0 = fitpars[1]; float y0 = fitpars[2]; + float x = pca(0); + float y = pca(1); + float dr = 0.2; + float dy0 = 0.05; + + // Do these numerically + + // dx/dradius + // increasing R changes both x and y + float phi = atan2(y-y0, x-x0); + float dxr = dr * cos(phi); + float dx_dr = dxr/dr; + + // dx/dx0 + float dx_dx0 = 1; + + // dx/dy0 + // x = x0 + sqrt(pow(radius, 2) + pow(y-y0, 2)) + float dxy0 = sqrt(pow(radius, 2) + pow(y-y0+dy0, 2)) + - sqrt(pow(radius, 2) + pow(y-y0, 2)); + float dx_dy0 = dxy0/dy0; + + if(Verbosity() > 1) { + std::cout << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; + std::cout << " LclDerivsX: dx_dx0 " << dx_dx0 << " dx_dy0 " << dx_dy0 << " dx_dr " << dx_dr << std::endl; + } - float x_x0 = 1.0; - // dx/dradius = radius / (R^2 - (y-y0)^2)^1/2 , sign of (x-x0)/fabs(x-x0) - float x_radius = ( pca(0)-x0 ) / fabs( pca(0)-x0 ) * radius / sqrt(radius*radius - (pca(1) - y0 ) * (pca(1) - y0 ) ); - if(Verbosity() > 0) {std::cout << " x derivatives: x_x0 " << x_x0 << " x_radius " << x_radius << std::endl;} - if(isnan(x_radius)) {x_radius = 0.0; } - // dx/dy0 = (y-y0) / (R^2 - (y-y0)^2)^1/2 - float x_y0 = (pca(1) - y0) / sqrt(radius*radius - (pca(1) - y0) * (pca(1) - y0)); - if(isnan(x_y0)) {x_y0 = 0.0; } - for(int i=0;i<5;++i) {lcl_derivative[i] = 0.0;} - lcl_derivative[0] = x_x0; - lcl_derivative[1] = x_y0; - lcl_derivative[3] = x_radius; + lcl_derivative[0] = dx_dx0; + lcl_derivative[1] = dx_dy0; + lcl_derivative[3] = dx_dr; } void HelicalFitter::getLocalDerivativesY(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[5]) @@ -629,46 +763,74 @@ void HelicalFitter::getLocalDerivativesY(Acts::Vector3& pca, std::vector& float radius = fitpars[0]; float x0 = fitpars[1]; float y0 = fitpars[2]; - - float y_y0 = 1.0; - // dy/dradius = sign * radius / (R^2 - (x-x0)^2)^1/2 , sign of (y-y0)/fabs(y-y0) - float y_radius = ( pca(1)-y0 ) / fabs( pca(1)-y0 ) * radius / sqrt(radius*radius - (pca(0) - x0 ) * (pca(0) - x0 ) ); - if(Verbosity() > 0) { std::cout << " y derivatives: y_y0 " << y_y0 << " y_radius " << y_radius << std::endl; } - if(isnan(y_radius)) {y_radius = 0.0; } - // dy/dx0 = (x-x0) / (R^2 - (x-x0)^2)^1/2 - float y_x0 = (pca(0) - x0) / sqrt(radius*radius - (pca(0) - x0) * (pca(0) - x0)); - if(isnan(y_x0)) {y_x0 = 0.0; } + float x = pca(0); + float y = pca(1); + float dr = 0.2; + float dx0 = 0.05; + + // dy/dradius + float phi = atan2(y-y0, x-x0); + float dy = dr * sin(phi); + float dy_dr = dy/dr; + + // dy/dy0 + float dy_dy0 = 1.0; + + // dy/dx0 + // y = y0 + sqrt(pow(radius, 2) + pow(x-x0, 2)) + float dyx0 = sqrt(pow(radius, 2) + pow(x-x0+dx0, 2)) + - sqrt(pow(radius, 2) + pow(x-x0, 2)); + float dy_dx0 = dyx0/dx0; + + if(Verbosity() > 1) { + std::cout << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; + std::cout << " LclDerivsY: dy_dy0 " << dy_dy0 << " dy_dx0 " << dy_dx0 << " dy_dr " << dy_dr << std::endl; + } for(int i=0;i& fitpars, float lcl_derivative[5]) { - // z = z0 + zslope * cluster_radius + float zslope = fitpars[3]; float cluster_radius = sqrt(global(0)*global(0)+global(1)*global(1)); - float z_zslope = cluster_radius; - float z_z0 = 1.0; - if(Verbosity() > 0) {std::cout << " z derivatives: z_zslope " << z_zslope << " z_z0 " << z_z0 << std::endl;} + float z0 = fitpars[4]; + + // z = z0 + zslope * cluster_radius + float dz_dz0 = 1.0; + float dz_dzslope = cluster_radius; + // float dz_dradius = zslope; + if(Verbosity() > 1) { + std::cout << " x " << global(0)<<" y "< angleDerivs, float glbl_derivative[], unsigned int layer) + void HelicalFitter::getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { // x - relevant global pars are alpha, beta, gamma, dx (ipar 0,1,2,3), relevant local pars are x_x0, x_radius for(int i=0;i angleDeriv } } -void HelicalFitter::getGlobalDerivativesY( std::vector angleDerivs, float glbl_derivative[], unsigned int layer) +void HelicalFitter::getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { // y - relevant global pars are alpha, beta, gamma, dy (ipar 0,1,2,4) for(int i=0;i angleDeriv } } -void HelicalFitter::getGlobalDerivativesZ( std::vector angleDerivs, float glbl_derivative[], unsigned int layer) +void HelicalFitter::getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { // z - relevant global pars are alpha, beta, dz (ipar 0,1,5) for(int i=0;i fitClusters(std::vector& global_vec, std::vector cluskey_vec); @@ -85,7 +87,9 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface int getLabelBase(Acts::GeometryIdentifier id); Acts::Transform3 makePerturbationTransformation(Acts::Vector3 angles); + Acts::Transform3 makePerturbationTranslation(Acts::Vector3 translations); std::vector getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing); + std::vector getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing); float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); void makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global); int getTpcRegion(int layer); @@ -94,10 +98,10 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface void getGlobalLabels(Surface surf, int glbl_label[]); void getLocalDerivativesX(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[]); void getLocalDerivativesY(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[]); - void getLocalDerivativesZ(Acts::Vector3& global, float lcl_derivative[]); - void getGlobalDerivativesX( std::vector angleDerivs, float glbl_derivatives[], unsigned int layer); - void getGlobalDerivativesY( std::vector angleDerivs, float glbl_derivatives[], unsigned int layer); - void getGlobalDerivativesZ( std::vector angleDerivs, float glbl_derivatives[], unsigned int layer); + void getLocalDerivativesZ(Acts::Vector3& global, std::vector& fitpars, float lcl_derivative[]); + void getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); + void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); + void getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void printBuffers(int index, Acts::Vector3 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); @@ -112,7 +116,8 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface ClusterErrorPara _ClusErrPara; - float sensorAngles[3] = {0.1, 0.1, 0.2}; // perturbation values for each alignment angle + float sensorAngles[3] = {0.01, 0.01, 0.01}; // perturbation values for each alignment angle + float sensorTransl[3] = {0.5, 0.5, 0.5}; // perturbation values for each translation direction (mm) std::set fixed_layers; std::set> fixed_layer_params; @@ -141,11 +146,12 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface static const int NLC = 5; static const int NGL = 6; - bool fitsilicon = false; - bool fittpc = true; - bool fitfulltrack = true; + bool fitsilicon = true; + bool fittpc = false; + bool fitfulltrack = false; float dca_cut = 0.1; // 1 mm + float _error_inflation = 1.0; std::string _field; int _fieldDir = -1; diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index dc4f1781cc..81794f481c 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -86,7 +86,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -108,7 +109,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -136,7 +138,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) for(unsigned int subsurfkey = subsurfkey_min; subsurfkeygeometryId(); if(localVerbosity) @@ -156,7 +159,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) millepedeTranslation = millepedeTranslation + perturbationTranslation; } surf = surfMaps.getMMSurface(hitsetkey); - Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -229,6 +233,30 @@ Eigen::Matrix3d AlignmentTransformation::rotateToGlobal(Surface surf) return globalRotation; } +Eigen::Matrix3d AlignmentTransformation::modifyRotationConvention(Eigen::Matrix3d rotationMatrix) +{ + // Acts uses a rotation matrix that transforms local position (x,z,y) into global position (x',y',z') + // That rotation matrix is obtained from the one we have (which does (x,y,z) to (x',y',z') by: + // exchanging column 2 and 3 (y with z) + // flipping the signs of the original content of column 2 + + Eigen::Matrix3d actsRotationMatrix; + actsRotationMatrix(0,0) = rotationMatrix(0,0); + actsRotationMatrix(1,0) = rotationMatrix(1,0); + actsRotationMatrix(2,0) = rotationMatrix(2,0); + + // flip column 1 and 2 + actsRotationMatrix(0,1) = rotationMatrix(0,2); + actsRotationMatrix(1,1) = rotationMatrix(1,2); + actsRotationMatrix(2,1) = rotationMatrix(2,2); + + actsRotationMatrix(0,2) = -rotationMatrix(0,1); + actsRotationMatrix(1,2) = -rotationMatrix(1,1); + actsRotationMatrix(2,2) = -rotationMatrix(2,1); + + return actsRotationMatrix; +} + Acts::Transform3 AlignmentTransformation::makeAffineMatrix(Eigen::Matrix3d rotationMatrix, Eigen::Vector3d translationVector) { // Acts uses a rotation matrix that transforms local position (x,z,y) into global position (x',y',z') @@ -257,6 +285,64 @@ Acts::Transform3 AlignmentTransformation::makeAffineMatrix(Eigen::Matrix3d rotat return affineMatrix; } +Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen::Vector3d millepedeTranslation, Eigen::Vector3d sensorAngles) +{ + //define null matrices + Eigen::Vector3d nullTranslation(0,0,0); + Eigen::AngleAxisd a(0, Eigen::Vector3d::UnitX()); + Eigen::AngleAxisd b(0, Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd g(0, Eigen::Vector3d::UnitZ()); + Eigen::Quaternion qnull = g*b*a; + Eigen::Matrix3d nullRotation = qnull.matrix(); + + // Create alignment rotation matrix + Eigen::AngleAxisd alpha(sensorAngles(0), Eigen::Vector3d::UnitX()); + Eigen::AngleAxisd beta(sensorAngles(1), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(sensorAngles(2), Eigen::Vector3d::UnitZ()); + Eigen::Quaternion q = gamma*beta*alpha; + Eigen::Matrix3d millepedeRotation = q.matrix(); + + Acts::Transform3 mpRotationAffine; + mpRotationAffine.linear() = millepedeRotation; + mpRotationAffine.translation() = nullTranslation; + + + // create alignment translation matrix + Acts::Transform3 mpTranslationAffine; + mpTranslationAffine.linear() = nullRotation; + mpTranslationAffine.translation() = millepedeTranslation; + + // get the acts transform components + Acts::Transform3 actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); + Eigen::Matrix3d actsRotationPart = actsTransform.rotation(); + Eigen::Vector3d actsTranslationPart = actsTransform.translation(); + + // modify actsRotationPart so that it rotates (x,y,z)->(x',y',z') instead of (x,z,y)->(x',y',z') + Eigen::Matrix3d modifiedActsRotationPart = modifyRotationConvention(actsRotationPart); + + // and make affine matrices from each + Acts::Transform3 actsRotationAffine; + actsRotationAffine.linear() = modifiedActsRotationPart; + actsRotationAffine.translation() = nullTranslation; + Acts::Transform3 actsTranslationAffine; + actsTranslationAffine.linear() = nullRotation; + actsTranslationAffine.translation() = actsTranslationPart; + + //Put them together into a combined transform + + Acts::Transform3 transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; + + if(localVerbosity > 2) + { + std::cout << "mpRotationAffine: "<< std::endl<< mpRotationAffine.matrix() < 0.001) + { + std::cout << " getPCALinePoint: old pca " << posref(0) << " " << posref(1) << " " << posref(2) << std::endl; + std::cout << " getPCALinePoint: new pca " << pca(0) << " " << pca(1) << " " << pca(2) << std::endl; + std::cout << " getPCALinePoint: delta pca " << pca(0) - posref(0) << " " << pca(1)-posref(1) << " " << pca(2) -posref(2) << std::endl; + } return pca; } From a3f3028a15e9a8094c3f6c5f8426c7f42c88df0d Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 8 Apr 2023 06:13:38 -0400 Subject: [PATCH 161/468] stach changes to go to another branch --- .../g4simulation/g4intt/PHG4InttDigitizer.cc | 1 - .../g4simulation/g4intt/PHG4InttHitReco.cc | 468 ++++++------- .../g4simulation/g4intt/PHG4InttHitReco.h | 21 +- .../g4intt/PHG4InttTruthClusterizer.cc | 615 ------------------ .../g4intt/PHG4InttTruthClusterizer.h | 76 --- .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 1 - 6 files changed, 209 insertions(+), 973 deletions(-) delete mode 100644 simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc delete mode 100644 simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index ebd9689ff1..d6362398b5 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -1,7 +1,6 @@ // This is the new trackbase container version #include "PHG4InttDigitizer.h" -#include "PHG4InttTruthClusterizer.h" #include "InttDeadMap.h" #include diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index 437cce74e4..7e87294931 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -1,14 +1,16 @@ #include "PHG4InttHitReco.h" -#include "PHG4InttTruthClusterizer.h" #include #include // for PHG4CylinderGeom #include +#include +#include #include #include #include +#include #include #include // for TrkrHit #include @@ -17,7 +19,6 @@ #include #include #include // for TrkrHit -#include #include // for PHParameterInterface @@ -249,7 +250,7 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) const int sphxlayer = hiter->second->get_detid(); CylinderGeomIntt *layergeom = dynamic_cast(geo->GetLayerGeom(sphxlayer)); - truthcheck_g4hit(g4hit, topNode); + truthcheck_g4hit(hiter->second, topNode); // checking ADC timing integration window cut // uses default values for now @@ -556,65 +557,69 @@ void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { // ----------------------------------------------- // Digitize, adapted from g4intt/PHG4InttDigitizer // ----------------------------------------------- + // + // Note: not using digitization, because as currently implemented, the SvtxTrack clusters + // don't use the adc weighting from the digitization code anyway. + // // don't use the dead map for truth tracks - TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; - hitset_iter != hitset_range.second; - ++hitset_iter) - { - // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer - // get the hitset key so we can find the layer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - const int layer = TrkrDefs::getLayer(hitsetkey); - const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); - const int ladder_z = InttDefs::getLadderZId(hitsetkey); - - if (Verbosity() > 1) - { - std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; - } - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - /* std::set dead_hits; // hits on dead channel */ // no dead channels implemented - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - // ++m_nCells; // not really used by PHG4InttDigitizer - - TrkrHit *hit = hit_iter->second; - TrkrDefs::hitkey hitkey = hit_iter->first; - int strip_col = InttDefs::getCol(hitkey); // strip z index - int strip_row = InttDefs::getRow(hitkey); // strip phi index - - // FIXME need energy scales here - if (_energy_scale.count(layer) > 1) - { - assert(!"Error: _energy_scale has two or more keys."); - } - const float mip_e = _energy_scale[layer]; - - std::vector > vadcrange = _max_fphx_adc[layer]; - - int adc = 0; - for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) - { - if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * - (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup - < vadcrange[irange].second * (double) mip_e) - { - adc = (unsigned short) irange; - } - } - hit->setAdc(adc); - - if (Verbosity() > 2) - { - std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi - << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; - } - } // end loop over hits in this hitset + /* TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); */ + /* for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; */ + /* hitset_iter != hitset_range.second; */ + /* ++hitset_iter) */ + /* { */ + /* // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer */ + /* // get the hitset key so we can find the layer */ + /* TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; */ + /* const int layer = TrkrDefs::getLayer(hitsetkey); */ + /* const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); */ + /* const int ladder_z = InttDefs::getLadderZId(hitsetkey); */ + + /* if (Verbosity() > 1) */ + /* { */ + /* std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; */ + /* } */ + /* // get all of the hits from this hitset */ + /* TrkrHitSet *hitset = hitset_iter->second; */ + /* TrkrHitSet::ConstRange hit_range = hitset->getHits(); */ + /* /1* std::set dead_hits; // hits on dead channel *1/ // no dead channels implemented */ + /* for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; */ + /* hit_iter != hit_range.second; */ + /* ++hit_iter) */ + /* { */ + /* // ++m_nCells; // not really used by PHG4InttDigitizer */ + + /* TrkrHit *hit = hit_iter->second; */ + /* TrkrDefs::hitkey hitkey = hit_iter->first; */ + /* int strip_col = InttDefs::getCol(hitkey); // strip z index */ + /* int strip_row = InttDefs::getRow(hitkey); // strip phi index */ + + /* // FIXME need energy scales here */ + /* if (_energy_scale.count(layer) > 1) */ + /* { */ + /* assert(!"Error: _energy_scale has two or more keys."); */ + /* } */ + /* const float mip_e = _energy_scale[layer]; */ + + /* std::vector > vadcrange = _max_fphx_adc[layer]; */ + + /* int adc = 0; */ + /* for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) */ + /* { */ + /* if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * */ + /* (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup */ + /* < vadcrange[irange].second * (double) mip_e) */ + /* { */ + /* adc = (unsigned short) irange; */ + /* } */ + /* } */ + /* hit->setAdc(adc); */ + + /* if (Verbosity() > 2) */ + /* { */ + /* std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi */ + /* << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; */ + /* } */ + /* } // end loop over hits in this hitset */ /* // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC */ /* for (const auto &key : dead_hits) */ @@ -625,244 +630,171 @@ void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { /* } */ /* hitset->removeHit(key); */ /* } */ - } // end loop over hitsets + /* } // end loop over hitsets */ // ----------------------------------------------- // Cluster, adapted from intt/InttClusterizer // ----------------------------------------------- - if (Verbosity() > 0) - std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl; - - //---------- - // Get Nodes - //---------- + if (Verbosity() > 1) std::cout << "Clustering truth clusters" << std::endl; + //----------- + // Clustering + //----------- // get the geometry node PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); if (!geom_container) return; - //----------- - // Clustering - //----------- // loop over the InttHitSet objects TrkrHitSetContainer::ConstRange hitsetrange = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); // from TruthClusterizerBase + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) + hitsetitr != hitsetrange.second; ++hitsetitr) { // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor - TrkrHitSet *hitset = hitsetitr->second; - + TrkrHitSet* hitset = hitsetitr->second; + TrkrDefs::hitsetkey hitsetkey = hitset->getHitSetKey(); + // cluster this hitset; all pixels in it are, by definition, part of the same clusters - if(Verbosity() > 1) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl; - if (Verbosity() > 2) - hitset->identify(); + if ( Verbosity() > 1 ) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl; + if ( Verbosity() > 2 ) hitset->identify(); // we have a single hitset, get the info that identifies the sensor - int layer = TrkrDefs::getLayer(hitsetitr->first); - int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first); - - // we will need the geometry object for this layer to get the global position - CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); - float pitch = geom->get_strip_y_spacing(); - float length = geom->get_strip_z_spacing(); - - /* // fill a vector of hits to make things easier - gets every hit in the hitset */ - /* std::vector > hitvec; */ - /* TrkrHitSet::ConstRange hitrangei = hitset->getHits(); */ - /* for (TrkrHitSet::ConstIterator hitr = hitrangei.first; */ - /* hitr != hitrangei.second; */ - /* ++hitr) */ - /* { */ - /* hitvec.push_back(std::make_pair(hitr->first, hitr->second)); */ - /* } */ - /* if (Verbosity() > 2) */ - /* std::cout << "hitvec.size(): " << hitvec.size() << std::endl; */ - - /* typedef adjacency_list Graph; */ - /* Graph G; */ - - /* // Find adjacent strips */ - /* for (unsigned int i = 0; i < hitvec.size(); i++) */ - /* { */ - /* for (unsigned int j = i + 1; j < hitvec.size(); j++) */ - /* { */ - /* if (_C__ladder_are_adjacent(hitvec[i], hitvec[j], layer)) */ - /* { */ - /* add_edge(i, j, G); */ - /* } */ - /* } */ - - /* add_edge(i, i, G); */ - /* } */ - - /* // Find the connections between the vertices of the graph (vertices are the rawhits, */ - /* // connections are made when they are adjacent to one another) */ - /* std::vector component(num_vertices(G)); */ - - /* // this is the actual clustering, performed by boost */ - /* connected_components(G, &component[0]); */ - - /* // Loop over the components(hit cells) compiling a list of the */ - /* // unique connected groups (ie. clusters). */ - /* std::set cluster_ids; // unique components */ - - /* std::multimap > clusters; */ - /* for (unsigned int i = 0; i < component.size(); i++) */ - /* { */ - /* cluster_ids.insert(component[i]); // one entry per unique cluster id */ - /* clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id */ - /* } */ - /* // loop over the cluster ID's and make the clusters from the connected hits */ - /* for (std::set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) */ - /* { */ - /* int clusid = *clusiter; */ - //cout << " intt clustering: add cluster number " << clusid << std::endl; - // get all hits for this cluster ID only - /* std::pair>::iterator, */ - /* std::multimap>::iterator> clusrange = clusters.equal_range(clusid); */ - /* std::multimap>::iterator mapiter = clusrange.first; */ - - // make the cluster directly in the node tree - auto hitsetkey = hitset->getHitSetKey(); - TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitsetkey, clusid); - - if (Verbosity() > 2) - std::cout << "Filling cluster with key " << ckey << std::endl; - - // get the bunch crossing number from the hitsetkey - /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */ - - // determine the size of the cluster in phi and z, useful for track fitting the cluster - std::set phibins; - std::set zbins; - - // determine the cluster position... - double xlocalsum = 0.0; - double ylocalsum = 0.0; - double zlocalsum = 0.0; - unsigned int clus_energy = 0.0; - /* unsigned int clus_maxadc = 0.0; */ - unsigned nhits = 0; - - // aggregate the adc values - double sum_energy {0}; - for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) - sum_energy += ihit->getEnergy(); - } + if (Verbosity() > 2) + std::cout << "Filling cluster with hitsetkey " << ((int)hitsetkey) << std::endl; + + // get the bunch crossing number from the hitsetkey + /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */ + + // determine the size of the cluster in phi and z, useful for track fitting the cluster + std::set phibins; + std::set zbins; + + // determine the cluster position... + double xlocalsum = 0.0; + double ylocalsum = 0.0; + double zlocalsum = 0.0; + unsigned int clus_energy = 0.0; + unsigned nhits = 0; + + // aggregate the adc values + double sum_energy {0}; + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { + sum_energy += ihit->second->getEnergy(); + } - // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes - // as the SvtxTrack clusters - const double threshold = sum_energy * m_truth_pixelthreshold; + // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes + // as the SvtxTrack clusters + const double threshold = sum_energy * m_truth_pixelthreshold; - //std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl; - for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) - /* for (mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) */ - { - if (ihit->getEnergy() < threshold) continue; - // mapiter->second.first is the hit key - //cout << " adding hitkey " << mapiter->second.first << std::endl; - int col = InttDefs::getCol( ihit->first); - int row = InttDefs::getRow( (ihit->first); - zbins.insert(col); - phibins.insert(row); - - // mapiter->second.second is the hit - unsigned int hit_adc = ihit->second->getAdc(); - - // now get the positions from the geometry - double local_hit_location[3] = {0., 0., 0.}; - geom->find_strip_center_localcoords(ladder_z_index, row, col, local_hit_location); - - // NOTE: - /* if (_make_e_weights[layer]) */ - /* if ( false ) // the current implementation of the code does not weight by adc values */ - /* // therefore the default here is to use use adc to cut the outliers and nothing else */ - /* { */ - /* xlocalsum += local_hit_location[0] * (double) hit_adc; */ - /* ylocalsum += local_hit_location[1] * (double) hit_adc; */ - /* zlocalsum += local_hit_location[2] * (double) hit_adc; */ - /* } */ - /* else */ - /* { */ - xlocalsum += local_hit_location[0]; - ylocalsum += local_hit_location[1]; - zlocalsum += local_hit_location[2]; - /* } */ - /* if(hit_adc > clus_maxadc) clus_maxadc = hit_adc; */ - clus_energy += hit_adc; - ++nhits; + int layer = TrkrDefs::getLayer ( hitsetkey ); + CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); - // add this cluster-hit association to the association map of (clusterkey,hitkey) - if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl; - if (Verbosity() > 2) + int ladder_z_index = InttDefs::getLadderZId ( hitsetkey ); + + for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { - std::cout << " From geometry object: hit x " << local_hit_location[0] - << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl; - std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " - << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl; - } - } + if (ihit->second->getEnergy() < threshold) continue; - /* static const float invsqrt12 = 1./sqrt(12); */ - // scale factors (phi direction) - /* - they corresponds to clusters of size 1 and 2 in phi - other clusters, which are very few and pathological, get a scale factor of 1 - These scale factors are applied to produce cluster pulls with width unity - */ + clus_energy += ihit->second->getEnergy(); - /* float phierror = pitch * invsqrt12; */ - - /* static constexpr std::array scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; */ - /* if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; */ - /* else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; */ - /* else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; */ - /* // z error. All clusters have a z-size of 1. */ - /* const float zerror = length * invsqrt12; */ + int col = InttDefs::getCol ( ihit->first ); + int row = InttDefs::getRow ( ihit->first ); - double cluslocaly = NAN; - double cluslocalz = NAN; + zbins .insert(col); + phibins .insert(row); - if (_make_e_weights[layer]) - { - cluslocaly = ylocalsum / (double) clus_adc; - cluslocalz = zlocalsum / (double) clus_adc; - } - else - { - cluslocaly = ylocalsum / nhits; - cluslocalz = zlocalsum / nhits; + // now get the positions from the geometry + double local_hit_location[3] = {0., 0., 0.}; + + geom->find_strip_center_localcoords(ladder_z_index, row, col, local_hit_location); + + xlocalsum += local_hit_location[0]; + ylocalsum += local_hit_location[1]; + zlocalsum += local_hit_location[2]; + + ++nhits; + + if (Verbosity() > 6) + { + std::cout << " From geometry object: hit x " << local_hit_location[0] + << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl; + std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " + << ylocalsum / nhits << " clusz " << zlocalsum / nhits << std::endl; + } + // NOTE: + /* if (_make_e_weights[layer]) */ // these values are all false by default + /* if ( false ) // the current implementation of the code does not weight by adc values */ + /* // therefore the default here is to use use adc to cut the outliers and nothing else */ + /* { */ + /* xlocalsum += local_hit_location[0] * (double) hit_adc; */ + /* ylocalsum += local_hit_location[1] * (double) hit_adc; */ + /* zlocalsum += local_hit_location[2] * (double) hit_adc; */ + /* } */ + /* else */ + /* { */ + /* } */ + /* if(hit_adc > clus_maxadc) clus_maxadc = hit_adc; */ //FIXME: do we want this value to be set? + /* clus_energy += hit_adc; */ } - if ( m_cluster_version==4 ){ - auto clus = std::make_unique(); - // Fill the cluster fields - clus->setAdc(clus_adc); - clus->setPhiSize(phibins.size()); - clus->setZSize(1); - - if(Verbosity() > 10) clus->identify(); - - clus->setLocalX(cluslocaly); - clus->setLocalY(cluslocalz); - // silicon has a 1-1 map between hitsetkey and surfaces. So set to - // 0 - clus->setSubSurfKey(0); - - m_hitsetkey_cnt.try_emplace(hitsetkey,0); - unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; - ckey = TrkrDefs::genClusKey(hitsetkey, cnt); - m_truthclusters->addClusterSpecifyKey(ckey, clus.release()); - m_current_track->addCluster(ckey); - ++cnt; - /* m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); */ - + + // add this cluster-hit association to the association map of (clusterkey,hitkey) + if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl; + + /* static const float invsqrt12 = 1./sqrt(12); */ + // scale factors (phi direction) + /* + they corresponds to clusters of size 1 and 2 in phi + other clusters, which are very few and pathological, get a scale factor of 1 + These scale factors are applied to produce cluster pulls with width unity + */ + + /* float phierror = pitch * invsqrt12; */ + + /* static constexpr std::array scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; */ + /* if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; */ + /* else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; */ + /* else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; */ + /* // z error. All clusters have a z-size of 1. */ + /* const float zerror = length * invsqrt12; */ + if (nhits == 0) continue; + + double cluslocaly = ylocalsum / nhits; + double cluslocalz = ylocalsum / nhits; + + //if (_make_e_weights[layer]) // FIXME: this is always false for now + /* { */ + /* cluslocaly = ylocalsum / (double) clus_adc; */ + /* cluslocalz = zlocalsum / (double) clus_adc; */ + /* } */ + /* else */ + /* { */ + /* } */ + if ( m_cluster_version==4 ){ + auto clus = std::make_unique(); + clus->setAdc(clus_energy); + clus->setPhiSize(phibins.size()); + clus->setZSize(1); + + if(Verbosity() > 10) clus->identify(); + + clus->setLocalX(cluslocaly); + clus->setLocalY(cluslocalz); + // silicon has a 1-1 map between hitsetkey and surfaces. So set to 0 + clus->setSubSurfKey(0); + + m_hitsetkey_cnt.try_emplace(hitsetkey,0); + unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; + TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitsetkey, cnt); + m_truthclusters->addClusterSpecifyKey(ckey, clus.release()); + m_current_track->addCluster(ckey); + ++cnt; + } // end loop over hitsets } - } // end loop over hitsets return; } diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.h b/simulation/g4simulation/g4intt/PHG4InttHitReco.h index d4b8250345..921ba996b5 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.h +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.h @@ -4,21 +4,24 @@ #define G4INTT_PHG4INTTHITRECO_H -#include - #include - #include // for gsl_vector +#include +#include #include +#include #include class PHCompositeNode; -class TrkrTruthTrackContainer; +class PHG4Hit; +class PHG4TruthInfoContainer; class TrkrClusterContainer; -class PHG4InttTruthClusterizer; - +class TrkrClusterContainer; +class TrkrHitSetContainer; +class TrkrTruthTrack; +class TrkrTruthTrackContainer; class PHG4InttHitReco : public SubsysReco, public PHParameterInterface { @@ -37,22 +40,16 @@ class PHG4InttHitReco : public SubsysReco, public PHParameterInterface void Detector(const std::string &d) { m_Detector = d; } - PHG4InttTruthClusterizer* get_truth_clusterizer() { return m_truthclusterizer; }; protected: std::string m_Detector = "INTT"; std::string m_HitNodeName; std::string m_CellNodeName; std::string m_GeoNodeName; - TrkrTruthTrackContainer* m_truthtracks { nullptr }; - TrkrClusterContainer* m_truthclusters { nullptr }; - double m_Tmin; double m_Tmax; double m_crossingPeriod; - PHG4InttTruthClusterizer* m_truthclusterizer; - gsl_vector *m_LocalOutVec = nullptr; gsl_vector *m_PathVec = nullptr; gsl_vector *m_SegmentVec = nullptr; diff --git a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc deleted file mode 100644 index 3b45668904..0000000000 --- a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.cc +++ /dev/null @@ -1,615 +0,0 @@ -#include "PHG4InttTruthClusterizer.h" -#include "PHG4InttDigitizer.h" -#include "InttDeadMap.h" - -#include -#include // for Fun4AllBase::VERBOSITY_MORE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for TrkrHit -#include -#include -#include -#include -#include -#include -#include // for exit -#include -#include // for allocator_traits<... -#include -#include // for __decay_and_strip... - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#pragma GCC diagnostic ignored "-Wshadow" -#include -#include -#pragma GCC diagnostic pop - -using namespace boost; -#include - -#include -#include -#include -#include -#include - - -int PHG4InttTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) -{ - _D__DigitizeLadderCells(m_topNode); // adapted from g4intt/PHG4InttDigitizer - _C__ClusterLadderCells(m_topNode, clusters); // adapted from intt/InttClusterizer - - return Fun4AllReturnCodes::EVENT_OK; -} - -PHG4InttTruthClusterizer::PHG4InttTruthClusterizer ( ) { }; - -void PHG4InttTruthClusterizer::init_run(PHCompositeNode*& _topNode, int _verbosity) { - init_clusterizer_base(_topNode, _verbosity); - // from PHG4MvtxDigitizer (_D_) - _D__InitRun(_topNode); - // nothing to do intialize for MvtxHitPruner -} - -void PHG4InttTruthClusterizer::check_g4hit(PHG4Hit* hit) { - if (m_verbosity>10) std::cout << " -> Checking PHG4Hit" << std::endl; - check_g4hit_status(hit); - if (m_was_emb) { - if (m_verbosity>3) { - std::cout << PHWHERE << std::endl - << " -> Pre clustering " << (int) m_hits->size() << " hits" << std::endl; - } - TrkrClusterContainerv4 clusters{}; - clusterize_hits (&clusters); - transfer_clusters (&clusters); - if (m_verbosity>3) { - std::cout << PHWHERE << std::endl - << " -> Clustered " << (int) clusters.size() << " clusters" << std::endl; - } - } - if (m_is_new_track) update_track(); -} - -void PHG4InttTruthClusterizer::end_of_event() { - check_g4hit(nullptr); // flush out last data if ended in truth track - m_hitsetkey_cnt.clear(); - if (m_verbosity>2) { - std::cout << PHWHERE << " :: tracks with clusters after clustering in Intt" << std::endl; - for (auto& track : m_truthtracks->getMap()) { - std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); - for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); - std::cout << std::endl; - } - } -} - - - // --------------------------------------- - // Implementation of: - // (1) g4intt/PHG4InttDigitizer _D__ - // note that no noise is added during the digitization - // --------------------------------------- -int PHG4InttTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) -{ - std::cout << "PHG4InttTruthClusterizer::_D__InitRun: detector = " << detector << std::endl; - //------------- - // Add Hit Node - //------------- - PHNodeIterator iter(topNode); - - // Looking for the DST node - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - _D__CalculateLadderCellADCScale(topNode); - - /* Create the run and par nodes - * These parameters are not currently used in the PHG4InttDigitizer - if (false) { // this will be saved when PHG4InttDigitizer runs -- skip in PHG4InttTruthClusterizer - PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); - PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); - - std::string paramnodename = "G4CELLPARAM_" + detector; - std::string geonodename = "G4CELLGEO_" + detector; - - UpdateParametersWithMacro(); // not used - // save this to the run wise tree to store on DST - PHNodeIterator runIter(runNode); - PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); - if (!RunDetNode) - { - RunDetNode = new PHCompositeNode(detector); - runNode->addNode(RunDetNode); - } - SaveToNodeTree(RunDetNode, paramnodename); - // save this to the parNode for use - PHNodeIterator parIter(parNode); - PHCompositeNode *ParDetNode = dynamic_cast(parIter.findFirst("PHCompositeNode", detector)); - if (!ParDetNode) - { - ParDetNode = new PHCompositeNode(detector); - parNode->addNode(ParDetNode); - } - PutOnParNode(ParDetNode, geonodename); - } - - mNoiseMean = get_double_param("NoiseMean"); - mNoiseSigma = get_double_param("NoiseSigma"); - mEnergyPerPair = get_double_param("EnergyPerPair"); - */ - - //---------------- - // Report Settings - //---------------- - - if (Verbosity() > 0) - { - std::cout << "====================== PHG4InttTruthClusterizer::_D__InitRun() =====================" << std::endl; - for (std::map::iterator iter1 = _max_adc.begin(); - iter1 != _max_adc.end(); - ++iter1) - { - std::cout << " Max ADC in Layer #" << iter1->first << " = " << iter1->second << std::endl; - } - for (std::map::iterator iter2 = _energy_scale.begin(); - iter2 != _energy_scale.end(); - ++iter2) - { - std::cout << " Energy per ADC in Layer #" << iter2->first << " = " << 1.0e6 * iter2->second << " keV" << std::endl; - } - std::cout << "===========================================================================" << std::endl; - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -void PHG4InttTruthClusterizer::_D__CalculateLadderCellADCScale(PHCompositeNode* topNode) -{ - // FPHX 3-bit ADC, thresholds are set in "set_fphx_adc_scale". - - //PHG4CellContainer *cells = findNode::getClass(topNode, "G4CELL_INTT"); - PHG4CylinderGeomContainer *geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); - - //if (!geom_container || !cells) return; - if (!geom_container) return; - - PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end(); - for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first; - layeriter != layerrange.second; - ++layeriter) - { - int layer = layeriter->second->get_layer(); - if (_max_fphx_adc.find(layer) == _max_fphx_adc.end()) - { - std::cout << "Error: _max_fphx_adc is not available." << std::endl; - gSystem->Exit(1); - } - float thickness = (layeriter->second)->get_thickness(); // cm - float mip_e = 0.003876 * thickness; // GeV - _energy_scale.insert(std::make_pair(layer, mip_e)); - } - return; -} - - -void PHG4InttTruthClusterizer::_D__DigitizeLadderCells(PHCompositeNode* topNode) { - //--------------------------- - // Get common Nodes - //--------------------------- - const InttDeadMap *deadmap = findNode::getClass(topNode, "DEADMAP_INTT"); - if (Verbosity() >= Fun4AllBase::VERBOSITY_MORE) - { - if (deadmap) - { - std::cout << "PHG4InttDigitizer::DigitizeLadderCells - Use deadmap "; - deadmap->identify(); - } - else - { - std::cout << "PHG4InttDigitizer::DigitizeLadderCells - Can not find deadmap, all channels enabled " << std::endl; - } - } - - // Get the TrkrHitSetContainer node - auto& trkrhitsetcontainer = m_hits; // alias local to name used in PHG4InttDigitizer - //------------- - // Digitization - //------------- - - // We want all hitsets for the Intt - TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::inttId); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; - hitset_iter != hitset_range.second; - ++hitset_iter) - { - // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer - // get the hitset key so we can find the layer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - const int layer = TrkrDefs::getLayer(hitsetkey); - const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); - const int ladder_z = InttDefs::getLadderZId(hitsetkey); - - if (Verbosity() > 1) - { - std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; - } - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - std::set dead_hits; // hits on dead channel - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - // ++m_nCells; // not really used by PHG4InttDigitizer - - TrkrHit *hit = hit_iter->second; - TrkrDefs::hitkey hitkey = hit_iter->first; - int strip_col = InttDefs::getCol(hitkey); // strip z index - int strip_row = InttDefs::getRow(hitkey); // strip phi index - - // Apply deadmap here if desired - if (deadmap) - { - if (deadmap->isDeadChannelIntt( - layer, - ladder_phi, - ladder_z, - strip_col, - strip_row)) - { - // ++m_nDeadCells; // not really used by PHG4InttDigitizer - - if (Verbosity() >= Fun4AllBase::VERBOSITY_MORE) - { - std::cout << "PHG4InttDigitizer::DigitizeLadderCells - dead strip at layer " << layer << ": "; - hit->identify(); - } - - dead_hits.insert(hit_iter->first); // store hitkey of dead channels to be remove later - continue; - } - } // if (deadmap) - - if (_energy_scale.count(layer) > 1) - { - assert(!"Error: _energy_scale has two or more keys."); - } - const float mip_e = _energy_scale[layer]; - - std::vector > vadcrange = _max_fphx_adc[layer]; - - int adc = 0; - for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) - { - if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup < vadcrange[irange].second * (double) mip_e) - { - adc = (unsigned short) irange; - } - } - hit->setAdc(adc); - - if (Verbosity() > 2) - { - std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi - << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; - } - } // end loop over hits in this hitset - - // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC - for (const auto &key : dead_hits) - { - if (Verbosity() > 2) - { - std::cout << " PHG4InttDigitizer: remove hit with key: " << key << std::endl; - } - hitset->removeHit(key); - } - } // end loop over hitsets - return; -} - -void PHG4InttTruthClusterizer::set_adc_scale(const int &layer, const std::vector &userrange) -{ - if (userrange.size() != nadcbins) - { - std::cout << "Error: vector in set_fphx_adc_scale(vector) must have eight elements." << std::endl; - gSystem->Exit(1); - } - //sort(userrange.begin(), userrange.end()); // TODO, causes GLIBC error - - std::vector > vadcrange; - for (unsigned int irange = 0; irange < userrange.size(); ++irange) - { - if (irange == userrange.size() - 1) - { - vadcrange.push_back(std::make_pair(userrange[irange], FLT_MAX)); - } - else - { - vadcrange.push_back(std::make_pair(userrange[irange], userrange[irange + 1])); - } - } - _max_fphx_adc.insert(std::make_pair(layer, vadcrange)); -} - - - -void PHG4InttTruthClusterizer::_C__ClusterLadderCells(PHCompositeNode* topNode, TrkrClusterContainer* m_clusterlist) -{ - if (Verbosity() > 0) - std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl; - - //---------- - // Get Nodes - //---------- - - // get the geometry node - PHG4CylinderGeomContainer* geom_container = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); - if (!geom_container) return; - - //----------- - // Clustering - //----------- - - // loop over the InttHitSet objects - TrkrHitSetContainer::ConstRange hitsetrange = - m_hits->getHitSets(TrkrDefs::TrkrId::inttId); // from TruthClusterizerBase - for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) - { - // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor - TrkrHitSet *hitset = hitsetitr->second; - - if(Verbosity() > 1) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl; - if (Verbosity() > 2) - hitset->identify(); - - // we have a single hitset, get the info that identifies the sensor - int layer = TrkrDefs::getLayer(hitsetitr->first); - int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first); - - // we will need the geometry object for this layer to get the global position - CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); - float pitch = geom->get_strip_y_spacing(); - float length = geom->get_strip_z_spacing(); - - // fill a vector of hits to make things easier - gets every hit in the hitset - std::vector > hitvec; - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - hitvec.push_back(std::make_pair(hitr->first, hitr->second)); - } - if (Verbosity() > 2) - std::cout << "hitvec.size(): " << hitvec.size() << std::endl; - - typedef adjacency_list Graph; - Graph G; - - // Find adjacent strips - for (unsigned int i = 0; i < hitvec.size(); i++) - { - for (unsigned int j = i + 1; j < hitvec.size(); j++) - { - if (_C__ladder_are_adjacent(hitvec[i], hitvec[j], layer)) - { - add_edge(i, j, G); - } - } - - add_edge(i, i, G); - } - - // Find the connections between the vertices of the graph (vertices are the rawhits, - // connections are made when they are adjacent to one another) - std::vector component(num_vertices(G)); - - // this is the actual clustering, performed by boost - connected_components(G, &component[0]); - - // Loop over the components(hit cells) compiling a list of the - // unique connected groups (ie. clusters). - std::set cluster_ids; // unique components - - std::multimap > clusters; - for (unsigned int i = 0; i < component.size(); i++) - { - cluster_ids.insert(component[i]); // one entry per unique cluster id - clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id - } - - // loop over the cluster ID's and make the clusters from the connected hits - for (std::set::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter) - { - int clusid = *clusiter; - //cout << " intt clustering: add cluster number " << clusid << std::endl; - // get all hits for this cluster ID only - std::pair>::iterator, - std::multimap>::iterator> clusrange = clusters.equal_range(clusid); - std::multimap>::iterator mapiter = clusrange.first; - - // make the cluster directly in the node tree - TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); - - if (Verbosity() > 2) - std::cout << "Filling cluster with key " << ckey << std::endl; - - // get the bunch crossing number from the hitsetkey - /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */ - - // determine the size of the cluster in phi and z, useful for track fitting the cluster - std::set phibins; - std::set zbins; - - // determine the cluster position... - double xlocalsum = 0.0; - double ylocalsum = 0.0; - double zlocalsum = 0.0; - unsigned int clus_adc = 0.0; - unsigned int clus_maxadc = 0.0; - unsigned nhits = 0; - - //std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl; - for (mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter) - { - // mapiter->second.first is the hit key - //cout << " adding hitkey " << mapiter->second.first << std::endl; - int col = InttDefs::getCol( (mapiter->second).first); - int row = InttDefs::getRow( (mapiter->second).first); - zbins.insert(col); - phibins.insert(row); - - // mapiter->second.second is the hit - unsigned int hit_adc = (mapiter->second).second->getAdc(); - - // now get the positions from the geometry - double local_hit_location[3] = {0., 0., 0.}; - geom->find_strip_center_localcoords(ladder_z_index, - row, col, - local_hit_location); - - if (_make_e_weights[layer]) - { - xlocalsum += local_hit_location[0] * (double) hit_adc; - ylocalsum += local_hit_location[1] * (double) hit_adc; - zlocalsum += local_hit_location[2] * (double) hit_adc; - } - else - { - xlocalsum += local_hit_location[0]; - ylocalsum += local_hit_location[1]; - zlocalsum += local_hit_location[2]; - } - if(hit_adc > clus_maxadc) - clus_maxadc = hit_adc; - clus_adc += hit_adc; - ++nhits; - - // add this cluster-hit association to the association map of (clusterkey,hitkey) - if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl; - if (Verbosity() > 2) - { - std::cout << " From geometry object: hit x " << local_hit_location[0] << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl; - std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl; - - } - } - - static const float invsqrt12 = 1./sqrt(12); - - // scale factors (phi direction) - /* - they corresponds to clusters of size 1 and 2 in phi - other clusters, which are very few and pathological, get a scale factor of 1 - These scale factors are applied to produce cluster pulls with width unity - */ - - float phierror = pitch * invsqrt12; - - static constexpr std::array scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; - if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; - else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; - else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; - // z error. All clusters have a z-size of 1. - const float zerror = length * invsqrt12; - - double cluslocaly = NAN; - double cluslocalz = NAN; - - if (_make_e_weights[layer]) - { - cluslocaly = ylocalsum / (double) clus_adc; - cluslocalz = zlocalsum / (double) clus_adc; - } - else - { - cluslocaly = ylocalsum / nhits; - cluslocalz = zlocalsum / nhits; - } - if(m_cluster_version==4){ - auto clus = std::make_unique(); - // Fill the cluster fields - clus->setAdc(clus_adc); - clus->setPhiSize(phibins.size()); - clus->setZSize(1); - - if(Verbosity() > 10) clus->identify(); - - clus->setLocalX(cluslocaly); - clus->setLocalY(cluslocalz); - // silicon has a 1-1 map between hitsetkey and surfaces. So set to - // 0 - clus->setSubSurfKey(0); - m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - - }else if(m_cluster_version==5){ - auto clus = std::make_unique(); - clus->setAdc(clus_adc); - clus->setMaxAdc(clus_maxadc); - clus->setLocalX(cluslocaly); - clus->setLocalY(cluslocalz); - clus->setPhiError(phierror); - clus->setZError(zerror); - clus->setPhiSize(phibins.size()); - clus->setZSize(1); - // All silicon surfaces have a 1-1 map to hitsetkey. - // So set subsurface key to 0 - clus->setSubSurfKey(0); - - if (Verbosity() > 2) - clus->identify(); - - m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - } - } // end loop over cluster ID's - } // end loop over hitsets - - return; -} - -bool PHG4InttTruthClusterizer::_C__ladder_are_adjacent( const std::pair &lhs, const std::pair &rhs, const int layer) -{ - if (get_z_clustering(layer)) - { - if (fabs( InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first) ) <= 1) - { - if (fabs( InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first) ) <= 1) - { - return true; - } - } - } - else - if (fabs( InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first) ) == 0) - { - if (fabs( InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first) ) <= 1) - { - return true; - } - } - - return false; -} diff --git a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h b/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h deleted file mode 100644 index b9c5859c31..0000000000 --- a/simulation/g4simulation/g4intt/PHG4InttTruthClusterizer.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef G4INTT_TRUTHCLUSTERIZER__H -#define G4INTT_TRUTHCLUSTERIZER__H - -#include -#include - -class PHCompositeNode; -class TrkrHit; - -class PHG4InttTruthClusterizer : public TruthClusterizerBase { - public: - - PHG4InttTruthClusterizer ( ); - - //void init_run(PHCompositeNode*& _topNode); - - // regular functions (in common iwht PHG4MvtxTruthClusterizer and PHG4TpcTruthClusterizer) - void init_run(PHCompositeNode*& _topnode, int _verbosity); - int clusterize_hits(TrkrClusterContainer*); - void check_g4hit(PHG4Hit*); - void end_of_event(); - ~PHG4InttTruthClusterizer(){}; - - // all data below is implemented for the clusterize_hits() function - // It does the work that the following modules do for SvtxTrack's: - // (1) g4intt/PHG4InttDigitizer -- use prefix _D__ - // (2) intt/InttClusterizer -- use prefix _C__ - - // --------------------------------------- - // (1) g4intt/PHG4InttDigitizer _D__ - // note that no noise is added during the digitization - // --------------------------------------- - public: - void set_adc_scale(const int &layer, const std::vector &userrange); - void _D__DigitizeLadderCells(PHCompositeNode *topNode); - private: - int _D__InitRun(PHCompositeNode* topNode); - void _D__CalculateLadderCellADCScale(PHCompositeNode* topNode); - - // settings - std::map _max_adc; - std::map > > _max_fphx_adc; - std::map _energy_scale; - std::string detector = "INTT"; - const unsigned int nadcbins = 8; - // unsigned int m_nCells = 0; // not really used by PHG4InttDigitizer - // unsigned int m_nDeadCells = 0; // not really used by PHG4InttDigitizer - - // --------------------------------------- - // (2) intt/InttClusterizer _C__ - // --------------------------------------- - public: - void _C__ClusterLadderCells(PHCompositeNode* topNode, TrkrClusterContainer*); - void PrintClusters(PHCompositeNode* topNode); - void set_cluster_version(int value) { m_cluster_version = value; } - - private: - bool _C__ladder_are_adjacent(const std::pair &lhs, const std::pair &rhs, const int layer); - int m_cluster_version = 4; - - void set_z_clustering(const int layer, const bool make_z_clustering) - { _make_z_clustering.insert(std::make_pair(layer, make_z_clustering)); } - bool get_z_clustering(const int layer) const - { - if (_make_z_clustering.find(layer) == _make_z_clustering.end()) return true; - return _make_z_clustering.find(layer)->second; - } - - std::map _thresholds_by_layer; // layer->threshold - std::map _make_z_clustering; // layer->z_clustering_option - std::map _make_e_weights; // layer->energy_weighting_option - -}; - -#endif - diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 76cc4870ce..086d78a9a9 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -13,7 +13,6 @@ #include class PHCompositeNode; -class PHG4MvtxTruthClusterizer; class PHG4TruthInfoContainer; class TrkrClusterContainer; class TrkrHitSetContainer; From 852dfc87d83077d30051eeab38da111f4cac0707 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 8 Apr 2023 06:29:58 -0400 Subject: [PATCH 162/468] more incremental change --- simulation/g4simulation/g4intt/PHG4InttDigitizer.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index 36585dbb3b..8ad4b4409b 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -339,12 +339,6 @@ void PHG4InttDigitizer::set_adc_scale(const int &layer, const std::vectorExit(1); } - //sort(userrange.begin(), userrange.end()); // TODO, causes GLIBC error - - std::vector vadcrange; - for (unsigned int irange = 0; irange < userrange.size(); ++irange) - { - vadcrange.push_back(userrange[irange]); - } - _max_fphx_adc.insert(std::make_pair(layer, vadcrange)); + _max_fphx_adc.insert(std::make_pair(layer, userrange)); + std::sort(_max_fphx_adc[layer].begin(), _max_fphx_adc[layer].end()); } From 644cac5cb5c04226110c5f984189824190c2f68d Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 8 Apr 2023 06:45:17 -0400 Subject: [PATCH 163/468] continued fix -- remove old files --- .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 7 +- .../g4mvtx/PHG4MvtxTruthClusterizer.cc | 425 ------------------ .../g4mvtx/PHG4MvtxTruthClusterizer.h | 75 ---- .../g4simulation/g4tpc/TpcClusterBuilder.cc | 4 - 4 files changed, 3 insertions(+), 508 deletions(-) delete mode 100644 simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc delete mode 100644 simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 1aacf987cf..283cbdc434 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -1,7 +1,6 @@ // this is the new trackbase version #include "PHG4MvtxHitReco.h" -#include "PHG4MvtxTruthClusterizer.h" #include #include @@ -1013,7 +1012,7 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { // make a tunable threshhold for energy in a given hit // -- percentage of someting? (total cluster energy) - double sum_energy; + double sum_energy { 0. }; for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { sum_energy += ihit->second->getEnergy(); } @@ -1024,7 +1023,7 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { double npixels {0.}; for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { - if (ihit->getEnergy()second->getEnergy()first); @@ -1070,7 +1069,7 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { /* if (m_cluster_version==4){ */ if (m_cluster_version == 4) { auto clus = std::make_unique(); - clus->setAdc(pixels); + clus->setAdc(npixels); clus->setLocalX(locclusx); clus->setLocalY(locclusz); diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc deleted file mode 100644 index 0dc7ded5d9..0000000000 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.cc +++ /dev/null @@ -1,425 +0,0 @@ -#include "PHG4MvtxTruthClusterizer.h" -#include "PHG4MvtxDigitizer.h" - -#include - -#include // for TrkrHit -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for PHNode -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::set; -using std::map; -using std::multimap; - -int PHG4MvtxTruthClusterizer::clusterize_hits(TrkrClusterContainer* clusters) -{ - // turn m_hits into clusters, filled into clusters - std::cout << " clusters " << (clusters == nullptr) << std::endl; - _D__DigitizeMvtxLadderCells(); // adapted from PHG4MvtxDigitizer - _P__MvtxHitPruner(); // adapted from mvtx/MvtxHitPruner - _C__ClusterMvtx(clusters); // adapted from mvtx/MvtxClusterizer - return Fun4AllReturnCodes::EVENT_OK; -} - - -PHG4MvtxTruthClusterizer::PHG4MvtxTruthClusterizer ( ) - : _energy_threshold ( 0.95e-6 ) -{ }; - -void PHG4MvtxTruthClusterizer::init_run(PHCompositeNode*& _topNode, int _verbosity) { - init_clusterizer_base(_topNode, _verbosity); - - // from PHG4MvtxDigitizer (_D_) - _D__InitRun(_topNode); - // nothing to do intialize for MvtxHitPruner -} - -void PHG4MvtxTruthClusterizer::check_g4hit(PHG4Hit* hit) { - if (Verbosity()>10) std::cout << " -> Checking PHG4Hit" << std::endl; - check_g4hit_status(hit); - if (m_was_emb) { - if (Verbosity()>3) { - std::cout << PHWHERE << std::endl - << " -> Pre clustering " << (int) m_hits->size() << " hits" << std::endl; - } - TrkrClusterContainerv4 clusters{}; - clusterize_hits (&clusters); - transfer_clusters (&clusters); - if (Verbosity()>3) { - std::cout << PHWHERE << std::endl - << " -> Clustered " << (int) clusters.size() << " clusters" << std::endl; - } - } - if (m_is_new_track) update_track(); -} - -void PHG4MvtxTruthClusterizer::end_of_event() { - check_g4hit(nullptr); // flush out last data if ended in truth track - m_hitsetkey_cnt.clear(); - if (Verbosity()>2) { - std::cout << PHWHERE << " :: tracks with clusters after clustering in MVTX" << std::endl; - for (auto& track : m_truthtracks->getMap()) { - std::cout << " track("<< track.first <<") nclusters: " << track.second->getClusters().size(); - for (auto& cluster : track.second->getClusters()) std::cout << " " << (int) TrkrDefs::getLayer(cluster); - std::cout << std::endl; - } - } -} - -int PHG4MvtxTruthClusterizer::_D__InitRun(PHCompositeNode *topNode) -{ - //------------- - // Add Hit Node - //------------- - PHNodeIterator iter(topNode); - - // Looking for the DST node - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - _D__CalculateMvtxLadderCellADCScale(topNode); - - //---------------- - // Report Settings - //---------------- - - if (Verbosity() > 0) - { - std::cout << "====================== PHG4MvtxTruthClusterizer copy of PHG4MvtxDigitizer::InitRun() =====================" << std::endl; - for (auto &miter : _max_adc) - { - std::cout << " Max ADC in Layer #" << miter.first << " = " << miter.second << std::endl; - } - for (auto &miter : _energy_scale) - { - std::cout << " Energy per ADC in Layer #" << miter.first << " = " << 1.0e6 * miter.second << " keV" << std::endl; - } - std::cout << "===========================================================================" << std::endl; - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -void PHG4MvtxTruthClusterizer::_D__CalculateMvtxLadderCellADCScale(PHCompositeNode *topNode) -{ - // defaults to 8-bit ADC, short-axis MIP placed at 1/4 dynamic range - PHG4CylinderGeomContainer *geom_container = findNode::getClass(topNode, "CYLINDERGEOM_MVTX"); - - if (!geom_container) return; - - if (Verbosity()) std::cout << "Found CYLINDERGEOM_MVTX node" << std::endl; - - PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end(); - for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first; - layeriter != layerrange.second; - ++layeriter) - { - int layer = layeriter->second->get_layer(); - float thickness = (layeriter->second)->get_pixel_thickness(); - float pitch = (layeriter->second)->get_pixel_x(); - float length = (layeriter->second)->get_pixel_z(); - - float minpath = pitch; - if (length < minpath) minpath = length; - if (thickness < minpath) minpath = thickness; - float mip_e = 0.003876 * minpath; - - if (Verbosity()) - std::cout << "mip_e = " << mip_e << std::endl; - - if (_max_adc.find(layer) == _max_adc.end()) - { - _max_adc[layer] = 255; - _energy_scale[layer] = mip_e / 64; - } - } - return; -} - -void PHG4MvtxTruthClusterizer::_D__DigitizeMvtxLadderCells() { - //---------- - // Get Nodes - //---------- - auto trkrhitsetcontainer = m_hits; - - //============= - // Get the TrkrHitSetContainer node - // Digitization - - // We want all hitsets for the Mvtx - TrkrHitSetContainer::ConstRange hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::mvtxId); - for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; - hitset_iter != hitset_range.second; - ++hitset_iter) - { - // we have an iterator to one TrkrHitSet for the mvtx from the trkrHitSetContainer - // get the hitset key so we can find the layer - TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; - int layer = TrkrDefs::getLayer(hitsetkey); - if (Verbosity() > 1) std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; - - // get all of the hits from this hitset - TrkrHitSet *hitset = hitset_iter->second; - TrkrHitSet::ConstRange hit_range = hitset->getHits(); - std::set hits_rm; - for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; - hit_iter != hit_range.second; - ++hit_iter) - { - TrkrHit *hit = hit_iter->second; - - // Convert the signal value to an ADC value and write that to the hit - // Unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); - if (Verbosity() > 0) - std::cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; - // Remove the hits with energy under threshold - bool rm_hit = false; - if ((hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup) < _energy_threshold) - { - if (Verbosity() > 0) std::cout << " remove hit, below energy threshold of " << _energy_threshold << std::endl; - rm_hit = true; - } - unsigned short adc = (unsigned short) (hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup * _energy_scale[layer])); - if (adc > _max_adc[layer]) adc = _max_adc[layer]; - hit->setAdc(adc); - - if (rm_hit) hits_rm.insert(hit_iter->first); - } - - for (const auto &key : hits_rm) - { - if (Verbosity() > 0) std::cout << " PHG4MvtxDigitizer: remove hit with key: " << key << std::endl; - hitset->removeHit(key); - } - } - return; -} - -int PHG4MvtxTruthClusterizer::_P__MvtxHitPruner() { - // We want to combine all strobe values for a given hitset - // Start by looping over all MVTX hitsets and making a map of physical sensor to hitsetkey-with-strobe - //============================================================================= - std::multimap hitset_multimap; // will map (bare hitset, hitset with strobe) - std::set bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero) - - TrkrHitSetContainer::ConstRange hitsetrange = - m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); - for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) - { - auto hitsetkey = hitsetitr->first; - - // get the hitsetkey value for strobe 0 - unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); - unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first); - unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); - auto bare_hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, 0); - - hitset_multimap.insert(std::make_pair(bare_hitsetkey, hitsetkey)); - bare_hitset_set.insert(bare_hitsetkey); - - if(Verbosity() > 0) std::cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; - } - - // Now consolidate all hits into the hitset with strobe 0, and delete the other hitsets - //============================================================== - for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it) - { - auto bare_hitsetkey = *bare_it; - TrkrHitSet* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; - if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl; - - auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey); - for(auto it = bare_hitsetrange.first; it != bare_hitsetrange.second; ++ it) - { - auto hitsetkey = it->second; - - int strobe = MvtxDefs::getStrobeId(hitsetkey); - if(strobe != 0) - { - if(Verbosity() > 0) std::cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl; - - // copy all hits to the hitset with strobe 0 - TrkrHitSet* hitset = m_hits->findHitSet(hitsetkey); - - if(Verbosity() > 0) - std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl; - - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) - { - auto hitkey = hitr->first; - if(Verbosity() > 0) std::cout << " found hitkey " << hitkey << std::endl; - // if it is already there, leave it alone, this is a duplicate hit - auto tmp_hit = bare_hitset->getHit(hitkey); - if(tmp_hit) - { - if(Verbosity() > 0) std::cout << " hitkey " << hitkey << " is already in bare hitsest, do not copy" << std::endl; - continue; - } - - // otherwise copy the hit over - if(Verbosity() > 0) std::cout << " copying over hitkey " << hitkey << std::endl; - auto old_hit = hitr->second; - TrkrHit *new_hit = new TrkrHitv2(); - new_hit->setAdc(old_hit->getAdc()); - bare_hitset->addHitSpecificKey(hitkey, new_hit); - } - - // all hits are copied over to the strobe zero hitset, remove this hitset - m_hits->removeHitSet(hitsetkey); - } - } - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -// --------------------------------------- -// mvtx/MvtxClusterizer _C__ -// --------------------------------------- -void PHG4MvtxTruthClusterizer::_C__ClusterMvtx(TrkrClusterContainer* m_clusterlist) { - // already inherit m_hits from class - if (Verbosity() > 0) - std::cout << "Entering PHG4MvtxTruthClusterizer::_C__ MvtxClusterizer::ClusterMvtx " << std::endl; - - PHG4CylinderGeomContainer* geom_container = findNode::getClass(m_topNode, "CYLINDERGEOM_MVTX"); - if (!geom_container) return; - - //----------- - // Clustering - //----------- - - // loop over each MvtxHitSet object (chip) - TrkrHitSetContainer::ConstRange hitsetrange = - m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); - for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) - { // hitsetitr : pair(TrkrDefs::hitsetkey, TrkrHitSet>; TrkrHitSet : map - TrkrHitSet *hitset = hitsetitr->second; // hitset : map - - if(Verbosity() > 0) - { - unsigned int layer = TrkrDefs::getLayer (hitsetitr ->first); - unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first); - unsigned int chip = MvtxDefs::getChipId (hitsetitr ->first); - unsigned int strobe = MvtxDefs::getStrobeId (hitsetitr ->first); - std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << std::endl; - } - - if (Verbosity() > 2) - hitset->identify(); - - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - - auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), 0); // there is only one cluster made per cluskey - - // determine the size of the cluster in phi and z - set phibins; - set zbins; - - // determine the cluster position... - double locxsum = 0.; - double loczsum = 0.; - - double locclusx = NAN; - double locclusz = NAN; - - // we need the geometry object for this layer to get the global positions - int layer = TrkrDefs::getLayer(ckey); - auto layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); - if (!layergeom) - exit(1); - - const unsigned int nhits = std::distance( hitrangei.first, hitrangei.second ); - for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) - { - // size - int col = MvtxDefs::getCol( ihit->first); - int row = MvtxDefs::getRow( ihit->first); - zbins.insert(col); - phibins.insert(row); - - // get local coordinates, in stave reference frame, for hit - auto local_coords = layergeom->get_local_coords_from_pixel(row,col); - - /* - manually offset position along y (thickness of the sensor), - to account for effective hit position in the sensor, resulting from diffusion. - Effective position corresponds to 1um above the middle of the sensor - */ - local_coords.SetY( 1e-4 ); - - // update cluster position - locxsum += local_coords.X(); - loczsum += local_coords.Z(); - // add the association between this cluster key and this hitkey to the table - } //mapiter - - // This is the local position - locclusx = locxsum / nhits; - locclusz = loczsum / nhits; - - const double pitch = layergeom->get_pixel_x(); - const double length = layergeom->get_pixel_z(); - const double phisize = phibins.size() * pitch; - const double zsize = zbins.size() * length; - - if(Verbosity() > 0) { - std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize - << " zbins " << zbins.size() << " length " << length << " zsize " << zsize - << " local x " << locclusx << " local y " << locclusz - << std::endl; - } - - // ok force it use use cluster version v4 for now (Valgrind is not happy with application of v5) - /* if (m_cluster_version==4){ */ - if (m_cluster_version == 4) { - auto clus = std::make_unique(); - clus->setAdc(nhits); - clus->setLocalX(locclusx); - clus->setLocalY(locclusz); - - clus->setPhiSize(phibins.size()); - clus->setZSize(zbins.size()); - // All silicon surfaces have a 1-1 map to hitsetkey. - // So set subsurface key to 0 - clus->setSubSurfKey(0); - - if (Verbosity() > 2) - clus->identify(); - - m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); - } else { - std::cout << PHWHERE << std::endl; - std::cout << "Error: only cluster version 4 allowed." << std::endl; - } // loop over hitsets - } - return; -} - diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h b/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h deleted file mode 100644 index 9ae4cba250..0000000000 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxTruthClusterizer.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef G4MVTX_TRUTHCLUSTERIZER__H -#define G4MVTX_TRUTHCLUSTERIZER__H - -#include - -class PHCompositeNode; -class TrkrHit; - -class PHG4MvtxTruthClusterizer : public TruthClusterizerBase { - public: - - PHG4MvtxTruthClusterizer (); - - //void init_run(PHCompositeNode*& _topNode); - - // regular functions (in common iwht PHG4InttTruthClusterizer and PHG4TpcTruthClusterizer) - void init_run ( PHCompositeNode*& _topNode, int _verbosity ); - int clusterize_hits(TrkrClusterContainer*); - void check_g4hit(PHG4Hit*); - void end_of_event(); - ~PHG4MvtxTruthClusterizer(){}; - - // all data below is implemented for the clusterize_hits() function - // It does the work that the following modules do for SvtxTrack's: - // (1) g4mvtx/PHG4MvtxDigitizer -- use prefix _D__ - // (2) mvtx/MvtxHitPruner -- use prefix _P__ - // (3) mvtx/MvtxClusterizer -- use prefix _C__ - - // --------------------------------------- - // (1) g4mvtx/PHG4MvtxDigitizer _D__ - // --------------------------------------- - private: - std::map _max_adc; - std::map _energy_scale; - float _energy_threshold; - public: - // Need to update the G4INTT macro accordingly with the set_adc_scale values - void set_adc_scale(const int layer, const unsigned short max_adc, const float energy_per_adc) - { - _max_adc.insert(std::make_pair(layer, max_adc)); - _energy_scale.insert(std::make_pair(layer, energy_per_adc)); - } - void set_energy_threshold(const float threshold) { _energy_threshold = threshold; } - float _D__get_energy_threshold() { return _energy_threshold; } - - int _D__InitRun (PHCompositeNode *topNode); - void _D__CalculateMvtxLadderCellADCScale (PHCompositeNode *topNode); // called by _D_InitRun - void _D__DigitizeMvtxLadderCells (); - - // --------------------------------------- - // (2) mvtx/MvtxHitPruner _P__ - // --------------------------------------- - public: - int _P__MvtxHitPruner(); - - // --------------------------------------- - // (3) mvtx/MvtxClusterizer _C__ - // --------------------------------------- - private: - bool m_makeZClustering { true }; // z_clustering_option - int m_cluster_version { 4 }; - bool _C__are_adjacent(const std::pair &lhs, const std::pair &rhs); - - public: - void set_cluster_version(int /*value*/) { - std::cout << "None-implemented function in PHG4MvtxTruthClusterizer. " << std::endl - << "Only TrkrClusterv4 currently implemented." << std::endl; - }; - void _C__ClusterMvtx(TrkrClusterContainer* clusters); - bool GetZClustering() const { return m_makeZClustering; }; - void SetZClustering(const bool make_z_clustering) { m_makeZClustering = make_z_clustering; }; - -}; - -#endif diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index 497a56366e..41f41b4dba 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -188,10 +188,6 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { TrkrDefs::cluskey cluskey = TrkrDefs::genClusKey(hitsetkey, hitsetkey_cnt[hitsetkey]); m_clusterlist->addClusterSpecifyKey(cluskey, cluster); - if (false) { // debug print statement - /* cout << hitsetkey_cnt[hitsetkey] << " " << cluster->getLocalX() << std::endl; */ - } - if (current_track != nullptr) current_track->addCluster(cluskey); } From b632b64a2bdfb697ec75de9f4b51fa8adda43be0 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 8 Apr 2023 10:07:01 -0400 Subject: [PATCH 164/468] Updates ready for Jenkins --- .../g4eval/FillTruthRecoMatchTree.cc | 54 ++++++++++++++++--- .../g4eval/FillTruthRecoMatchTree.h | 10 ++-- .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 21 +++----- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index 6800907ef7..ce041e8d9b 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include using std::cout; using std::endl; @@ -30,16 +33,26 @@ FillTruthRecoMatchTree::FillTruthRecoMatchTree( , bool _fill_SvUnMatched , float _cluster_nzwidths , float _cluster_nphiwidths - , const std::string& _tfile_name + , const std::string& _outfile_name ) : - m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } + m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } , m_fill_clusters { _fill_clusters } , m_fill_SvU { _fill_SvUnMatched } + , m_outfile_name { _outfile_name } { m_cluscntr.set_comparer(&m_cluster_comp); - m_tfile = new TFile(_tfile_name.c_str(), "recreate"); - m_tfile->cd(); + PHTFileServer::get().open(m_outfile_name, "RECREATE"); + + h2_G4_nPixelsPhi = new TH2D("G4_nPixelsPhi", "PHG4 Emb Tracks; cluster pixel width Phi; layer", + 100, -0.5, 99.5, 56, -0.5, 55.5); + h2_G4_nPixelsZ = new TH2D("G4_nPixelsZ", "PHG4 Emb Tracks; cluster pixel width Z; layer", + 100, -0.5, 99.5, 56, -0.5, 55.5); + h2_Sv_nPixelsPhi = new TH2D("Sv_nPixelsPhi", "Svtx Reco Tracks; cluster pixel width Phi; layer", + 100, -0.5, 99.5, 56, -0.5, 55.5); + h2_Sv_nPixelsZ = new TH2D("Sv_nPixelsZ", "Svtx Reco Tracks; cluster pixel width Z; layer", + 100, -0.5, 99.5, 56, -0.5, 55.5); + m_ttree = new TTree("T", "Tracks (and sometimes clusters)"); m_ttree->Branch("event", &nevent); @@ -250,6 +263,28 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) nsvtx = m_SvtxTrackMap ->size(); ntrackmatches = m_EmbRecoMatchContainer->getMatches().size(); // get centrality later... + + // fill in pixel widths on truth tracks + + for (auto hitsetkey : m_cluscntr.get_PHG4_clusters()->getHitSetKeys()) { + float layer = (float) TrkrDefs::getLayer(hitsetkey); + auto range = m_cluscntr.get_PHG4_clusters()->getClusters(hitsetkey); + for (auto iter = range.first; iter != range.second; ++iter) { + auto& cluster = iter->second; + h2_G4_nPixelsPhi ->Fill( (float)cluster->getPhiSize(), layer ); + h2_G4_nPixelsZ ->Fill( (float)cluster->getZSize(), layer ); + } + } + // fill in pixel widths on reco tracks + for (auto hitsetkey : m_cluscntr.get_SVTX_clusters()->getHitSetKeys()) { + float layer = (float) TrkrDefs::getLayer(hitsetkey); + auto range = m_cluscntr.get_SVTX_clusters()->getClusters(hitsetkey); + for (auto iter = range.first; iter != range.second; ++iter) { + auto& cluster = iter->second; + h2_Sv_nPixelsPhi ->Fill( (float)cluster->getPhiSize(), layer ); + h2_Sv_nPixelsZ ->Fill( (float)cluster->getZSize(), layer ); + } + } nphg4_part = 0; const auto range = m_PHG4TruthInfoContainer->GetPrimaryParticleRange(); @@ -258,6 +293,7 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) { nphg4_part++; } + // unmatched tracks are only entered once // matches can repeat a given svtx or phg4 track, depending on the // parameters in teh matching in filltruthrecomatchtree @@ -481,10 +517,14 @@ void FillTruthRecoMatchTree::print_mvtx_diagnostics() { int FillTruthRecoMatchTree::End(PHCompositeNode *) { if (Verbosity()>2) std::cout << PHWHERE << ": ending FillTruthRecoMatchTree" << std::endl; - m_tfile->cd(); + PHTFileServer::get().cd(m_outfile_name); + + h2_G4_nPixelsPhi ->Write(); + h2_G4_nPixelsZ ->Write(); + h2_Sv_nPixelsPhi ->Write(); + h2_Sv_nPixelsZ ->Write(); + m_ttree->Write(); - m_tfile->Save(); - m_tfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h index 31cea9a01a..977afbebc7 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.h @@ -62,11 +62,11 @@ class SvtxTrack; class SvtxTrackMap; class TrackSeedContainer; class TrkrCluster; -class TrkrClusterContainer; +/* class TrkrClusterContainer; */ class TrkrTruthTrack; class TrkrTruthTrackContainer; class TTree; -class TFile; +class TH2D; class FillTruthRecoMatchTree : public SubsysReco { @@ -107,10 +107,10 @@ class FillTruthRecoMatchTree : public SubsysReco /* PHG4TpcCylinderGeomContainer *m_PHG4TpcCylinderGeomContainer {nullptr}; */ - TFile* m_tfile; TTree* m_ttree; bool m_fill_clusters; bool m_fill_SvU; // unmatched Svtx tracks + std::string m_outfile_name; // Tree Branch members: int nevent {-1}; @@ -131,6 +131,10 @@ class FillTruthRecoMatchTree : public SubsysReco // clusters: // M : matched // U : unmatched + TH2D* h2_G4_nPixelsPhi; + TH2D* h2_G4_nPixelsZ; + TH2D* h2_Sv_nPixelsPhi; + TH2D* h2_Sv_nPixelsZ; // TRACKS WHICH ARE MATCHED std::vector b_G4M_trackid {}; // g4-track-matched diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 283cbdc434..1367be2e1a 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -661,9 +661,7 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) end_event_truthcluster(topNode); - // FIXME - if (true) { - /* if (Verbosity() > 3) { */ + if (Verbosity() > 3) { int nclusprint = -1; std::cout << PHWHERE << ": content of clusters " << std::endl; auto& tmap = m_truthtracks->getMap(); @@ -973,9 +971,8 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { { // hitsetitr : pair(TrkrDefs::hitsetkey, TrkrHitSet>; TrkrHitSet : map TrkrHitSet *hitset = hitsetitr->second; // hitset : map - // FIXME - /* if(Verbosity() > 0) */ - if (true) + /* if (true) */ + if(Verbosity() > 0) { unsigned int layer = TrkrDefs::getLayer (hitsetitr ->first); unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first); @@ -1056,9 +1053,8 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { const double phisize = phibins.size() * pitch; const double zsize = zbins.size() * length; - // FIXME - if (true) { - /* if(Verbosity() > 0) { */ + /* if (true) { */ + if(Verbosity() > 0) { std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize << " zbins " << zbins.size() << " length " << length << " zsize " << zsize << " local x " << locclusx << " local y " << locclusz @@ -1079,18 +1075,13 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { // So set subsurface key to 0 clus->setSubSurfKey(0); - //FIXME - if (true) - /* if (Verbosity() > 2) */ + if (Verbosity() > 2) clus->identify(); // get the count of how many clusters have allready been added to this hitsetkey (possibly from other embedded tracks tracks) m_hitsetkey_cnt.try_emplace(hitsetkey,0); unsigned int& cnt = m_hitsetkey_cnt[hitsetkey]; ckey = TrkrDefs::genClusKey(hitsetkey, cnt); - //FIXME - if (true) std::cout << " Adding key PLUM to hitsetkey("< 4) std::cout << " Adding key PLUM to hitsetkey("<addClusterSpecifyKey(ckey, clus.release()); m_current_track->addCluster(ckey); ++cnt; From a4dede480e0b89ec6f55adb5b5de1218fd7a561d Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Sat, 8 Apr 2023 10:26:18 -0400 Subject: [PATCH 165/468] Attempt to address Valgrind error A copy of the passed vector needs to be sorted and inserted, therefore change the function signature. --- simulation/g4simulation/g4intt/PHG4InttDigitizer.cc | 4 ++-- simulation/g4simulation/g4intt/PHG4InttDigitizer.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc index 8ad4b4409b..dbcbdea4db 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.cc @@ -332,13 +332,13 @@ float PHG4InttDigitizer::added_noise() return noise; } -void PHG4InttDigitizer::set_adc_scale(const int &layer, const std::vector &userrange) +void PHG4InttDigitizer::set_adc_scale(const int &layer, std::vector userrange) { if (userrange.size() != nadcbins) { std::cout << "Error: vector in set_fphx_adc_scale(vector) must have eight elements." << std::endl; gSystem->Exit(1); } + std::sort(userrange.begin(), userrange.end()); _max_fphx_adc.insert(std::make_pair(layer, userrange)); - std::sort(_max_fphx_adc[layer].begin(), _max_fphx_adc[layer].end()); } diff --git a/simulation/g4simulation/g4intt/PHG4InttDigitizer.h b/simulation/g4simulation/g4intt/PHG4InttDigitizer.h index e9774da632..35695c4b94 100644 --- a/simulation/g4simulation/g4intt/PHG4InttDigitizer.h +++ b/simulation/g4simulation/g4intt/PHG4InttDigitizer.h @@ -33,7 +33,7 @@ class PHG4InttDigitizer : public SubsysReco, public PHParameterInterface void Detector(const std::string &d) { detector = d; } - void set_adc_scale(const int &layer, const std::vector &userrange); + void set_adc_scale(const int &layer, std::vector userrange_copy); private: void CalculateLadderCellADCScale(PHCompositeNode *topNode); From 77c2d5db39140bc226b288d04caa213c390fc57d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 11:01:18 -0400 Subject: [PATCH 166/468] remove obsolete EpdGeomMaker --- offline/packages/epd/EpdGeomMaker.cc | 34 ---------------------------- offline/packages/epd/EpdGeomMaker.h | 23 ------------------- offline/packages/epd/Makefile.am | 20 ++-------------- 3 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 offline/packages/epd/EpdGeomMaker.cc delete mode 100644 offline/packages/epd/EpdGeomMaker.h diff --git a/offline/packages/epd/EpdGeomMaker.cc b/offline/packages/epd/EpdGeomMaker.cc deleted file mode 100644 index 9e12bfec86..0000000000 --- a/offline/packages/epd/EpdGeomMaker.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "EpdGeomMaker.h" - -#include "EpdGeom.h" -#include "EpdGeomV1.h" - -#include - -#include -#include - -#include -#include -#include - -EpdGeomMaker::EpdGeomMaker(const std::string &name) : SubsysReco(name) { - this->epd_geom = new EpdGeomV1(); -} - -EpdGeomMaker::~EpdGeomMaker() { - delete this->epd_geom; -} - -void EpdGeomMaker::CreateNodeTree(PHCompositeNode *topNode) { - // Find the DST node - PHNodeIterator node_itr(topNode); - PHCompositeNode *dst_node = dynamic_cast(node_itr.findFirst("PHCompositeNode", "DST")); - if (!dst_node) { - std::cout << "PHComposite node created: DST" << std::endl; - dst_node = new PHCompositeNode("DST"); - topNode->addNode(dst_node); - } - PHIODataNode *epd_geom_node = new PHIODataNode(this->epd_geom, "EPD_Geometry", "PHObject"); - dst_node->addNode(epd_geom_node); -} \ No newline at end of file diff --git a/offline/packages/epd/EpdGeomMaker.h b/offline/packages/epd/EpdGeomMaker.h deleted file mode 100644 index a58218a8e9..0000000000 --- a/offline/packages/epd/EpdGeomMaker.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -Creates the EPD Geometry object and adds it to the node tree -*/ - -#include "EpdGeom.h" - -#include - -#include - -#include - - -class EpdGeomMaker : public SubsysReco { -public: - EpdGeomMaker(const std::string &name = "EpdGeomMaker"); - ~EpdGeomMaker() override; - - void CreateNodeTree(PHCompositeNode *topNode); - -private: - EpdGeom *epd_geom; -}; \ No newline at end of file diff --git a/offline/packages/epd/Makefile.am b/offline/packages/epd/Makefile.am index 8dfd0037f0..9b84eafa6a 100644 --- a/offline/packages/epd/Makefile.am +++ b/offline/packages/epd/Makefile.am @@ -5,8 +5,7 @@ AUTOMAKE_OPTIONS = foreign # list of shared libraries to produce lib_LTLIBRARIES = \ - libepd_io.la \ - libepd.la + libepd_io.la AM_CPPFLAGS = \ -I$(includedir) \ @@ -23,17 +22,10 @@ libepd_io_la_LIBADD = \ -lphool \ -lcalo_io -libepd_la_LIBADD = \ - libepd_io.la \ - -lgsl \ - -lgslcblas \ - -lSubsysReco - pkginclude_HEADERS = \ EPDDefs.h \ EpdGeom.h \ - EpdGeomV1.h \ - EpdGeomMaker.h + EpdGeomV1.h ROOTDICTS = \ EpdGeom_Dict.cc \ @@ -49,10 +41,6 @@ libepd_io_la_SOURCES = \ $(ROOTDICTS) \ EpdGeomV1.cc -libepd_la_SOURCES = \ - EpdGeomMaker.cc - - # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ @@ -66,12 +54,8 @@ libepd_la_SOURCES = \ BUILT_SOURCES = testexternals.cc noinst_PROGRAMS = \ - testexternals \ testexternals_io -testexternals_SOURCES = testexternals.cc -testexternals_LDADD = libepd.la - testexternals_io_SOURCES = testexternals.cc testexternals_io_LDADD = libepd_io.la From a4eec644628de5718c8df61744c6ba6eb637c903 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 11:03:05 -0400 Subject: [PATCH 167/468] move TOWERGEOM_EPD to EPD composite node under the run node --- simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc index 089b7ddb34..1622f7077c 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc @@ -58,11 +58,20 @@ int PHG4EPDModuleReco::InitRun(PHCompositeNode *topNode) gSystem->Exit(1); exit(1); } + + PHNodeIterator runiter(runNode); + PHCompositeNode *DetNode = dynamic_cast(runiter.findFirst("PHCompositeNode", m_Detector)); + if (!DetNode) + { + DetNode = new PHCompositeNode(m_Detector); + runNode->addNode(DetNode); + } + EpdGeom *epdGeom = findNode::getClass(topNode,"TOWERGEOM_EPD"); if (!epdGeom) { epdGeom = new EpdGeomV1(); PHIODataNode *newNode = new PHIODataNode(epdGeom, "TOWERGEOM_EPD", "PHObject"); - runNode->addNode(newNode); + DetNode->addNode(newNode); } //fill epd geometry From be4ca119b8ad74aa5b80b0b409fed1a5f2bdeec8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 11:03:54 -0400 Subject: [PATCH 168/468] clang-format --- .../g4simulation/g4epd/PHG4EPDModuleReco.cc | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc index 1622f7077c..7023279f00 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc @@ -1,9 +1,9 @@ #include "PHG4EPDModuleReco.h" -#include #include #include #include +#include #include @@ -53,7 +53,8 @@ int PHG4EPDModuleReco::InitRun(PHCompositeNode *topNode) CreateNodes(topNode); PHNodeIterator node_itr(topNode); PHCompositeNode *runNode = dynamic_cast(node_itr.findFirst("PHCompositeNode", "RUN")); - if (!runNode) { + if (!runNode) + { std::cout << PHWHERE << "RUN Node not found - that is fatal" << std::endl; gSystem->Exit(1); exit(1); @@ -67,21 +68,22 @@ int PHG4EPDModuleReco::InitRun(PHCompositeNode *topNode) runNode->addNode(DetNode); } - EpdGeom *epdGeom = findNode::getClass(topNode,"TOWERGEOM_EPD"); - if (!epdGeom) { + EpdGeom *epdGeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdGeom) + { epdGeom = new EpdGeomV1(); PHIODataNode *newNode = new PHIODataNode(epdGeom, "TOWERGEOM_EPD", "PHObject"); DetNode->addNode(newNode); } - - //fill epd geometry + + // fill epd geometry unsigned int epdchannels = 744; for (unsigned int ch = 0; ch < epdchannels; ch++) { unsigned int thiskey = TowerInfoDefs::encode_epd(ch); epdGeom->set_z(thiskey, GetTileZ(TowerInfoDefs::get_epd_arm(thiskey))); epdGeom->set_r(thiskey, GetTileR(TowerInfoDefs::get_epd_rbin(thiskey))); - if(TowerInfoDefs::get_epd_rbin(thiskey) == 0) + if (TowerInfoDefs::get_epd_rbin(thiskey) == 0) { epdGeom->set_phi0(thiskey, GetTilePhi0(TowerInfoDefs::get_epd_phibin(thiskey))); } @@ -90,7 +92,7 @@ int PHG4EPDModuleReco::InitRun(PHCompositeNode *topNode) epdGeom->set_phi(thiskey, GetTilePhi(TowerInfoDefs::get_epd_phibin(thiskey))); } } - + return Fun4AllReturnCodes::EVENT_OK; } @@ -152,12 +154,12 @@ int PHG4EPDModuleReco::process_event(PHCompositeNode *topNode) { unsigned int globalphi = Getphimap(j) + 2 * i; unsigned int r = Getrmap(j); - if (r == 0) - { - globalphi = i; - } + if (r == 0) + { + globalphi = i; + } - unsigned int key = TowerInfoDefs::encode_epd(k,r,globalphi); + unsigned int key = TowerInfoDefs::encode_epd(k, r, globalphi); unsigned int ch = m_TowerInfoContainer->decode_key(key); m_TowerInfoContainer->get_tower_at_channel(ch)->set_energy(m_EpdTile_e[k][i][j]); m_TowerInfoContainer_calib->get_tower_at_channel(ch)->set_energy(m_EpdTile_Calib_e[k][i][j]); @@ -199,15 +201,15 @@ int PHG4EPDModuleReco::Getphimap(int phiindex) float PHG4EPDModuleReco::GetTilePhi(int thisphi) { - static const float tilephi[24] = {0.13089969, 0.39269908, 0.65449847, 0.91629786, 1.17809725,1.43989663, 1.70169602, 1.96349541, 2.2252948 , 2.48709418, 2.74889357, 3.01069296, 3.27249235, 3.53429174, 3.79609112, 4.05789051, 4.3196899 , 4.58148929, 4.84328867, 5.10508806, 5.36688745, 5.62868684, 5.89048623, 6.15228561}; + static const float tilephi[24] = {0.13089969, 0.39269908, 0.65449847, 0.91629786, 1.17809725, 1.43989663, 1.70169602, 1.96349541, 2.2252948, 2.48709418, 2.74889357, 3.01069296, 3.27249235, 3.53429174, 3.79609112, 4.05789051, 4.3196899, 4.58148929, 4.84328867, 5.10508806, 5.36688745, 5.62868684, 5.89048623, 6.15228561}; return tilephi[thisphi]; -} +} float PHG4EPDModuleReco::GetTilePhi0(int thisphi0) { static const float tilephi0[12] = {0.26179939, 0.78539816, 1.30899694, 1.83259571, 2.35619449, 2.87979327, 3.40339204, 3.92699082, 4.45058959, 4.97418837, 5.49778714, 6.02138592}; return tilephi0[thisphi0]; -} +} float PHG4EPDModuleReco::GetTileR(int thisr) { @@ -240,7 +242,7 @@ void PHG4EPDModuleReco::CreateNodes(PHCompositeNode *topNode) dstNode->addNode(DetNode); } - m_TowerInfoNodeName = "TOWERINFO_" + m_EPDSimTowerNodePrefix + "_" + m_Detector; // detector name and prefix are set by now + m_TowerInfoNodeName = "TOWERINFO_" + m_EPDSimTowerNodePrefix + "_" + m_Detector; // detector name and prefix are set by now TowerInfoContainer *m_TowerInfoContainer = findNode::getClass(DetNode, m_TowerInfoNodeName); if (m_TowerInfoContainer == nullptr) { @@ -249,7 +251,7 @@ void PHG4EPDModuleReco::CreateNodes(PHCompositeNode *topNode) DetNode->addNode(TowerInfoNode); } - m_TowerInfoNodeName_calib = "TOWERINFO_" + m_EPDCalibTowerNodePrefix + "_" + m_Detector; // detector name and prefix are set by now + m_TowerInfoNodeName_calib = "TOWERINFO_" + m_EPDCalibTowerNodePrefix + "_" + m_Detector; // detector name and prefix are set by now TowerInfoContainer *m_TowerInfoContainer_calib = findNode::getClass(DetNode, m_TowerInfoNodeName_calib); if (m_TowerInfoContainer_calib == nullptr) { From f416d9b5c8984b7ad4a6e59848acf0f8d86fdaf5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 14:54:34 -0400 Subject: [PATCH 169/468] fix crash for empty hit_times vector --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index 2f2f4d0ab3..658c157e3a 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -352,6 +352,8 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) { for (int iarm = 0; iarm < 2; iarm++) { + if (! hit_times[iarm].empty()) + { std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); float earliest = hit_times[iarm][0]; @@ -370,6 +372,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) _bbcout->AddBbcNS(iarm, f_bbcn[iarm], f_bbcq[iarm], f_bbct[iarm]); } + } } // Now calculate zvtx, t0 from best times From f4b4a29b3631cef2f63233473393a8b1a3eb209f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 14:54:53 -0400 Subject: [PATCH 170/468] clang-format --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 50 ++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index 658c157e3a..a6a23f3f17 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -21,15 +21,15 @@ #include #include +#include #include #include #include #include #include #include -#include -#include #include +#include #include #include @@ -116,7 +116,7 @@ namespace BBCINFO }; */ -} +} // namespace BBCINFO //____________________________________ BbcSimReco::BbcSimReco(const std::string &name) @@ -219,7 +219,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) if (Verbosity()) { std::cout << "VTXP " - << "\t" << f_vx << "\t" << f_vy << "\t" << f_vz << "\t" << f_vt << std::endl; + << "\t" << f_vx << "\t" << f_vy << "\t" << f_vz << "\t" << f_vt << std::endl; } } @@ -260,7 +260,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) if (fabs(this_hit->get_t(1)) < 106.5) { first_time[ch] = this_hit->get_t(1) - vtxp->get_t(); - Float_t dt = gsl_ran_gaussian(m_RandomGenerator, _tres); // get fluctuation in time + Float_t dt = gsl_ran_gaussian(m_RandomGenerator, _tres); // get fluctuation in time first_time[ch] += dt; } else @@ -308,8 +308,8 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) } // Get charge in BBC tube - float npe = len[ich] * (120 / 3.0); // we get 120 p.e. per 3 cm - float dnpe = gsl_ran_gaussian(m_RandomGenerator, std::sqrt(npe)); // get fluctuation in npe + float npe = len[ich] * (120 / 3.0); // we get 120 p.e. per 3 cm + float dnpe = gsl_ran_gaussian(m_RandomGenerator, std::sqrt(npe)); // get fluctuation in npe npe += dnpe; // apply the fluctuations in npe @@ -337,14 +337,12 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) } } - //int ipmt = f_bbcn[0] + f_bbcn[1]; // number of hit pmt + // int ipmt = f_bbcn[0] + f_bbcn[1]; // number of hit pmt _bbcpmts->AddBbcPmt(ich, f_pmtq[ich], f_pmtt0[ich], f_pmtt1[ich]); // threshold should be > 0. ++f_bbcn[arm]; } - - } // Get best t @@ -352,26 +350,26 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) { for (int iarm = 0; iarm < 2; iarm++) { - if (! hit_times[iarm].empty()) + if (!hit_times[iarm].empty()) { - std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); - float earliest = hit_times[iarm][0]; + std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); + float earliest = hit_times[iarm][0]; - gaussian->SetParameter(0, 5); - gaussian->SetParameter(1, earliest); - gaussian->SetRange(6, earliest + 5 * 0.05); - // gaussian->SetParameter(1,hevt_bbct[iarm]->GetMean()); - // gaussian->SetRange(6,hevt_bbct[iarm]->GetMean()+0.125); + gaussian->SetParameter(0, 5); + gaussian->SetParameter(1, earliest); + gaussian->SetRange(6, earliest + 5 * 0.05); + // gaussian->SetParameter(1,hevt_bbct[iarm]->GetMean()); + // gaussian->SetRange(6,hevt_bbct[iarm]->GetMean()+0.125); - hevt_bbct[iarm]->Fit(gaussian, "BLRNQ"); - if (f_bbcn[iarm] > 0) - { - // f_bbct[iarm] = f_bbct[iarm] / f_bbcn[iarm]; - f_bbct[iarm] = gaussian->GetParameter(1); - f_bbcte[iarm] = earliest; + hevt_bbct[iarm]->Fit(gaussian, "BLRNQ"); + if (f_bbcn[iarm] > 0) + { + // f_bbct[iarm] = f_bbct[iarm] / f_bbcn[iarm]; + f_bbct[iarm] = gaussian->GetParameter(1); + f_bbcte[iarm] = earliest; - _bbcout->AddBbcNS(iarm, f_bbcn[iarm], f_bbcq[iarm], f_bbct[iarm]); - } + _bbcout->AddBbcNS(iarm, f_bbcn[iarm], f_bbcq[iarm], f_bbct[iarm]); + } } } From e31e30fb61679b31ba3c7164c584ea39384b449f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 8 Apr 2023 14:55:26 -0400 Subject: [PATCH 171/468] remove dependency on libepd --- offline/packages/TPCHitTrackDisplay/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/TPCHitTrackDisplay/Makefile.am b/offline/packages/TPCHitTrackDisplay/Makefile.am index c62c86622a..54ce516cf5 100644 --- a/offline/packages/TPCHitTrackDisplay/Makefile.am +++ b/offline/packages/TPCHitTrackDisplay/Makefile.am @@ -19,7 +19,6 @@ AM_LDFLAGS = \ libTPCHitTrackDisplay_la_LIBADD = \ -lphool \ -lg4detectors \ - -lepd \ -lcentrality_io \ -lphg4hit \ -lConstituentSubtractor \ From 04cf839f28f51e5aef453125c4bafd08e1dd22d8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 9 Apr 2023 19:08:02 -0400 Subject: [PATCH 172/468] fill bbcns with -999999 if arm has no signal to avoid crashes --- simulation/g4simulation/g4bbc/BbcSimReco.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcSimReco.cc index a6a23f3f17..5cc090c1c7 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcSimReco.cc @@ -370,6 +370,14 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) _bbcout->AddBbcNS(iarm, f_bbcn[iarm], f_bbcq[iarm], f_bbct[iarm]); } + else + { + _bbcout->AddBbcNS(iarm, 0, -99999., -99999.); + } + } + else + { + _bbcout->AddBbcNS(iarm, 0, -99999., -99999.); } } From 4403d47f4275cf4d92190a35a3d2525978eb28c7 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Mon, 10 Apr 2023 07:17:49 -0400 Subject: [PATCH 173/468] fixed a phibinoffset error --- offline/packages/CaloBase/TowerInfoDefs.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoDefs.cc b/offline/packages/CaloBase/TowerInfoDefs.cc index 03f58138ea..1aa6e235c5 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.cc +++ b/offline/packages/CaloBase/TowerInfoDefs.cc @@ -177,9 +177,9 @@ unsigned int TowerInfoDefs::encode_hcal(const unsigned int towerIndex) phibinoffset[0] = 0; - phibinoffset[1] = 8; - phibinoffset[2] = 16; - phibinoffset[3] = 0; + phibinoffset[1] = 2; + phibinoffset[2] = 4; + phibinoffset[3] = 6; ifirst = 0; } From 7cb9fe7cbdf70b1df32843a8af47a53555ba35d4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 10 Apr 2023 09:24:30 -0400 Subject: [PATCH 174/468] remove verbosity --- offline/packages/trackbase/ClusterErrorPara.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 9ac4d7f002..cac17d5774 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -473,11 +473,9 @@ ClusterErrorPara::ClusterErrorPara() } //_________________________________________________________________________________ -ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key) +ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClusterv5* clusterv5, double, TrkrDefs::cluskey key) { - if(cluster_r>300){ - std::cout << " far out " << std::endl; - } + int layer = TrkrDefs::getLayer(key); double phierror = clusterv5->getRPhiError(); From 578ad086842d8b032d43d81a87f8dbf6ea605c13 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 10 Apr 2023 09:57:03 -0400 Subject: [PATCH 175/468] Removed versioning cout statements --- offline/packages/tpc/TpcClusterizer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 90ce0cef57..1b3a340888 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -432,7 +432,7 @@ namespace clus->setActsLocalError(1,1, t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2)); my_data.cluster_vector.push_back(clus); }else if(my_data.cluster_version==4){ - std::cout << "ver4" << std::endl; + //std::cout << "ver4" << std::endl; // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if(sqrt(phi_err_square) > 0.01){ auto clus = new TrkrClusterv4; @@ -451,7 +451,7 @@ namespace my_data.cluster_vector.push_back(clus); } }else if(my_data.cluster_version==5){ - std::cout << "ver5" << std::endl; + //std::cout << "ver5" << std::endl; // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if(sqrt(phi_err_square) > 0.01){ auto clus = new TrkrClusterv5; From 640c8ecb114588f3a361b4e6860c6b8d2554b3a7 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 10 Apr 2023 10:37:22 -0400 Subject: [PATCH 176/468] add resid tree --- .../QA/modules/QAG4SimulationDistortions.cc | 46 +++++++++++++++++++ .../QA/modules/QAG4SimulationDistortions.h | 19 ++++++++ 2 files changed, 65 insertions(+) diff --git a/offline/QA/modules/QAG4SimulationDistortions.cc b/offline/QA/modules/QAG4SimulationDistortions.cc index a57bb43ce8..d9f89c9135 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.cc +++ b/offline/QA/modules/QAG4SimulationDistortions.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,28 @@ int QAG4SimulationDistortions::Init(PHCompositeNode*) h = new TH2F(TString(get_histo_prefix()) + "clusrphi_pulls", "layer; #Deltar#phi_{track-cluster}/#sigma_{r#phi}^{clus}", 57, 0, 57, 100, -5, 5); hm->registerHisto(h); + TTree* t(nullptr); + + t = new TTree(TString(get_histo_prefix()) + "residTree", "tpc residual info"); + t->Branch("tanAlpha", &m_tanAlpha, "tanAlpha/D"); + t->Branch("tanBeta", &m_tanBeta, "tanBeta/D"); + t->Branch("drphi", &m_drphi, "drphi/D"); + t->Branch("dz", &m_dz, "dz/D"); + t->Branch("clusR", &m_clusR, "clusR/D"); + t->Branch("clusPhi", &m_clusPhi, "clusPhi/D"); + t->Branch("clusZ", &m_clusZ, "clusZ/D"); + t->Branch("statePhi", &m_statePhi, "statePhi/D"); + t->Branch("stateZ", &m_stateZ, "stateZ/D"); + t->Branch("stateR", &m_stateR, "stateR/D"); + t->Branch("stateRPhiErr", &m_stateRPhiErr, "stateRPhiErr/D"); + t->Branch("stateZErr", &m_stateZErr, "stateZErr/D"); + t->Branch("clusRPhiErr", &m_clusRPhiErr, "clusRPhiErr/D"); + t->Branch("clusZErr", &m_clusZErr, "clusZErr/D"); + t->Branch("cluskey", &m_cluskey, "cluskey/l"); + t->Branch("event", &m_event, "event/I"); + + hm->registerHisto(t); + return Fun4AllReturnCodes::EVENT_OK; } @@ -195,6 +218,9 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) auto h_clusrphi_pulls = dynamic_cast(hm->getHisto(get_histo_prefix() + "clusrphi_pulls")); assert(h_clusrphi_pulls); + auto t_tree = dynamic_cast(hm->getHisto(get_histo_prefix() + "residTree")); + assert(t_tree); + for (const auto& [key, track] : *m_trackMap) { if (!checkTrack(track)) @@ -288,8 +314,28 @@ int QAG4SimulationDistortions::process_event(PHCompositeNode*) h_staterphi_pulls->Fill(layer, drphi / stateRPhiErr); h_clusz_pulls->Fill(layer, dz / clusZErr); h_clusrphi_pulls->Fill(layer, drphi / clusRPhiErr); + + m_tanAlpha = trackAlpha; + m_tanBeta = trackBeta; + m_drphi = drphi; + m_dz = dz; + m_clusR = clusR; + m_clusPhi = clusPhi; + m_clusZ = clusZ; + m_statePhi = statePhi; + m_stateZ = stateZ; + m_stateR = stateR; + m_stateRPhiErr = stateRPhiErr; + m_stateZErr = stateZErr; + m_clusRPhiErr = clusRPhiErr; + m_clusZErr = clusZErr; + m_cluskey = key; + t_tree->Fill(); } } + + m_event++; + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/QA/modules/QAG4SimulationDistortions.h b/offline/QA/modules/QAG4SimulationDistortions.h index 9ae705bd4a..e2da48f59f 100644 --- a/offline/QA/modules/QAG4SimulationDistortions.h +++ b/offline/QA/modules/QAG4SimulationDistortions.h @@ -6,8 +6,10 @@ #include #include +#include #include #include + class PHCompositeNode; class SvtxTrackMap; class TrkrClusterContainer; @@ -36,6 +38,23 @@ class QAG4SimulationDistortions : public SubsysReco SvtxTrackMap* m_trackMap = nullptr; TrkrClusterContainer* m_clusterContainer = nullptr; ActsGeometry* m_tGeometry = nullptr; + + int m_event = 0; + float m_tanAlpha = NAN; + float m_tanBeta = NAN; + float m_drphi = NAN; + float m_dz = NAN; + float m_clusR = NAN; + float m_clusPhi = NAN; + float m_clusZ = NAN; + float m_statePhi = NAN; + float m_stateZ = NAN; + float m_stateR = NAN; + float m_stateRPhiErr = NAN; + float m_stateZErr = NAN; + float m_clusRPhiErr = NAN; + float m_clusZErr = NAN; + TrkrDefs::cluskey m_cluskey = TrkrDefs::CLUSKEYMAX; }; #endif // QAG4SIMULATIONDISTORTIONS_H From e8deea09758ea78f287b38f2671278337f3e31c3 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 10 Apr 2023 11:32:22 -0400 Subject: [PATCH 177/468] trigger jenkins From 1c0a2fc0a0eb97214c872a9b5acd8e22adf1db1d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 12:00:22 -0400 Subject: [PATCH 178/468] clang-format --- offline/packages/tpc/TpcClusterizer.cc | 1557 +++++++++++++----------- offline/packages/tpc/TpcClusterizer.h | 34 +- 2 files changed, 836 insertions(+), 755 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 8a1e0c7654..a96be538e1 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -2,23 +2,23 @@ #include #include +#include #include #include #include -#include #include // for hitkey, getLayer #include #include -#include #include +#include #include #include -#include #include +#include #include -#include // for SubsysReco +#include // for SubsysReco #include #include @@ -27,10 +27,10 @@ #include #include -#include // for PHIODataNode -#include // for PHNode +#include // for PHIODataNode +#include // for PHNode #include -#include // for PHObject +#include // for PHObject #include #include // for PHWHERE @@ -38,24 +38,28 @@ #include // for TMatrixT, ope... #include // for TMatrixTRow -#include +#include +#include #include // for sqrt, cos, sin #include +#include #include // for _Rb_tree_cons... #include #include // for pair -#include #include #include -#include // Terra incognita.... #include -namespace +namespace { - template inline constexpr T square( const T& x ) { return x*x; } - + template + inline constexpr T square(const T &x) + { + return x * x; + } + using assoc = std::pair; struct ihit @@ -66,10 +70,10 @@ namespace unsigned short edge = 0; }; - struct thread_data + struct thread_data { PHG4TpcCylinderGeom *layergeom = nullptr; - TrkrHitSetTpc *hitset = nullptr; + TrkrHitSet *hitset = nullptr; RawHitSetv1 *rawhitset = nullptr; ActsGeometry *tGeometry = nullptr; unsigned int layer = 0; @@ -94,406 +98,443 @@ namespace double sampa_tbias = 0; int cluster_version = 4; std::vector association_vector; - std::vector cluster_vector; + std::vector cluster_vector; int verbosity = 0; }; - + pthread_mutex_t mythreadlock; - + void remove_hit(double adc, int phibin, int tbin, int edge, std::multimap &all_hit_map, std::vector> &adcval) { typedef std::multimap::iterator hit_iterator; std::pair iterpair = all_hit_map.equal_range(adc); hit_iterator it = iterpair.first; - for (; it != iterpair.second; ++it) { - if (it->second.iphi == phibin && it->second.it == tbin) { - all_hit_map.erase(it); - break; + for (; it != iterpair.second; ++it) + { + if (it->second.iphi == phibin && it->second.it == tbin) + { + all_hit_map.erase(it); + break; } } - if(edge) + if (edge) adcval[phibin][tbin] = USHRT_MAX; else adcval[phibin][tbin] = 0; } - - void remove_hits(std::vector &ihit_list, std::multimap &all_hit_map,std::vector> &adcval) + + void remove_hits(std::vector &ihit_list, std::multimap &all_hit_map, std::vector> &adcval) { - for(auto iter = ihit_list.begin(); iter != ihit_list.end();++iter){ - unsigned short adc = iter->adc; + for (auto iter = ihit_list.begin(); iter != ihit_list.end(); ++iter) + { + unsigned short adc = iter->adc; unsigned short phibin = iter->iphi; - unsigned short tbin = iter->it; - unsigned short edge = iter->edge; - remove_hit(adc,phibin,tbin,edge,all_hit_map,adcval); + unsigned short tbin = iter->it; + unsigned short edge = iter->edge; + remove_hit(adc, phibin, tbin, edge, all_hit_map, adcval); } } - - void find_t_range(int phibin, int tbin, const thread_data& my_data, const std::vector> &adcval, int& tdown, int& tup, int &touch, int &edge){ - - const int FitRangeT= (int) my_data.maxHalfSizeT; + + void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, int &touch, int &edge) + { + const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; tup = 0; tdown = 0; - for(int it=0; it< FitRangeT; it++){ + for (int it = 0; it < FitRangeT; it++) + { int ct = tbin + it; - - if(ct <= 0 || ct >= NTBinsMax){ - // tup = it; - edge++; - break; // truncate edge + + if (ct <= 0 || ct >= NTBinsMax) + { + // tup = it; + edge++; + break; // truncate edge } - - if(adcval[phibin][ct] <= 0) { - break; + + if (adcval[phibin][ct] <= 0) + { + break; } - if(adcval[phibin][ct] == USHRT_MAX) { - touch++; - break; + if (adcval[phibin][ct] == USHRT_MAX) + { + touch++; + break; } - //check local minima and break at minimum. - if(ct= NTBinsMax){ - // tdown = it; - edge++; - break; // truncate edge + if (ct <= 0 || ct >= NTBinsMax) + { + // tdown = it; + edge++; + break; // truncate edge } - if(adcval[phibin][ct] <= 0) { - break; + if (adcval[phibin][ct] <= 0) + { + break; } - if(adcval[phibin][ct] == USHRT_MAX) { - touch++; - break; + if (adcval[phibin][ct] == USHRT_MAX) + { + touch++; + break; } - if(ct>4){//make sure we stay clear from the edge - if(adcval[phibin][ct]+adcval[phibin][ct-1] < - adcval[phibin][ct-2]+adcval[phibin][ct-3]){//rising again - tdown = it+1; - touch++; - break; - } + if (ct > 4) + { // make sure we stay clear from the edge + if (adcval[phibin][ct] + adcval[phibin][ct - 1] < + adcval[phibin][ct - 2] + adcval[phibin][ct - 3]) + { // rising again + tdown = it + 1; + touch++; + break; + } } tdown = it; } return; } - - void find_phi_range(int phibin, int tbin, const thread_data& my_data, const std::vector> &adcval, int& phidown, int& phiup, int &touch, int &edge) + + void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, int &touch, int &edge) { - int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; phidown = 0; phiup = 0; - for(int iphi=0; iphi< FitRangePHI; iphi++){ + for (int iphi = 0; iphi < FitRangePHI; iphi++) + { int cphi = phibin + iphi; - if(cphi < 0 || cphi >= NPhiBinsMax){ - // phiup = iphi; - edge++; - break; // truncate edge + if (cphi < 0 || cphi >= NPhiBinsMax) + { + // phiup = iphi; + edge++; + break; // truncate edge } - - //break when below minimum - if(adcval[cphi][tbin] <= 0) { - // phiup = iphi; - break; + + // break when below minimum + if (adcval[cphi][tbin] <= 0) + { + // phiup = iphi; + break; } - if(adcval[cphi][tbin] == USHRT_MAX) { - touch++; - break; + if (adcval[cphi][tbin] == USHRT_MAX) + { + touch++; + break; } - //check local minima and break at minimum. - if(cphi= NPhiBinsMax){ - // phidown = iphi; - edge++; - break; // truncate edge + if (cphi < 0 || cphi >= NPhiBinsMax) + { + // phidown = iphi; + edge++; + break; // truncate edge } - - if(adcval[cphi][tbin] <= 0) { - //phidown = iphi; - break; + + if (adcval[cphi][tbin] <= 0) + { + // phidown = iphi; + break; } - if(adcval[cphi][tbin] == USHRT_MAX) { - touch++; - break; + if (adcval[cphi][tbin] == USHRT_MAX) + { + touch++; + break; } - if(cphi>4){//make sure we stay clear from the edge - if(adcval[cphi][tbin]+adcval[cphi-1][tbin] < - adcval[cphi-2][tbin]+adcval[cphi-3][tbin]){//rising again - phidown = iphi+1; - touch++; - break; - } + if (cphi > 4) + { // make sure we stay clear from the edge + if (adcval[cphi][tbin] + adcval[cphi - 1][tbin] < + adcval[cphi - 2][tbin] + adcval[cphi - 3][tbin]) + { // rising again + phidown = iphi + 1; + touch++; + break; + } } phidown = iphi; } return; } - - void get_cluster(int phibin, int tbin, const thread_data& my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) - { - // search along phi at the peak in t - - int tup =0; - int tdown =0; - find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); - //now we have the t extent of the cluster, go find the phi edges - - for(int it=tbin - tdown ; it<= tbin + tup; it++){ - int phiup = 0; - int phidown = 0; - find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); - for (int iphi = phibin - phidown; iphi <= (phibin + phiup); iphi++){ - if(adcval[iphi][it]>0 && adcval[iphi][it]!=USHRT_MAX){ - ihit hit; - hit.iphi = iphi; - hit.it = it; - hit.adc = adcval[iphi][it]; - if(touch>0){ - if((iphi == (phibin - phidown))|| - (iphi == (phibin + phiup))){ - hit.edge = 1; - } - } - ihit_list.push_back(hit); - } - } - } - return; - } - - void calc_cluster_parameter(const std::vector &ihit_list, thread_data& my_data, int ntouch, int nedge ) + + void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) + { + // search along phi at the peak in t + + int tup = 0; + int tdown = 0; + find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); + // now we have the t extent of the cluster, go find the phi edges + + for (int it = tbin - tdown; it <= tbin + tup; it++) { - // - // get z range from layer geometry - /* these are used for rescaling the drift velocity */ - //const double z_min = -105.5; - //const double z_max = 105.5; - // std::cout << "calc clus" << std::endl; - // loop over the hits in this cluster - double t_sum = 0.0; - //double phi_sum = 0.0; - double adc_sum = 0.0; - double t2_sum = 0.0; - // double phi2_sum = 0.0; - - double iphi_sum = 0.0; - double iphi2_sum = 0.0; - - double radius = my_data.layergeom->get_radius(); // returns center of layer - - int phibinhi = -1; - int phibinlo = 666666; - int tbinhi = -1; - int tbinlo = 666666; - int clus_size = ihit_list.size(); - int max_adc = 0; - if(clus_size == 1) return; - // std::cout << "process list" << std::endl; - std::vector hitkeyvec; - for(auto iter = ihit_list.begin(); iter != ihit_list.end();++iter){ - double adc = iter->adc; - - if (adc <= 0) continue; - if(adc > max_adc) - max_adc = adc; - int iphi = iter->iphi + my_data.phioffset; - int it = iter->it + my_data.toffset; - if(iphi > phibinhi) phibinhi = iphi; - if(iphi < phibinlo) phibinlo = iphi; - if(it > tbinhi) tbinhi = it; - if(it < tbinlo) tbinlo = it; - - // update phi sums - // double phi_center = my_data.layergeom->get_phicenter(iphi); - - //phi_sum += phi_center * adc; - //phi2_sum += square(phi_center)*adc; - // std::cout << "phi_center: " << phi_center << " adc: " << adc <get_zcenter(it); - t_sum += t*adc; - t2_sum += square(t)*adc; - - adc_sum += adc; - - // capture the hitkeys for all adc values above a certain threshold - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); - // if(adc>5) - hitkeyvec.push_back(hitkey); - } - // std::cout << "done process list" << std::endl; - if (adc_sum < 10){ - hitkeyvec.clear(); - return; // skip obvious noise "clusters" - } - // This is the global position - double clusiphi = iphi_sum / adc_sum; - double clusphi = my_data.layergeom->get_phi(clusiphi); - - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); - double clust = t_sum / adc_sum; - // needed for surface identification - double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); - // convert z drift length to z position in the TPC - double clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; - if(my_data.side == 0) - clusz = -clusz; - - const double phi_cov = (iphi2_sum/adc_sum - square(clusiphi))* pow(my_data.layergeom->get_phistep(),2); - const double t_cov = t2_sum/adc_sum - square(clust); - - // Get the surface key to find the surface from the - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey( my_data.layer, my_data.sector, my_data.side ); - Acts::Vector3 global(clusx, clusy, clusz); - TrkrDefs::subsurfkey subsurfkey = 0; - - Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( - tpcHitSetKey, - global, - subsurfkey); - - if(!surface) - { - /// If the surface can't be found, we can't track with it. So - /// just return and don't add the cluster to the container - hitkeyvec.clear(); - return; - } - - // Estimate the errors - const double phi_err_square = (phibinhi == phibinlo) ? - square(radius*my_data.layergeom->get_phistep())/12: - square(radius)*phi_cov/(adc_sum*0.14); - - const double t_err_square = (tbinhi == tbinlo) ? - square(my_data.layergeom->get_zstep())/12: - t_cov/(adc_sum*0.14); - - char tsize = tbinhi - tbinlo + 1; - char phisize = phibinhi - phibinlo + 1; - // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: - // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi - // - N is the number of electrons that drift to the readout plane - // We have to convert (sum of adc units for all bins in the cluster) to number of ionization electrons N - // Conversion gain is 20 mV/fC - relates total charge collected on pad to PEAK voltage out of ADC. The GEM gain is assumed to be 2000 - // To get equivalent charge per T bin, so that summing ADC input voltage over all T bins returns total input charge, divide voltages by 2.4 for 80 ns SAMPA - // Equivalent charge per T bin is then (ADU x 2200 mV / 1024) / 2.4 x (1/20) fC/mV x (1/1.6e-04) electrons/fC x (1/2000) = ADU x 0.14 - - // SAMPA shaping bias correction - clust = clust + my_data.sampa_tbias; - - /// convert to Acts units - global *= Acts::UnitConstants::cm; - //std::cout << "transform" << std::endl; - Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; - local /= Acts::UnitConstants::cm; - //std::cout << "done transform" << std::endl; - // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) - - if(my_data.cluster_version==3){ - //std::cout << "ver3" << std::endl; - // Fill in the cluster details - //================ - auto clus = new TrkrClusterv3; - //auto clus = std::make_unique(); - clus->setAdc(adc_sum); - clus->setSubSurfKey(subsurfkey); - clus->setLocalX(local(0)); - clus->setLocalY(clust); - clus->setActsLocalError(0,0, phi_err_square); - clus->setActsLocalError(1,0, 0); - clus->setActsLocalError(0,1, 0); - clus->setActsLocalError(1,1, t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2)); - my_data.cluster_vector.push_back(clus); - }else if(my_data.cluster_version==4){ - //std::cout << "ver4" << std::endl; - // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; - if(sqrt(phi_err_square) > 0.01){ - auto clus = new TrkrClusterv4; - //auto clus = std::make_unique(); - clus->setAdc(adc_sum); - clus->setMaxAdc(max_adc); - clus->setOverlap(ntouch); - clus->setEdge(nedge); - clus->setPhiSize(phisize); - clus->setZSize(tsize); - clus->setSubSurfKey(subsurfkey); - clus->setLocalX(local(0)); - clus->setLocalY(clust); - // clus->setPhiErr(sqrt(phi_err_square)); - //clus->setZErr(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2))); - my_data.cluster_vector.push_back(clus); - } - }else if(my_data.cluster_version==5){ - //std::cout << "ver5" << std::endl; - // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; - if(sqrt(phi_err_square) > 0.01){ - auto clus = new TrkrClusterv5; - //auto clus = std::make_unique(); - clus->setAdc(adc_sum); - clus->setMaxAdc(max_adc); - clus->setEdge(nedge); - clus->setPhiSize(phisize); - clus->setZSize(tsize); - clus->setSubSurfKey(subsurfkey); - clus->setLocalX(local(0)); - clus->setLocalY(clust); - clus->setPhiError(sqrt(phi_err_square)); - clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2))); - my_data.cluster_vector.push_back(clus); - } - } - - //std::cout << "end clus out" << std::endl; - // if(my_data.do_assoc && my_data.clusterhitassoc){ - if(my_data.do_assoc) - { - // get cluster index in vector. It is used to store associations, and build relevant cluster keys when filling the containers - uint32_t index = my_data.cluster_vector.size()-1; - for (unsigned int i = 0; i < hitkeyvec.size(); i++){ - my_data.association_vector.emplace_back(index, hitkeyvec[i]); + int phiup = 0; + int phidown = 0; + find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); + for (int iphi = phibin - phidown; iphi <= (phibin + phiup); iphi++) + { + if (adcval[iphi][it] > 0 && adcval[iphi][it] != USHRT_MAX) + { + ihit hit; + hit.iphi = iphi; + hit.it = it; + hit.adc = adcval[iphi][it]; + if (touch > 0) + { + if ((iphi == (phibin - phidown)) || + (iphi == (phibin + phiup))) + { + hit.edge = 1; + } + } + ihit_list.push_back(hit); } } + } + return; + } + + void calc_cluster_parameter(const std::vector &ihit_list, thread_data &my_data, int ntouch, int nedge) + { + // + // get z range from layer geometry + /* these are used for rescaling the drift velocity */ + // const double z_min = -105.5; + // const double z_max = 105.5; + // std::cout << "calc clus" << std::endl; + // loop over the hits in this cluster + double t_sum = 0.0; + // double phi_sum = 0.0; + double adc_sum = 0.0; + double t2_sum = 0.0; + // double phi2_sum = 0.0; + + double iphi_sum = 0.0; + double iphi2_sum = 0.0; + + double radius = my_data.layergeom->get_radius(); // returns center of layer + + int phibinhi = -1; + int phibinlo = 666666; + int tbinhi = -1; + int tbinlo = 666666; + int clus_size = ihit_list.size(); + int max_adc = 0; + if (clus_size == 1) return; + // std::cout << "process list" << std::endl; + std::vector hitkeyvec; + for (auto iter = ihit_list.begin(); iter != ihit_list.end(); ++iter) + { + double adc = iter->adc; + + if (adc <= 0) continue; + if (adc > max_adc) + max_adc = adc; + int iphi = iter->iphi + my_data.phioffset; + int it = iter->it + my_data.toffset; + if (iphi > phibinhi) phibinhi = iphi; + if (iphi < phibinlo) phibinlo = iphi; + if (it > tbinhi) tbinhi = it; + if (it < tbinlo) tbinlo = it; + + // update phi sums + // double phi_center = my_data.layergeom->get_phicenter(iphi); + + // phi_sum += phi_center * adc; + // phi2_sum += square(phi_center)*adc; + // std::cout << "phi_center: " << phi_center << " adc: " << adc <get_zcenter(it); + t_sum += t * adc; + t2_sum += square(t) * adc; + + adc_sum += adc; + + // capture the hitkeys for all adc values above a certain threshold + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); + // if(adc>5) + hitkeyvec.push_back(hitkey); + } + // std::cout << "done process list" << std::endl; + if (adc_sum < 10) + { + hitkeyvec.clear(); + return; // skip obvious noise "clusters" + } + // This is the global position + double clusiphi = iphi_sum / adc_sum; + double clusphi = my_data.layergeom->get_phi(clusiphi); + + float clusx = radius * cos(clusphi); + float clusy = radius * sin(clusphi); + double clust = t_sum / adc_sum; + // needed for surface identification + double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); + // convert z drift length to z position in the TPC + double clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; + if (my_data.side == 0) + clusz = -clusz; + + const double phi_cov = (iphi2_sum / adc_sum - square(clusiphi)) * pow(my_data.layergeom->get_phistep(), 2); + const double t_cov = t2_sum / adc_sum - square(clust); + + // Get the surface key to find the surface from the + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); + Acts::Vector3 global(clusx, clusy, clusz); + TrkrDefs::subsurfkey subsurfkey = 0; + + Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( + tpcHitSetKey, + global, + subsurfkey); + + if (!surface) + { + /// If the surface can't be found, we can't track with it. So + /// just return and don't add the cluster to the container hitkeyvec.clear(); - // std::cout << "done calc" << std::endl; + return; + } + + // Estimate the errors + const double phi_err_square = (phibinhi == phibinlo) ? square(radius * my_data.layergeom->get_phistep()) / 12 : square(radius) * phi_cov / (adc_sum * 0.14); + + const double t_err_square = (tbinhi == tbinlo) ? square(my_data.layergeom->get_zstep()) / 12 : t_cov / (adc_sum * 0.14); + + char tsize = tbinhi - tbinlo + 1; + char phisize = phibinhi - phibinlo + 1; + // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: + // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi + // - N is the number of electrons that drift to the readout plane + // We have to convert (sum of adc units for all bins in the cluster) to number of ionization electrons N + // Conversion gain is 20 mV/fC - relates total charge collected on pad to PEAK voltage out of ADC. The GEM gain is assumed to be 2000 + // To get equivalent charge per T bin, so that summing ADC input voltage over all T bins returns total input charge, divide voltages by 2.4 for 80 ns SAMPA + // Equivalent charge per T bin is then (ADU x 2200 mV / 1024) / 2.4 x (1/20) fC/mV x (1/1.6e-04) electrons/fC x (1/2000) = ADU x 0.14 + + // SAMPA shaping bias correction + clust = clust + my_data.sampa_tbias; + + /// convert to Acts units + global *= Acts::UnitConstants::cm; + // std::cout << "transform" << std::endl; + Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; + local /= Acts::UnitConstants::cm; + // std::cout << "done transform" << std::endl; + // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) + + if (my_data.cluster_version == 3) + { + // std::cout << "ver3" << std::endl; + // Fill in the cluster details + //================ + auto clus = new TrkrClusterv3; + // auto clus = std::make_unique(); + clus->setAdc(adc_sum); + clus->setSubSurfKey(subsurfkey); + clus->setLocalX(local(0)); + clus->setLocalY(clust); + clus->setActsLocalError(0, 0, phi_err_square); + clus->setActsLocalError(1, 0, 0); + clus->setActsLocalError(0, 1, 0); + clus->setActsLocalError(1, 1, t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2)); + my_data.cluster_vector.push_back(clus); + } + else if (my_data.cluster_version == 4) + { + // std::cout << "ver4" << std::endl; + // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; + if (sqrt(phi_err_square) > 0.01) + { + auto clus = new TrkrClusterv4; + // auto clus = std::make_unique(); + clus->setAdc(adc_sum); + clus->setMaxAdc(max_adc); + clus->setOverlap(ntouch); + clus->setEdge(nedge); + clus->setPhiSize(phisize); + clus->setZSize(tsize); + clus->setSubSurfKey(subsurfkey); + clus->setLocalX(local(0)); + clus->setLocalY(clust); + // clus->setPhiErr(sqrt(phi_err_square)); + // clus->setZErr(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(),2))); + my_data.cluster_vector.push_back(clus); + } } - - void ProcessSectorData(thread_data* my_data) { - - const auto& pedestal = my_data->pedestal; - const auto& phibins = my_data->phibins; - const auto& phioffset = my_data->phioffset; - const auto& tbins = my_data->tbins ; - const auto& toffset = my_data->toffset ; - const auto& layer = my_data->layer ; + else if (my_data.cluster_version == 5) + { + // std::cout << "ver5" << std::endl; + // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; + if (sqrt(phi_err_square) > 0.01) + { + auto clus = new TrkrClusterv5; + // auto clus = std::make_unique(); + clus->setAdc(adc_sum); + clus->setMaxAdc(max_adc); + clus->setEdge(nedge); + clus->setPhiSize(phisize); + clus->setZSize(tsize); + clus->setSubSurfKey(subsurfkey); + clus->setLocalX(local(0)); + clus->setLocalY(clust); + clus->setPhiError(sqrt(phi_err_square)); + clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); + my_data.cluster_vector.push_back(clus); + } + } + + // std::cout << "end clus out" << std::endl; + // if(my_data.do_assoc && my_data.clusterhitassoc){ + if (my_data.do_assoc) + { + // get cluster index in vector. It is used to store associations, and build relevant cluster keys when filling the containers + uint32_t index = my_data.cluster_vector.size() - 1; + for (unsigned int i = 0; i < hitkeyvec.size(); i++) + { + my_data.association_vector.emplace_back(index, hitkeyvec[i]); + } + } + hitkeyvec.clear(); + // std::cout << "done calc" << std::endl; + } + + void ProcessSectorData(thread_data *my_data) + { + const auto &pedestal = my_data->pedestal; + const auto &phibins = my_data->phibins; + const auto &phioffset = my_data->phioffset; + const auto &tbins = my_data->tbins; + const auto &toffset = my_data->toffset; + const auto &layer = my_data->layer; // int nhits = 0; // for convenience, create a 2D vector to store adc values in and initialize to zero std::vector> adcval(phibins, std::vector(tbins, 0)); @@ -502,198 +543,223 @@ namespace int tbinmax = 498; int tbinmin = 0; - if(my_data->do_wedge_emulation){ - if(layer>=7 && layer <22){ - int etacut = 249 - ((50+(layer-7))/105.5)*249; - tbinmin = etacut; - tbinmax -= etacut; + if (my_data->do_wedge_emulation) + { + if (layer >= 7 && layer < 22) + { + int etacut = 249 - ((50 + (layer - 7)) / 105.5) * 249; + tbinmin = etacut; + tbinmax -= etacut; } - if(layer>=22 && layer <=48){ - int etacut = 249 - ((65+((40.5/26)*(layer-22)))/105.5)*249; - tbinmin = etacut; - tbinmax -= etacut; + if (layer >= 22 && layer <= 48) + { + int etacut = 249 - ((65 + ((40.5 / 26) * (layer - 22))) / 105.5) * 249; + tbinmin = etacut; + tbinmax -= etacut; } } - if( my_data->hitset!=nullptr){ - TrkrHitSetTpc *hitset = my_data->hitset; + if (my_data->hitset != nullptr) + { + TrkrHitSet *hitset = my_data->hitset; TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr){ - - if( TpcDefs::getPad(hitr->first) - phioffset < 0 ){ - //std::cout << "WARNING phibin out of range: " << TpcDefs::getPad(hitr->first) - phioffset << " | " << phibins << std::endl; - continue; - } - if( TpcDefs::getTBin(hitr->first) - toffset < 0 ){ - //std::cout << "WARNING tbin out of range: " << TpcDefs::getTBin(hitr->first) - toffset << " | " << tbins <first) - phioffset; - unsigned short tbin = TpcDefs::getTBin(hitr->first) - toffset; - unsigned short tbinorg = TpcDefs::getTBin(hitr->first); - if(phibin>=phibins){ - //std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; - continue; - } - if(tbin>=tbins){ - //std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; - continue; - } - if(tbinorg>tbinmax||tbinorgsecond->getAdc()) - pedestal; // proper int rounding +0.5 - unsigned short adc = 0; - if(fadc>0) adc = (unsigned short) fadc; - if(phibin >= phibins) continue; - if(tbin >= tbins) continue; // tbin is unsigned int, <0 cannot happen - - if(adc>0){ - if(adc>(5+my_data->threshold)){ - ihit thisHit; - - thisHit.iphi = phibin; - thisHit.it = tbin; - thisHit.adc = adc; - thisHit.edge = 0; - all_hit_map.insert(std::make_pair(adc, thisHit)); - } - if(adc>my_data->threshold){ - adcval[phibin][tbin] = (unsigned short) adc; - } - } + hitr != hitrangei.second; + ++hitr) + { + if (TpcDefs::getPad(hitr->first) - phioffset < 0) + { + // std::cout << "WARNING phibin out of range: " << TpcDefs::getPad(hitr->first) - phioffset << " | " << phibins << std::endl; + continue; + } + if (TpcDefs::getTBin(hitr->first) - toffset < 0) + { + // std::cout << "WARNING tbin out of range: " << TpcDefs::getTBin(hitr->first) - toffset << " | " << tbins <first) - phioffset; + unsigned short tbin = TpcDefs::getTBin(hitr->first) - toffset; + unsigned short tbinorg = TpcDefs::getTBin(hitr->first); + if (phibin >= phibins) + { + // std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; + continue; + } + if (tbin >= tbins) + { + // std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; + continue; + } + if (tbinorg > tbinmax || tbinorg < tbinmin) + continue; + float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + unsigned short adc = 0; + if (fadc > 0) adc = (unsigned short) fadc; + if (phibin >= phibins) continue; + if (tbin >= tbins) continue; // tbin is unsigned int, <0 cannot happen + + if (adc > 0) + { + if (adc > (5 + my_data->threshold)) + { + ihit thisHit; + + thisHit.iphi = phibin; + thisHit.it = tbin; + thisHit.adc = adc; + thisHit.edge = 0; + all_hit_map.insert(std::make_pair(adc, thisHit)); + } + if (adc > my_data->threshold) + { + adcval[phibin][tbin] = (unsigned short) adc; + } + } } - - - - }else if( my_data->rawhitset!=nullptr){ + } + else if (my_data->rawhitset != nullptr) + { RawHitSetv1 *hitset = my_data->rawhitset; - /*std::cout << "Layer: " << my_data->layer - << "Side: " << my_data->side - << "Sector: " << my_data->sector - << " nhits: " << hitset.size() - << std::endl; + /*std::cout << "Layer: " << my_data->layer + << "Side: " << my_data->side + << "Sector: " << my_data->sector + << " nhits: " << hitset.size() + << std::endl; */ - for(int nphi= 0; nphi < phibins;nphi++){ - // nhits += hitset->m_tpchits[nphi].size(); - if(hitset->m_tpchits[nphi].size()==0) continue; - - int pindex = 0; - for(unsigned int nt = 0;ntm_tpchits[nphi].size();nt++){ - unsigned short val = hitset->m_tpchits[nphi][nt]; - - if(val==0) - pindex++; - else{ - if(nt==0){ - if(val>5){ - ihit thisHit; - thisHit.iphi = nphi; - thisHit.it = pindex; - thisHit.adc = val; - thisHit.edge = 0; - all_hit_map.insert(std::make_pair(val, thisHit)); - } - adcval[nphi][pindex++]=val; - }else{ - if((hitset->m_tpchits[nphi][nt-1]==0)&&(hitset->m_tpchits[nphi][nt+1]==0))//found zero count - pindex+=val; - else{ - if(val>5){ - ihit thisHit; - thisHit.iphi = nphi; - thisHit.it = pindex; - thisHit.adc = val; - thisHit.edge = 0; - all_hit_map.insert(std::make_pair(val, thisHit)); - } - adcval[nphi][pindex++]=val; - } - } - } - } + for (int nphi = 0; nphi < phibins; nphi++) + { + // nhits += hitset->m_tpchits[nphi].size(); + if (hitset->m_tpchits[nphi].size() == 0) continue; + + int pindex = 0; + for (unsigned int nt = 0; nt < hitset->m_tpchits[nphi].size(); nt++) + { + unsigned short val = hitset->m_tpchits[nphi][nt]; + + if (val == 0) + pindex++; + else + { + if (nt == 0) + { + if (val > 5) + { + ihit thisHit; + thisHit.iphi = nphi; + thisHit.it = pindex; + thisHit.adc = val; + thisHit.edge = 0; + all_hit_map.insert(std::make_pair(val, thisHit)); + } + adcval[nphi][pindex++] = val; + } + else + { + if ((hitset->m_tpchits[nphi][nt - 1] == 0) && (hitset->m_tpchits[nphi][nt + 1] == 0)) // found zero count + pindex += val; + else + { + if (val > 5) + { + ihit thisHit; + thisHit.iphi = nphi; + thisHit.it = pindex; + thisHit.adc = val; + thisHit.edge = 0; + all_hit_map.insert(std::make_pair(val, thisHit)); + } + adcval[nphi][pindex++] = val; + } + } + } + } } } - - if(my_data->do_singles){ - for(auto ahit:all_hit_map){ - ihit hiHit = ahit.second; - int iphi = hiHit.iphi; - int it = hiHit.it; - unsigned short edge = hiHit.edge; - double adc = hiHit.adc; - if(it>0&&itdo_singles) + { + for (auto ahit : all_hit_map) + { + ihit hiHit = ahit.second; + int iphi = hiHit.iphi; + int it = hiHit.it; + unsigned short edge = hiHit.edge; + double adc = hiHit.adc; + if (it > 0 && it < tbins) + { + if (adcval[iphi][it - 1] == 0 && + adcval[iphi][it + 1] == 0) + { + remove_hit(adc, iphi, it, edge, all_hit_map, adcval); + } + } } } - + // std::cout << "done filling " << std::endl; - while(all_hit_map.size()>0){ - //std::cout << "all hit map size: " << all_hit_map.size() << std::endl; + while (all_hit_map.size() > 0) + { + // std::cout << "all hit map size: " << all_hit_map.size() << std::endl; auto iter = all_hit_map.rbegin(); - if(iter == all_hit_map.rend()){ - break; + if (iter == all_hit_map.rend()) + { + break; } ihit hiHit = iter->second; int iphi = hiHit.iphi; int it = hiHit.it; - //put all hits in the all_hit_map (sorted by adc) - //start with highest adc hit - // -> cluster around it and get vector of hits + // put all hits in the all_hit_map (sorted by adc) + // start with highest adc hit + // -> cluster around it and get vector of hits std::vector ihit_list; int ntouch = 0; - int nedge =0; - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge ); - + int nedge = 0; + get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // -> calculate cluster parameters // -> add hits to truth association // remove hits from all_hit_map // repeat untill all_hit_map empty - calc_cluster_parameter(ihit_list, *my_data, ntouch, nedge ); - remove_hits(ihit_list,all_hit_map, adcval); + calc_cluster_parameter(ihit_list, *my_data, ntouch, nedge); + remove_hits(ihit_list, all_hit_map, adcval); ihit_list.clear(); } /* if( my_data->rawhitset!=nullptr){ RawHitSetv1 *hitset = my_data->rawhitset; - std::cout << "Layer: " << my_data->layer - << " Side: " << my_data->side - << " Sector: " << my_data->sector - << " nhits: " << hitset->size() - << " nhits coutn : " << nhits - << " nclus: " << my_data->cluster_vector.size() - << std::endl; + std::cout << "Layer: " << my_data->layer + << " Side: " << my_data->side + << " Sector: " << my_data->sector + << " nhits: " << hitset->size() + << " nhits coutn : " << nhits + << " nclus: " << my_data->cluster_vector.size() + << std::endl; } */ // pthread_exit(nullptr); } - void *ProcessSector(void *threadarg) { - - auto my_data = static_cast(threadarg); + void *ProcessSector(void *threadarg) + { + auto my_data = static_cast(threadarg); ProcessSectorData(my_data); pthread_exit(nullptr); } -} +} // namespace TpcClusterizer::TpcClusterizer(const std::string &name) : SubsysReco(name) -{} +{ +} bool TpcClusterizer::is_in_sector_boundary(int phibin, int sector, PHG4TpcCylinderGeom *layergeom) const { bool reject_it = false; - // sector boundaries occur every 1/12 of the full phi bin range + // sector boundaries occur every 1/12 of the full phi bin range int PhiBins = layergeom->get_phibins(); - int PhiBinsSector = PhiBins/12; + int PhiBinsSector = PhiBins / 12; double radius = layergeom->get_radius(); - double PhiBinSize = 2.0* radius * M_PI / (double) PhiBins; + double PhiBinSize = 2.0 * radius * M_PI / (double) PhiBins; // sector starts where? int sector_lo = sector * PhiBinsSector; @@ -701,24 +767,22 @@ bool TpcClusterizer::is_in_sector_boundary(int phibin, int sector, PHG4TpcCylind int sector_fiducial_bins = (int) (SectorFiducialCut / PhiBinSize); - if(phibin < sector_lo + sector_fiducial_bins || phibin > sector_hi - sector_fiducial_bins) - { - reject_it = true; - /* - int layer = layergeom->get_layer(); - std::cout << " local maximum is in sector fiducial boundary: layer " << layer << " radius " << radius << " sector " << sector - << " PhiBins " << PhiBins << " sector_fiducial_bins " << sector_fiducial_bins - << " PhiBinSize " << PhiBinSize << " phibin " << phibin << " sector_lo " << sector_lo << " sector_hi " << sector_hi << std::endl; - */ - } + if (phibin < sector_lo + sector_fiducial_bins || phibin > sector_hi - sector_fiducial_bins) + { + reject_it = true; + /* + int layer = layergeom->get_layer(); + std::cout << " local maximum is in sector fiducial boundary: layer " << layer << " radius " << radius << " sector " << sector + << " PhiBins " << PhiBins << " sector_fiducial_bins " << sector_fiducial_bins + << " PhiBinSize " << PhiBinSize << " phibin " << phibin << " sector_lo " << sector_lo << " sector_hi " << sector_hi << std::endl; + */ + } return reject_it; } - int TpcClusterizer::InitRun(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); // Looking for the DST node @@ -782,22 +846,25 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - if(!do_read_raw){ + if (!do_read_raw) + { // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET_TPC"); if (!m_hits) - { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - }else{ + { + std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET_TPC" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + } + else + { // get node containing the digitized hits m_rawhits = findNode::getClass(topNode, "TRKR_RAWHITSET"); if (!m_rawhits) - { - std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + { + std::cout << PHWHERE << "ERROR: Can't find node TRKR_RAWHITSET" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } } // get node for clusters @@ -825,14 +892,14 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) } m_tGeometry = findNode::getClass(topNode, - "ActsGeometry"); - if(!m_tGeometry) - { - std::cout << PHWHERE - << "ActsGeometry not found on node tree. Exiting" - << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + "ActsGeometry"); + if (!m_tGeometry) + { + std::cout << PHWHERE + << "ActsGeometry not found on node tree. Exiting" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } // The hits are stored in hitsets, where each hitset contains all hits in a given TPC readout (layer, sector, side), so clusters are confined to a hitset // The TPC clustering is more complicated than for the silicon, because we have to deal with overlapping clusters @@ -841,12 +908,15 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) RawHitSetContainer::ConstRange rawhitsetrange; int num_hitsets = 0; - if(!do_read_raw){ + if (!do_read_raw) + { hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); - num_hitsets = std::distance(hitsetrange.first,hitsetrange.second); - }else{ + num_hitsets = std::distance(hitsetrange.first, hitsetrange.second); + } + else + { rawhitsetrange = m_rawhits->getHitSets(TrkrDefs::TrkrId::tpcId); - num_hitsets = std::distance(rawhitsetrange.first,rawhitsetrange.second); + num_hitsets = std::distance(rawhitsetrange.first, rawhitsetrange.second); } // create structure to store given thread and associated data @@ -855,134 +925,140 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) pthread_t thread; thread_data data; }; - + // create vector of thread pairs and reserve the right size upfront to avoid reallocation std::vector threads; - threads.reserve( num_hitsets ); + threads.reserve(num_hitsets); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - + if (pthread_mutex_init(&mythreadlock, nullptr) != 0) - { - printf("\n mutex init failed\n"); - return 1; - } + { + printf("\n mutex init failed\n"); + return 1; + } int count = 0; - if(!do_read_raw){ + if (!do_read_raw) + { for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + // if(count>0)continue; + TrkrHitSet *hitset = hitsetitr->second; + unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); + int side = TpcDefs::getSide(hitsetitr->first); + unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); + PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); + + // instanciate new thread pair, at the end of thread vector + thread_pair_t &thread_pair = threads.emplace_back(); + + thread_pair.data.layergeom = layergeom; + thread_pair.data.hitset = hitset; + thread_pair.data.rawhitset = nullptr; + thread_pair.data.layer = layer; + thread_pair.data.pedestal = pedestal; + thread_pair.data.threshold = threshold; + thread_pair.data.sector = sector; + thread_pair.data.side = side; + thread_pair.data.do_assoc = do_hit_assoc; + thread_pair.data.do_wedge_emulation = do_wedge_emulation; + thread_pair.data.do_singles = do_singles; + thread_pair.data.tGeometry = m_tGeometry; + thread_pair.data.maxHalfSizeT = MaxClusterHalfSizeT; + thread_pair.data.maxHalfSizePhi = MaxClusterHalfSizePhi; + thread_pair.data.sampa_tbias = m_sampa_tbias; + thread_pair.data.cluster_version = cluster_version; + thread_pair.data.verbosity = Verbosity(); + + unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); + unsigned short NPhiBinsSector = NPhiBins / 12; + unsigned short NTBins = (unsigned short) layergeom->get_zbins(); + unsigned short NTBinsSide = NTBins; + unsigned short NTBinsMin = 0; + unsigned short PhiOffset = NPhiBinsSector * sector; + unsigned short TOffset = NTBinsMin; + + m_tdriftmax = AdcClockPeriod * NTBins / 2.0; + thread_pair.data.m_tdriftmax = m_tdriftmax; + + thread_pair.data.phibins = NPhiBinsSector; + thread_pair.data.phioffset = PhiOffset; + thread_pair.data.tbins = NTBinsSide; + thread_pair.data.toffset = TOffset; + + thread_pair.data.radius = layergeom->get_radius(); + thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); + thread_pair.data.pads_per_sector = 0; + thread_pair.data.phistep = 0; + int rc; + rc = pthread_create(&thread_pair.thread, &attr, ProcessSector, (void *) &thread_pair.data); + + if (rc) { - //if(count>0)continue; - TrkrHitSetTpc *hitset = dynamic_cast(hitsetitr->second); - assert(hitset); - unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); - int side = TpcDefs::getSide(hitsetitr->first); - unsigned int sector= TpcDefs::getSectorId(hitsetitr->first); - PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); - - // instanciate new thread pair, at the end of thread vector - thread_pair_t& thread_pair = threads.emplace_back(); - - thread_pair.data.layergeom = layergeom; - thread_pair.data.hitset = hitset; - thread_pair.data.rawhitset = nullptr; - thread_pair.data.layer = layer; - thread_pair.data.pedestal = pedestal; - thread_pair.data.threshold = threshold; - thread_pair.data.sector = sector; - thread_pair.data.side = side; - thread_pair.data.do_assoc = do_hit_assoc; - thread_pair.data.do_wedge_emulation = do_wedge_emulation; - thread_pair.data.do_singles = do_singles; - thread_pair.data.tGeometry = m_tGeometry; - thread_pair.data.maxHalfSizeT = MaxClusterHalfSizeT; - thread_pair.data.maxHalfSizePhi = MaxClusterHalfSizePhi; - thread_pair.data.sampa_tbias = m_sampa_tbias; - thread_pair.data.cluster_version = cluster_version; - thread_pair.data.verbosity = Verbosity(); - - unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); - unsigned short NPhiBinsSector = NPhiBins/12; - unsigned short NTBins = (unsigned short)layergeom->get_zbins(); - unsigned short NTBinsSide = NTBins; - unsigned short NTBinsMin = 0; - unsigned short PhiOffset = NPhiBinsSector * sector; - unsigned short TOffset = NTBinsMin; - - m_tdriftmax = AdcClockPeriod * NTBins / 2.0; - thread_pair.data.m_tdriftmax = m_tdriftmax; - - thread_pair.data.phibins = NPhiBinsSector; - thread_pair.data.phioffset = PhiOffset; - thread_pair.data.tbins = NTBinsSide; - thread_pair.data.toffset = TOffset ; - - thread_pair.data.radius = layergeom->get_radius(); - thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); - thread_pair.data.pads_per_sector = 0; - thread_pair.data.phistep = 0; - int rc; - rc = pthread_create(&thread_pair.thread, &attr, ProcessSector, (void *)&thread_pair.data); - - if (rc) { - std::cout << "Error:unable to create thread," << rc << std::endl; - } - if(do_sequential){ - int rc2 = pthread_join(thread_pair.thread, nullptr); - if (rc2) - { std::cout << "Error:unable to join," << rc2 << std::endl; } - - // get the hitsetkey from thread data - const auto& data( thread_pair.data ); - const auto hitsetkey = TpcDefs::genHitSetKey( data.layer, data.sector, data.side ); - - // copy clusters to map - for( uint32_t index = 0; index < data.cluster_vector.size(); ++index ) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // get cluster - auto cluster = data.cluster_vector[index]; - - // insert in map - m_clusterlist->addClusterSpecifyKey(ckey, cluster); - } - - // copy hit associations to map - for( const auto& [index,hkey]:thread_pair.data.association_vector) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // add to association table - m_clusterhitassoc->addAssoc(ckey,hkey); - } - } - count++; + std::cout << "Error:unable to create thread," << rc << std::endl; } - }else{ + if (do_sequential) + { + int rc2 = pthread_join(thread_pair.thread, nullptr); + if (rc2) + { + std::cout << "Error:unable to join," << rc2 << std::endl; + } + // get the hitsetkey from thread data + const auto &data(thread_pair.data); + const auto hitsetkey = TpcDefs::genHitSetKey(data.layer, data.sector, data.side); + + // copy clusters to map + for (uint32_t index = 0; index < data.cluster_vector.size(); ++index) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // get cluster + auto cluster = data.cluster_vector[index]; + + // insert in map + m_clusterlist->addClusterSpecifyKey(ckey, cluster); + } + + // copy hit associations to map + for (const auto &[index, hkey] : thread_pair.data.association_vector) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // add to association table + m_clusterhitassoc->addAssoc(ckey, hkey); + } + } + count++; + } + } + else + { for (RawHitSetContainer::ConstIterator hitsetitr = rawhitsetrange.first; - hitsetitr != rawhitsetrange.second; - ++hitsetitr){ + hitsetitr != rawhitsetrange.second; + ++hitsetitr) + { // if(count>0)continue; - // const auto hitsetid = hitsetitr->first; + // const auto hitsetid = hitsetitr->first; // std::cout << " starting thread # " << count << std::endl; - RawHitSet *hitset = hitsetitr->second; + RawHitSet *hitset = hitsetitr->second; unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); - unsigned int sector= TpcDefs::getSectorId(hitsetitr->first); + unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); - + // instanciate new thread pair, at the end of thread vector - thread_pair_t& thread_pair = threads.emplace_back(); - + thread_pair_t &thread_pair = threads.emplace_back(); + thread_pair.data.layergeom = layergeom; thread_pair.data.hitset = nullptr; thread_pair.data.rawhitset = dynamic_cast(hitset); @@ -993,145 +1069,150 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.do_assoc = do_hit_assoc; thread_pair.data.do_wedge_emulation = do_wedge_emulation; thread_pair.data.tGeometry = m_tGeometry; - thread_pair.data.maxHalfSizeT = MaxClusterHalfSizeT; + thread_pair.data.maxHalfSizeT = MaxClusterHalfSizeT; thread_pair.data.maxHalfSizePhi = MaxClusterHalfSizePhi; thread_pair.data.sampa_tbias = m_sampa_tbias; thread_pair.data.cluster_version = cluster_version; thread_pair.data.verbosity = Verbosity(); unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); - unsigned short NPhiBinsSector = NPhiBins/12; - unsigned short NTBins = (unsigned short)layergeom->get_zbins(); + unsigned short NPhiBinsSector = NPhiBins / 12; + unsigned short NTBins = (unsigned short) layergeom->get_zbins(); unsigned short NTBinsSide = NTBins; unsigned short NTBinsMin = 0; unsigned short PhiOffset = NPhiBinsSector * sector; unsigned short TOffset = NTBinsMin; - m_tdriftmax = AdcClockPeriod * NTBins / 2.0; + m_tdriftmax = AdcClockPeriod * NTBins / 2.0; thread_pair.data.m_tdriftmax = m_tdriftmax; - thread_pair.data.phibins = NPhiBinsSector; + thread_pair.data.phibins = NPhiBinsSector; thread_pair.data.phioffset = PhiOffset; - thread_pair.data.tbins = NTBinsSide; - thread_pair.data.toffset = TOffset ; + thread_pair.data.tbins = NTBinsSide; + thread_pair.data.toffset = TOffset; /* PHG4TpcCylinderGeom *testlayergeom = geom_container->GetLayerCellGeom(32); for( float iphi = 1408; iphi < 1408+ 128;iphi+=0.1){ - double clusiphi = iphi; - double clusphi = testlayergeom->get_phi(clusiphi); - double radius = layergeom->get_radius(); - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); - float clusz = -37.524; - - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey( 32,11, 0 ); - Acts::Vector3 global(clusx, clusy, clusz); - TrkrDefs::subsurfkey subsurfkey = 0; - - Surface surface = m_tGeometry->get_tpc_surface_from_coords( - tpcHitSetKey, - global, - subsurfkey); - std::cout << " iphi: " << iphi << " clusphi: " << clusphi << " surfkey " << subsurfkey << std::endl; - // std::cout << "surfkey" << subsurfkey << std::endl; + double clusiphi = iphi; + double clusphi = testlayergeom->get_phi(clusiphi); + double radius = layergeom->get_radius(); + float clusx = radius * cos(clusphi); + float clusy = radius * sin(clusphi); + float clusz = -37.524; + + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey( 32,11, 0 ); + Acts::Vector3 global(clusx, clusy, clusz); + TrkrDefs::subsurfkey subsurfkey = 0; + + Surface surface = m_tGeometry->get_tpc_surface_from_coords( + tpcHitSetKey, + global, + subsurfkey); + std::cout << " iphi: " << iphi << " clusphi: " << clusphi << " surfkey " << subsurfkey << std::endl; + // std::cout << "surfkey" << subsurfkey << std::endl; } continue; */ int rc = 0; // if(layer==32) - rc = pthread_create(&thread_pair.thread, &attr, ProcessSector, (void *)&thread_pair.data); + rc = pthread_create(&thread_pair.thread, &attr, ProcessSector, (void *) &thread_pair.data); // else - //continue; - - if (rc) { - std::cout << "Error:unable to create thread," << rc << std::endl; + // continue; + + if (rc) + { + std::cout << "Error:unable to create thread," << rc << std::endl; + } + + if (do_sequential) + { + int rc2 = pthread_join(thread_pair.thread, nullptr); + if (rc2) + { + std::cout << "Error:unable to join," << rc2 << std::endl; + } + + // get the hitsetkey from thread data + const auto &data(thread_pair.data); + const auto hitsetkey = TpcDefs::genHitSetKey(data.layer, data.sector, data.side); + + // copy clusters to map + for (uint32_t index = 0; index < data.cluster_vector.size(); ++index) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // get cluster + auto cluster = data.cluster_vector[index]; + + // insert in map + m_clusterlist->addClusterSpecifyKey(ckey, cluster); + } + + // copy hit associations to map + for (const auto &[index, hkey] : thread_pair.data.association_vector) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // add to association table + m_clusterhitassoc->addAssoc(ckey, hkey); + } } - - if(do_sequential){ - int rc2 = pthread_join(thread_pair.thread, nullptr); - if (rc2) - { std::cout << "Error:unable to join," << rc2 << std::endl; } - - // get the hitsetkey from thread data - const auto& data( thread_pair.data ); - const auto hitsetkey = TpcDefs::genHitSetKey( data.layer, data.sector, data.side ); - - // copy clusters to map - for( uint32_t index = 0; index < data.cluster_vector.size(); ++index ) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // get cluster - auto cluster = data.cluster_vector[index]; - - // insert in map - m_clusterlist->addClusterSpecifyKey(ckey, cluster); - } - - // copy hit associations to map - for( const auto& [index,hkey]:thread_pair.data.association_vector) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // add to association table - m_clusterhitassoc->addAssoc(ckey,hkey); - } - } count++; } } - pthread_attr_destroy(&attr); - count =0; + count = 0; // wait for completion of all threads - if(!do_sequential){ - for( const auto& thread_pair:threads ) - { - int rc2 = pthread_join(thread_pair.thread, nullptr); - if (rc2) - { std::cout << "Error:unable to join," << rc2 << std::endl; } - - // get the hitsetkey from thread data - const auto& data( thread_pair.data ); - const auto hitsetkey = TpcDefs::genHitSetKey( data.layer, data.sector, data.side ); - - // copy clusters to map - for( uint32_t index = 0; index < data.cluster_vector.size(); ++index ) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // get cluster - auto cluster = data.cluster_vector[index]; - - // insert in map - //std::cout << "X: " << cluster->getLocalX() << "Y: " << cluster->getLocalY() << std::endl; - m_clusterlist->addClusterSpecifyKey(ckey, cluster); - } - - // copy hit associations to map - for( const auto& [index,hkey]:thread_pair.data.association_vector) - { - // generate cluster key - const auto ckey = TrkrDefs::genClusKey( hitsetkey, index ); - - // add to association table - m_clusterhitassoc->addAssoc(ckey,hkey); - } + if (!do_sequential) + { + for (const auto &thread_pair : threads) + { + int rc2 = pthread_join(thread_pair.thread, nullptr); + if (rc2) + { + std::cout << "Error:unable to join," << rc2 << std::endl; + } + + // get the hitsetkey from thread data + const auto &data(thread_pair.data); + const auto hitsetkey = TpcDefs::genHitSetKey(data.layer, data.sector, data.side); + + // copy clusters to map + for (uint32_t index = 0; index < data.cluster_vector.size(); ++index) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // get cluster + auto cluster = data.cluster_vector[index]; + // insert in map + // std::cout << "X: " << cluster->getLocalX() << "Y: " << cluster->getLocalY() << std::endl; + m_clusterlist->addClusterSpecifyKey(ckey, cluster); } + + // copy hit associations to map + for (const auto &[index, hkey] : thread_pair.data.association_vector) + { + // generate cluster key + const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); + + // add to association table + m_clusterhitassoc->addAssoc(ckey, hkey); + } + } } if (Verbosity() > 0) - std::cout << "TPC Clusterizer found " << m_clusterlist->size() << " Clusters " << std::endl; + std::cout << "TPC Clusterizer found " << m_clusterlist->size() << " Clusters " << std::endl; return Fun4AllReturnCodes::EVENT_OK; } -int TpcClusterizer::End(PHCompositeNode */*topNode*/) +int TpcClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index f6c56a970e..ff41168e63 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -2,12 +2,12 @@ #define TPC_TPCCLUSTERIZER_H #include -#include #include +#include -#include -#include +#include #include +#include class PHCompositeNode; class TrkrHitSet; @@ -19,8 +19,8 @@ class TrkrClusterHitAssoc; class PHG4TpcCylinderGeom; class PHG4TpcCylinderGeomContainer; -//typedef std::pair iphiz; -//typedef std::pair ihit; +// typedef std::pair iphiz; +// typedef std::pair ihit; typedef std::pair iphiz; typedef std::pair ihit; @@ -34,17 +34,17 @@ class TpcClusterizer : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void set_sector_fiducial_cut(const double cut){SectorFiducialCut = cut; } - void set_do_hit_association(bool do_assoc){do_hit_assoc = do_assoc;} - void set_do_wedge_emulation(bool do_wedge){ do_wedge_emulation = do_wedge;} - void set_do_sequential(bool do_seq){ do_sequential = do_seq;} - void set_threshold(float val) { threshold = val;} - void set_remove_singles(bool do_sing){ do_singles = do_sing;} - void set_read_raw(bool read_raw){ do_read_raw = read_raw;} - void set_max_cluster_half_size_phi(unsigned short size) { MaxClusterHalfSizePhi = size ;} - void set_max_cluster_half_size_z(unsigned short size) { MaxClusterHalfSizeT = size ;} + void set_sector_fiducial_cut(const double cut) { SectorFiducialCut = cut; } + void set_do_hit_association(bool do_assoc) { do_hit_assoc = do_assoc; } + void set_do_wedge_emulation(bool do_wedge) { do_wedge_emulation = do_wedge; } + void set_do_sequential(bool do_seq) { do_sequential = do_seq; } + void set_threshold(float val) { threshold = val; } + void set_remove_singles(bool do_sing) { do_singles = do_sing; } + void set_read_raw(bool read_raw) { do_read_raw = read_raw; } + void set_max_cluster_half_size_phi(unsigned short size) { MaxClusterHalfSizePhi = size; } + void set_max_cluster_half_size_z(unsigned short size) { MaxClusterHalfSizeT = size; } void set_cluster_version(int value) { cluster_version = value; } - + private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcCylinderGeom *layergeom) const; @@ -65,11 +65,11 @@ class TpcClusterizer : public SubsysReco unsigned short MaxClusterHalfSizeT = 5; int cluster_version = 4; double m_tdriftmax = 0; - double AdcClockPeriod = 53.0; // ns + double AdcClockPeriod = 53.0; // ns // TPC shaping offset correction parameter // From Tony Frawley July 5, 2022 - double m_sampa_tbias = 39.6; // ns + double m_sampa_tbias = 39.6; // ns }; #endif From 2efac13f52146fe9f17dedd5d3bdece498f4cdd8 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 14:41:40 -0400 Subject: [PATCH 179/468] allow clusterizer to support both old and new TPC data format --- offline/packages/tpc/TpcClusterizer.cc | 175 ++++++++++++++++++------- 1 file changed, 126 insertions(+), 49 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index a96be538e1..05467c81c1 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -41,6 +41,7 @@ #include #include +#include #include // for sqrt, cos, sin #include #include @@ -48,7 +49,6 @@ #include #include // for pair #include -#include // Terra incognita.... #include @@ -561,62 +561,139 @@ namespace if (my_data->hitset != nullptr) { - TrkrHitSet *hitset = my_data->hitset; - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) + if (dynamic_cast(my_data->hitset)) { - if (TpcDefs::getPad(hitr->first) - phioffset < 0) - { - // std::cout << "WARNING phibin out of range: " << TpcDefs::getPad(hitr->first) - phioffset << " | " << phibins << std::endl; - continue; - } - if (TpcDefs::getTBin(hitr->first) - toffset < 0) - { - // std::cout << "WARNING tbin out of range: " << TpcDefs::getTBin(hitr->first) - toffset << " | " << tbins <first) - phioffset; - unsigned short tbin = TpcDefs::getTBin(hitr->first) - toffset; - unsigned short tbinorg = TpcDefs::getTBin(hitr->first); - if (phibin >= phibins) - { - // std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; - continue; - } - if (tbin >= tbins) - { - // std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; - continue; - } - if (tbinorg > tbinmax || tbinorg < tbinmin) - continue; - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 - unsigned short adc = 0; - if (fadc > 0) adc = (unsigned short) fadc; - if (phibin >= phibins) continue; - if (tbin >= tbins) continue; // tbin is unsigned int, <0 cannot happen - - if (adc > 0) + // TPC specific hit set format + + TrkrHitSetTpc *hitset = dynamic_cast(my_data->hitset); + assert(hitset); + + const TrkrHitSetTpc::TimeFrameADCDataType &dataframe = hitset->getTimeFrameAdcData(); + + for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) { - if (adc > (5 + my_data->threshold)) + const std::vector &pad_data = dataframe[local_pad]; + + for (unsigned int local_tbin = 0; local_tbin < pad_data.size(); ++local_tbin) { - ihit thisHit; + const TpcDefs::ADCDataType &rawadc = pad_data[local_tbin]; + TrkrDefs::hitkey hitkey = hitset->getHitKeyfromLocalBin(local_pad, local_tbin); + + if (TpcDefs::getPad(hitkey) - phioffset < 0) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING phibin out of range: " << TpcDefs::getPad(hitkey) - phioffset << " | " << phibins << std::endl; + continue; + } + if (TpcDefs::getTBin(hitkey) - toffset < 0) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING tbin out of range: " << TpcDefs::getTBin(hitkey) - toffset << " | " << tbins << std::endl; + } + unsigned short phibin = TpcDefs::getPad(hitkey) - phioffset; + unsigned short tbin = TpcDefs::getTBin(hitkey) - toffset; + unsigned short tbinorg = TpcDefs::getTBin(hitkey); + if (phibin >= phibins) + { + // std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; + continue; + } + if (tbin >= tbins) + { + // std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; + continue; + } + if (tbinorg > tbinmax || tbinorg < tbinmin) + continue; + float_t fadc = rawadc - pedestal; // proper int rounding +0.5 + unsigned short adc = 0; + if (fadc > 0) adc = (unsigned short) fadc; + if (phibin >= phibins) continue; + if (tbin >= tbins) continue; // tbin is unsigned int, <0 cannot happen + + if (adc > 0) + { + if (adc > (5 + my_data->threshold)) + { + ihit thisHit; - thisHit.iphi = phibin; - thisHit.it = tbin; - thisHit.adc = adc; - thisHit.edge = 0; - all_hit_map.insert(std::make_pair(adc, thisHit)); + thisHit.iphi = phibin; + thisHit.it = tbin; + thisHit.adc = adc; + thisHit.edge = 0; + all_hit_map.insert(std::make_pair(adc, thisHit)); + } + if (adc > my_data->threshold) + { + adcval[phibin][tbin] = (unsigned short) adc; + } + } + + } // for (int local_tbin = 0; local_tbin < pad_data.size(); ++local_tbin) + + } // for (int local_pad = 0; local_pad < dataframe.size(); ++local_pad) + + } // if (dynamic_cast(my_data->hitset)) + else + { + // generic hitset format + + TrkrHitSet *hitset = my_data->hitset; + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) + { + if (TpcDefs::getPad(hitr->first) - phioffset < 0) + { + // std::cout << "WARNING phibin out of range: " << TpcDefs::getPad(hitr->first) - phioffset << " | " << phibins << std::endl; + continue; } - if (adc > my_data->threshold) + if (TpcDefs::getTBin(hitr->first) - toffset < 0) { - adcval[phibin][tbin] = (unsigned short) adc; + // std::cout << "WARNING tbin out of range: " << TpcDefs::getTBin(hitr->first) - toffset << " | " << tbins <first) - phioffset; + unsigned short tbin = TpcDefs::getTBin(hitr->first) - toffset; + unsigned short tbinorg = TpcDefs::getTBin(hitr->first); + if (phibin >= phibins) + { + // std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; + continue; + } + if (tbin >= tbins) + { + // std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; + continue; + } + if (tbinorg > tbinmax || tbinorg < tbinmin) + continue; + float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + unsigned short adc = 0; + if (fadc > 0) adc = (unsigned short) fadc; + if (phibin >= phibins) continue; + if (tbin >= tbins) continue; // tbin is unsigned int, <0 cannot happen + + if (adc > 0) + { + if (adc > (5 + my_data->threshold)) + { + ihit thisHit; + + thisHit.iphi = phibin; + thisHit.it = tbin; + thisHit.adc = adc; + thisHit.edge = 0; + all_hit_map.insert(std::make_pair(adc, thisHit)); + } + if (adc > my_data->threshold) + { + adcval[phibin][tbin] = (unsigned short) adc; + } } } - } - } + } // else -> if (dynamic_cast(my_data->hitset)) + + } // if (my_data->hitset != nullptr) else if (my_data->rawhitset != nullptr) { RawHitSetv1 *hitset = my_data->rawhitset; From 6e91ecdee0449930d9c491772bb1faf984460e6e Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 14:54:39 -0400 Subject: [PATCH 180/468] adapt to new TPC hit format --- .../tpccalib/TpcDirectLaserReconstruction.cc | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc index e89cfb1e28..d1f0884852 100644 --- a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc +++ b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc @@ -22,6 +22,7 @@ #include #include // for TrkrHit #include +#include #include #include @@ -374,7 +375,9 @@ void TpcDirectLaserReconstruction::process_track( SvtxTrack* track ) const TrkrDefs::hitsetkey& hitsetkey = hitsetitr->first; const int side = TpcDefs::getSide(hitsetkey); - auto hitset = hitsetitr->second; + auto hitset = dynamic_cast(hitsetitr->second); + assert(hitset); + const unsigned int layer = TrkrDefs::getLayer(hitsetkey); const auto layergeom = m_geom_container->GetLayerCellGeom(layer); const auto layer_center_radius = layergeom->get_radius(); @@ -388,12 +391,25 @@ void TpcDirectLaserReconstruction::process_track( SvtxTrack* track ) // get corresponding hits TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (auto hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) +// for (auto hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) + + const TrkrHitSetTpc::TimeFrameADCDataType &dataframe = hitset->getTimeFrameAdcData(); + + for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) + { + const std::vector &pad_data = dataframe[local_pad]; + + for (unsigned int local_tbin = 0; local_tbin < pad_data.size(); ++local_tbin) { + const TpcDefs::ADCDataType &rawadc = pad_data[local_tbin]; + TrkrDefs::hitkey hitkey = hitset->getHitKeyfromLocalBin(local_pad, local_tbin); + + if (rawadc<=0) continue; + ++m_total_hits; - const unsigned short phibin = TpcDefs::getPad(hitr->first); - const unsigned short zbin = TpcDefs::getTBin(hitr->first); + const unsigned short phibin = TpcDefs::getPad(hitkey); + const unsigned short zbin = TpcDefs::getTBin(hitkey); const double phi = layergeom->get_phicenter(phibin); const double x = layer_center_radius * cos(phi); @@ -410,7 +426,7 @@ void TpcDirectLaserReconstruction::process_track( SvtxTrack* track ) h_hits->Fill(x,y,z); } - float adc = (hitr->second->getAdc()) - m_pedestal; + float adc = rawadc - m_pedestal; // calculate dca // origin is track origin, direction is track direction @@ -480,6 +496,9 @@ void TpcDirectLaserReconstruction::process_track( SvtxTrack* track ) cluspos_map.insert(std::make_pair(layer, cluspos_pair)); layer_bin_set.insert(layer); } + }// for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) + + } for(int GEMS_iter = 0; GEMS_iter < 72; GEMS_iter++) From aa3d08866e1f3ed7560f411fdfbe5dfc2e7852ea Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 16:11:35 -0400 Subject: [PATCH 181/468] adapt to new TPC hit format --- .../g4simulation/g4eval/TrackEvaluation.cc | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/simulation/g4simulation/g4eval/TrackEvaluation.cc b/simulation/g4simulation/g4eval/TrackEvaluation.cc index 1156b515a3..cf87baf8d4 100644 --- a/simulation/g4simulation/g4eval/TrackEvaluation.cc +++ b/simulation/g4simulation/g4eval/TrackEvaluation.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -205,37 +206,46 @@ namespace } //! hit energy for a given cluster - void add_cluster_energy( TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrDefs::cluskey clus_key, - TrkrClusterHitAssoc* cluster_hit_map, - TrkrHitSetContainer* hitsetcontainer ) + void add_cluster_energy(TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrDefs::cluskey clus_key, + TrkrClusterHitAssoc* cluster_hit_map, + TrkrHitSetContainer* hitsetcontainer) { - // check container - if(!(cluster_hit_map && hitsetcontainer)) return; + if (!(cluster_hit_map && hitsetcontainer)) return; // for now this is only filled for micromegas const auto detId = TrkrDefs::getTrkrId(clus_key); - if(detId != TrkrDefs::micromegasId) return; + if (detId != TrkrDefs::micromegasId) return; const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(clus_key); - const auto hitset = hitsetcontainer->findHitSet( hitset_key ); - if( !hitset ) return; + const auto hitset = hitsetcontainer->findHitSet(hitset_key); + if (!hitset) return; const auto range = cluster_hit_map->getHits(clus_key); cluster.energy_max = 0; cluster.energy_sum = 0; - for( const auto& pair:range_adaptor(range)) + for (const auto& pair : range_adaptor(range)) { - const auto hit = hitset->getHit( pair.second ); - if( hit ) + if (dynamic_cast(hitset)) { - const auto energy = hit->getEnergy(); + // specialized hit container for TPCs + + const auto energy = dynamic_cast(hitset)->getTpcADC(pair.second); cluster.energy_sum += energy; - if( energy > cluster.energy_max ) cluster.energy_max = energy; + if (energy > cluster.energy_max) cluster.energy_max = energy; + } + else + { + const auto hit = hitset->getHit(pair.second); + if (hit) + { + const auto energy = hit->getEnergy(); + cluster.energy_sum += energy; + if (energy > cluster.energy_max) cluster.energy_max = energy; + } } } - } // ad}d truth information From 7b7be17ae143eda817730024a24ae3032f031e88 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 16:59:41 -0400 Subject: [PATCH 182/468] adapt to new TPC hit format --- .../g4simulation/g4eval/SvtxEvaluator.cc | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index c654b83c78..1db45cbf49 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -816,19 +817,38 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float occ31 = 0; float occ316 = 0; - for ([[maybe_unused]] const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET_TPC"); + if (hitmap_in) { - TrkrHitSetContainer* hitmap_in = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); - if (hitmap_in) + TrkrHitSetContainer::ConstRange all_hitsets = hitmap_in->getHitSets(); + for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; + hitsetiter != all_hitsets.second; + ++hitsetiter) { - TrkrHitSetContainer::ConstRange all_hitsets = hitmap_in->getHitSets(); - for (TrkrHitSetContainer::ConstIterator hitsetiter = all_hitsets.first; - hitsetiter != all_hitsets.second; - ++hitsetiter) + // we have a single hitset, get the layer + unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { - // we have a single hitset, get the layer - unsigned int layer = TrkrDefs::getLayer(hitsetiter->first); - if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + if (dynamic_cast(hitsetiter->second)) + { + const TrkrHitSetTpc::TimeFrameADCDataType& dataframe = hitset->getTimeFrameAdcData(); + + for (const auto& pad_data : dataframe) + { + for (const auto& adc : pad_data) + { + if (adc > 0) + { + nhit[layer]++; + nhit_tpc_all++; + if ((float) layer == _nlayers_maps + _nlayers_intt) nhit_tpc_in++; + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc - 1) nhit_tpc_out++; + if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) nhit_tpc_mid++; + } + } + } + } // if (dynamic_cast(hitsetiter->second)) + else { // count all hits in this hitset TrkrHitSet::ConstRange hitrangei = hitsetiter->second->getHits(); @@ -845,7 +865,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } } } - } // for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) + } /**********/ PHG4TpcCylinderGeomContainer* geom_container = From b45fcff876b481b17b770d97604c64ed4f9ce079 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 10 Apr 2023 17:15:38 -0400 Subject: [PATCH 183/468] adapt to new TPC hit format: hit ntuple --- .../g4simulation/g4eval/SvtxEvaluator.cc | 474 ++++++++++++------ 1 file changed, 327 insertions(+), 147 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 1db45cbf49..359f6ea3e7 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -831,7 +831,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) { if (dynamic_cast(hitsetiter->second)) { - const TrkrHitSetTpc::TimeFrameADCDataType& dataframe = hitset->getTimeFrameAdcData(); + const TrkrHitSetTpc::TimeFrameADCDataType& dataframe = dynamic_cast(hitsetiter->second)->getTimeFrameAdcData(); for (const auto& pad_data : dataframe) { @@ -863,7 +863,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) if ((float) layer == _nlayers_maps + _nlayers_intt + _nlayers_tpc / 2 - 1) nhit_tpc_mid++; } } - } + }// if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + } } @@ -1583,171 +1584,350 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ++iter) { TrkrDefs::hitsetkey hitset_key = iter->first; - TrkrHitSet* hitset = iter->second; - // get all hits for this hitset - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr) + if (dynamic_cast(iter->second)) { - TrkrDefs::hitkey hit_key = hitr->first; - TrkrHit* hit = hitr->second; - PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); - PHG4Particle* g4particle = trutheval->get_particle(g4hit); - float event = _ievent; - float hitID = hit_key; - float e = hit->getEnergy(); - float adc = hit->getAdc(); - float layer = TrkrDefs::getLayer(hitset_key); - float sector = TpcDefs::getSectorId(hitset_key); - float side = TpcDefs::getSide(hitset_key); - float cellID = 0; - float ecell = hit->getAdc(); - - float phibin = NAN; - float zbin = NAN; - float phi = NAN; - float z = NAN; - - if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) - { - PHG4TpcCylinderGeom* GeoLayer = geom_container->GetLayerCellGeom(layer); - phibin = (float) TpcDefs::getPad(hit_key); - zbin = (float) TpcDefs::getTBin(hit_key); - phi = GeoLayer->get_phicenter(phibin); - z = GeoLayer->get_zcenter(zbin); - } + TrkrHitSetTpc* hitset = dynamic_cast(iter->second); - float g4hitID = NAN; - float gedep = NAN; - float gx = NAN; - float gy = NAN; - float gz = NAN; - float gt = NAN; - float gtrackID = NAN; - float gflavor = NAN; - float gpx = NAN; - float gpy = NAN; - float gpz = NAN; - float gvx = NAN; - float gvy = NAN; - float gvz = NAN; - float gvt = NAN; - float gfpx = NAN; - float gfpy = NAN; - float gfpz = NAN; - float gfx = NAN; - float gfy = NAN; - float gfz = NAN; - float gembed = NAN; - float gprimary = NAN; - - float efromtruth = NAN; - - if (g4hit) + const TrkrHitSetTpc::TimeFrameADCDataType& dataframe = hitset->getTimeFrameAdcData(); + + for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) { - g4hitID = g4hit->get_hit_id(); - gedep = g4hit->get_edep(); - gx = g4hit->get_avg_x(); - gy = g4hit->get_avg_y(); - gz = g4hit->get_avg_z(); - gt = g4hit->get_avg_t(); + const std::vector& pad_data = dataframe[local_pad]; - if (g4particle) + for (unsigned int local_tbin = 0; local_tbin < pad_data.size(); ++local_tbin) { - if (_scan_for_embedded) + const TpcDefs::ADCDataType& rawadc = pad_data[local_tbin]; + if (rawadc <= 0) continue; + + TrkrDefs::hitkey hit_key = hitset->getHitKeyfromLocalBin(local_pad, local_tbin); + + PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); + PHG4Particle* g4particle = trutheval->get_particle(g4hit); + float event = _ievent; + float hitID = hit_key; + float e = rawadc; + float adc = rawadc; + float layer = TrkrDefs::getLayer(hitset_key); + float sector = TpcDefs::getSectorId(hitset_key); + float side = TpcDefs::getSide(hitset_key); + float cellID = 0; + float ecell = rawadc; + + float phibin = NAN; + float zbin = NAN; + float phi = NAN; + float z = NAN; + + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { - if (trutheval->get_embed(g4particle) <= 0) continue; + PHG4TpcCylinderGeom* GeoLayer = geom_container->GetLayerCellGeom(layer); + phibin = (float) TpcDefs::getPad(hit_key); + zbin = (float) TpcDefs::getTBin(hit_key); + phi = GeoLayer->get_phicenter(phibin); + z = GeoLayer->get_zcenter(zbin); } - gtrackID = g4particle->get_track_id(); - gflavor = g4particle->get_pid(); - gpx = g4particle->get_px(); - gpy = g4particle->get_py(); - gpz = g4particle->get_pz(); - - PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle); - - if (vtx) + float g4hitID = NAN; + float gedep = NAN; + float gx = NAN; + float gy = NAN; + float gz = NAN; + float gt = NAN; + float gtrackID = NAN; + float gflavor = NAN; + float gpx = NAN; + float gpy = NAN; + float gpz = NAN; + float gvx = NAN; + float gvy = NAN; + float gvz = NAN; + float gvt = NAN; + float gfpx = NAN; + float gfpy = NAN; + float gfpz = NAN; + float gfx = NAN; + float gfy = NAN; + float gfz = NAN; + float gembed = NAN; + float gprimary = NAN; + + float efromtruth = NAN; + + if (g4hit) { - gvx = vtx->get_x(); - gvy = vtx->get_y(); - gvz = vtx->get_z(); - gvt = vtx->get_t(); + g4hitID = g4hit->get_hit_id(); + gedep = g4hit->get_edep(); + gx = g4hit->get_avg_x(); + gy = g4hit->get_avg_y(); + gz = g4hit->get_avg_z(); + gt = g4hit->get_avg_t(); + + if (g4particle) + { + if (_scan_for_embedded) + { + if (trutheval->get_embed(g4particle) <= 0) continue; + } + + gtrackID = g4particle->get_track_id(); + gflavor = g4particle->get_pid(); + gpx = g4particle->get_px(); + gpy = g4particle->get_py(); + gpz = g4particle->get_pz(); + + PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle); + + if (vtx) + { + gvx = vtx->get_x(); + gvy = vtx->get_y(); + gvz = vtx->get_z(); + gvt = vtx->get_t(); + } + + PHG4Hit* outerhit = nullptr; + if (_do_eval_light == false) + outerhit = trutheval->get_outermost_truth_hit(g4particle); + if (outerhit) + { + gfpx = outerhit->get_px(1); + gfpy = outerhit->get_py(1); + gfpz = outerhit->get_pz(1); + gfx = outerhit->get_x(1); + gfy = outerhit->get_y(1); + gfz = outerhit->get_z(1); + } + gembed = trutheval->get_embed(g4particle); + gprimary = trutheval->is_primary(g4particle); + } // if (g4particle){ } - PHG4Hit* outerhit = nullptr; - if (_do_eval_light == false) - outerhit = trutheval->get_outermost_truth_hit(g4particle); - if (outerhit) + if (g4particle) { - gfpx = outerhit->get_px(1); - gfpy = outerhit->get_py(1); - gfpz = outerhit->get_pz(1); - gfx = outerhit->get_x(1); - gfy = outerhit->get_y(1); - gfz = outerhit->get_z(1); + efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); } - gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); - } // if (g4particle){ - } - if (g4particle) + float hit_data[] = { + event, + (float) _iseed, + hitID, + e, + adc, + layer, + sector, + side, + cellID, + ecell, + (float) phibin, + (float) zbin, + phi, + z, + g4hitID, + gedep, + gx, + gy, + gz, + gt, + gtrackID, + gflavor, + gpx, + gpy, + gpz, + gvx, + gvy, + gvz, + gvt, + gfpx, + gfpy, + gfpz, + gfx, + gfy, + gfz, + gembed, + gprimary, + efromtruth, + nhit_tpc_all, + nhit_tpc_in, + nhit_tpc_mid, + nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; + + _ntp_hit->Fill(hit_data); + + } // for (unsigned int local_tbin = 0; local_tbin < pad_data.size(); ++local_tbin) + + } // for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) + + } // if (TrkrHitSetTpc *hitset = dynamic_cast(my_data->hitset);) + else + { + TrkrHitSet* hitset = iter->second; + + // get all hits for this hitset + TrkrHitSet::ConstRange hitrangei = hitset->getHits(); + for (TrkrHitSet::ConstIterator hitr = hitrangei.first; + hitr != hitrangei.second; + ++hitr) { - efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); + TrkrDefs::hitkey hit_key = hitr->first; + TrkrHit* hit = hitr->second; + PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); + PHG4Particle* g4particle = trutheval->get_particle(g4hit); + float event = _ievent; + float hitID = hit_key; + float e = hit->getEnergy(); + float adc = hit->getAdc(); + float layer = TrkrDefs::getLayer(hitset_key); + float sector = TpcDefs::getSectorId(hitset_key); + float side = TpcDefs::getSide(hitset_key); + float cellID = 0; + float ecell = hit->getAdc(); + + float phibin = NAN; + float zbin = NAN; + float phi = NAN; + float z = NAN; + + if (layer >= _nlayers_maps + _nlayers_intt && layer < _nlayers_maps + _nlayers_intt + _nlayers_tpc) + { + PHG4TpcCylinderGeom* GeoLayer = geom_container->GetLayerCellGeom(layer); + phibin = (float) TpcDefs::getPad(hit_key); + zbin = (float) TpcDefs::getTBin(hit_key); + phi = GeoLayer->get_phicenter(phibin); + z = GeoLayer->get_zcenter(zbin); + } + + float g4hitID = NAN; + float gedep = NAN; + float gx = NAN; + float gy = NAN; + float gz = NAN; + float gt = NAN; + float gtrackID = NAN; + float gflavor = NAN; + float gpx = NAN; + float gpy = NAN; + float gpz = NAN; + float gvx = NAN; + float gvy = NAN; + float gvz = NAN; + float gvt = NAN; + float gfpx = NAN; + float gfpy = NAN; + float gfpz = NAN; + float gfx = NAN; + float gfy = NAN; + float gfz = NAN; + float gembed = NAN; + float gprimary = NAN; + + float efromtruth = NAN; + + if (g4hit) + { + g4hitID = g4hit->get_hit_id(); + gedep = g4hit->get_edep(); + gx = g4hit->get_avg_x(); + gy = g4hit->get_avg_y(); + gz = g4hit->get_avg_z(); + gt = g4hit->get_avg_t(); + + if (g4particle) + { + if (_scan_for_embedded) + { + if (trutheval->get_embed(g4particle) <= 0) continue; + } + + gtrackID = g4particle->get_track_id(); + gflavor = g4particle->get_pid(); + gpx = g4particle->get_px(); + gpy = g4particle->get_py(); + gpz = g4particle->get_pz(); + + PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle); + + if (vtx) + { + gvx = vtx->get_x(); + gvy = vtx->get_y(); + gvz = vtx->get_z(); + gvt = vtx->get_t(); + } + + PHG4Hit* outerhit = nullptr; + if (_do_eval_light == false) + outerhit = trutheval->get_outermost_truth_hit(g4particle); + if (outerhit) + { + gfpx = outerhit->get_px(1); + gfpy = outerhit->get_py(1); + gfpz = outerhit->get_pz(1); + gfx = outerhit->get_x(1); + gfy = outerhit->get_y(1); + gfz = outerhit->get_z(1); + } + gembed = trutheval->get_embed(g4particle); + gprimary = trutheval->is_primary(g4particle); + } // if (g4particle){ + } + + if (g4particle) + { + efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); + } + + float hit_data[] = { + event, + (float) _iseed, + hitID, + e, + adc, + layer, + sector, + side, + cellID, + ecell, + (float) phibin, + (float) zbin, + phi, + z, + g4hitID, + gedep, + gx, + gy, + gz, + gt, + gtrackID, + gflavor, + gpx, + gpy, + gpz, + gvx, + gvy, + gvz, + gvt, + gfpx, + gfpy, + gfpz, + gfx, + gfy, + gfz, + gembed, + gprimary, + efromtruth, + nhit_tpc_all, + nhit_tpc_in, + nhit_tpc_mid, + nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; + + _ntp_hit->Fill(hit_data); } - float hit_data[] = { - event, - (float) _iseed, - hitID, - e, - adc, - layer, - sector, - side, - cellID, - ecell, - (float) phibin, - (float) zbin, - phi, - z, - g4hitID, - gedep, - gx, - gy, - gz, - gt, - gtrackID, - gflavor, - gpx, - gpy, - gpz, - gvx, - gvy, - gvz, - gvt, - gfpx, - gfpy, - gfpz, - gfx, - gfy, - gfz, - gembed, - gprimary, - efromtruth, - nhit_tpc_all, - nhit_tpc_in, - nhit_tpc_mid, - nhit_tpc_out, nclus_all, nclus_tpc, nclus_intt, nclus_maps, nclus_mms}; - - _ntp_hit->Fill(hit_data); - } + } // else -> if (TrkrHitSetTpc *hitset = dynamic_cast(my_data->hitset);) } } - } // for ([[maybe_unused]] const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) + } // for ([[maybe_unused]] const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) if (Verbosity() >= 1) { From 389bb5eb5d95107298a2b30992b3391e979941c7 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 10 Apr 2023 17:20:35 -0400 Subject: [PATCH 184/468] Moving to using residuals and alignment parameters in local coordinates. --- .../HelicalFitter.cc | 309 ++++++++++++------ .../TrackerMillepedeAlignment/HelicalFitter.h | 14 +- .../trackbase/AlignmentTransformation.cc | 32 +- 3 files changed, 238 insertions(+), 117 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 3fedce79f9..e4c224698a 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -165,64 +165,96 @@ int HelicalFitter::process_event(PHCompositeNode*) auto cluskey = cluskey_vec[ivec]; auto cluster = _cluster_map->findCluster(cluskey); if(!cluster) { continue;} + + // What we need now is to find the point on the surface at which the helix would intersect + // If we have that point, we can transform the fit back to local coords + // we have fitpars for the helix and the cluster key, from which we get the surface + + Surface surf = _tGeometry->maps().getSurface(cluskey, cluster); + Acts::Vector3 fitpoint = get_helix_surface_intersection(surf, fitpars, global); + std::cout << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl; + + // fitpoint is the point where the helical fit intersects the plane of the surface + // this is what we need to get the residuals - // PCA of helix to cluster global position - ////Acts::Vector3 pca = get_helix_pca(fitpars, global); - Acts::Vector3 pca = TrackFitUtils::get_helix_pca(fitpars, global); if(Verbosity() > 1) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) - << " pca " << pca(0) << " " << pca(1) << " " << pca(2) << std::endl;} + << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl;} - // capture residuals in the form of (data - fit) - auto residual = global - pca; + // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates + Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); + fitpoint_local /= Acts::UnitConstants::cm; + + Acts::Vector2 residual(cluster->getLocalX() - fitpoint_local(0), cluster->getLocalY() - fitpoint_local(1)); unsigned int layer = TrkrDefs::getLayer(cluskey_vec[ivec]); - if(layer < 2) - { - std::cout << " layer " << layer << " phi " << atan2(global(1), global(0)) - << " dx " << global(0) - pca(0) - << " dy " << global(1) - pca(1) - << std::endl; + float phi = atan2(global(1), global(0)); + std::cout << "Local residuals: layer " << layer << " phi " << phi << " dx " << residual(0) << " dy " << residual(1) << std::endl; + if(Verbosity() > 2) + { + if(layer < 2) + { + std::cout << " Global residuals: layer " << layer << " phi " << phi + << " dx " << global(0) - fitpoint(0) + << " dy " << global(1) - fitpoint(1) + << std::endl; + /* + Acts::Vector3 pca = TrackFitUtils::get_helix_pca(fitpars, global); + std::cout << " layer " << layer << " phi " << phi + << " dx " << global(0) - pca(0) + << " dy " << global(1) - pca(1) + << std::endl; + */ + /* + // check + float phirel = atan2( (global(0) - fitpars[1]), (global(1) - fitpars[2])); + float pdist = sqrt( pow(global(0) - fitpars[1], 2) + pow(global(1) - fitpars[2], 2)); + float pcadist = sqrt( pow(fitpoint(0) - fitpars[1], 2) + pow(fitpoint(1) - fitpars[2], 2)); + std::cout << " helix fitpoint:layer " << layer << " phi " << phi << " phirel " << phirel << " pdist " << pdist << " pcadist " << pcadist + << " R " << fitpars[0] << std::endl; + */ + } } // need standard deviation of measurements Acts::Vector3 clus_sigma = getClusterError(cluster, cluskey, global); if(isnan(clus_sigma(0)) || isnan(clus_sigma(1)) || isnan(clus_sigma(2))) { continue; } - Surface surf = _tGeometry->maps().getSurface(cluskey, cluster); int glbl_label[NGL]; getGlobalLabels(surf, glbl_label); // these depend on the sensor grouping float lcl_derivative[NLC]; float glbl_derivative[NGL]; - unsigned int crossing = 0; // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) - std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster, surf, crossing); - std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster, surf, crossing); + std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); + std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); // Add the measurement separately for each coordinate direction to Mille // set the derivatives non-zero only for parameters we want to be optimized - getLocalDerivativesX(pca, fitpars, lcl_derivative); + getLocalDerivativesX(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative); getGlobalDerivativesX(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} - getLocalDerivativesY(pca, fitpars, lcl_derivative); + /* + getLocalDerivativesY(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative); getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " Y buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if( !isnan(residual(1)) && clus_sigma(1) < 1.0) // discards crazy clusters {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} - + */ + unsigned int trkrid = TrkrDefs::getTrkrId(cluskey); - getLocalDerivativesZ(pca, fitpars, lcl_derivative); + getLocalDerivativesZ(fitpoint, fitpars, lcl_derivative); getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 3) { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(2, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } - if(!isnan(residual(2)) && clus_sigma(2) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(2), _error_inflation*clus_sigma(2));} + if(!isnan(residual(1)) && clus_sigma(2) < 1.0 && trkrid != TrkrDefs::inttId) + {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(2));} + } // close out this track @@ -232,6 +264,85 @@ int HelicalFitter::process_event(PHCompositeNode*) return Fun4AllReturnCodes::EVENT_OK; } + +Acts::Vector3 HelicalFitter::get_helix_surface_intersection(Surface surf, std::vector& fitpars, Acts::Vector3 global) +{ + // we want the point where the helix intersects the plane of the surface + + // get the plane of the surface + Acts::Vector3 sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1; // convert to cm + Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext()); + sensorNormal /= sensorNormal.norm(); + + // there are analytic solutions for a line-plane intersection. + // to use this, need to get the vector tangent to the helix near the measurement and a point on it. + std::pair line = get_helix_tangent(fitpars, global); + Acts::Vector3 pca = line.first; + Acts::Vector3 tangent = line.second; + + std::cout << " pca: " << pca(0) << " " << pca(1) << " " << pca(2) << " " << std::endl; + + Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal); + + return intersection; +} + +Acts::Vector3 HelicalFitter::get_line_plane_intersection(Acts::Vector3 PCA, Acts::Vector3 tangent, Acts::Vector3 sensor_center, Acts::Vector3 sensor_normal) +{ + // get the intersection of the line made by PCA and tangent with the plane of the sensor + + // For a point on the line + // p = PCA + d * tangent; + // for a point on the plane + // (p - sensor_center).sensor_normal = 0 + + // The solution is: + float d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal); + Acts::Vector3 intersection = PCA + d * tangent; + std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; + std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; + std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; + + return intersection; +} + + +std::pair HelicalFitter::get_helix_tangent(std::vector& fitpars, Acts::Vector3 global) +{ + // no analytic solution for the coordinates of the closest approach of a helix to a point + // Instead, we get the PCA in x and y to the circle, and the PCA in z to the z vs R line at the R of the PCA + + float radius = fitpars[0]; + float x0 = fitpars[1]; + float y0 = fitpars[2]; + float zslope = fitpars[3]; + float z0 = fitpars[4]; + + Acts::Vector2 pca_circle = get_circle_point_pca(radius, x0, y0, global); + + // The radius of the PCA determines the z position: + float pca_circle_radius = pca_circle.norm(); + float pca_z = pca_circle_radius * zslope + z0; + Acts::Vector3 pca(pca_circle(0), pca_circle(1), pca_z); + + // now we want a second point on the helix so we can get a local straight line approximation to the track + // project the circle PCA vector an additional small amount and find the helix PCA to that point + float projection = 0.25; // cm + Acts::Vector3 second_point = pca + projection * pca/pca.norm(); + Acts::Vector2 second_point_pca_circle = get_circle_point_pca(radius, x0, y0, second_point); + float second_point_pca_z = pca_circle_radius * zslope + z0; + Acts::Vector3 second_point_pca(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z); + + // pca and second_point_pca define a straight line approximation to the track + Acts::Vector3 tangent = (second_point_pca - pca) / (second_point_pca - pca).norm(); + + // get the PCA of the cluster to that line + Acts::Vector3 final_pca = getPCALinePoint(global, tangent, pca); + + std::pair line = std::make_pair(final_pca, tangent); + + return line; +} int HelicalFitter::End(PHCompositeNode* ) { @@ -309,17 +420,11 @@ Acts::Vector2 HelicalFitter::get_circle_point_pca(float radius, float x0, float return pca; } -std::vector HelicalFitter::getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing) +std::vector HelicalFitter::getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) { - // The value of global is from the geocontext transformation - // we add to that transformation a small rotation around the relevant axis in the surface frame - std::vector derivs_vector; - // get the transformation from the geocontext - Acts::Transform3 transform = surface->transform(_tGeometry->geometry().getGeoContext()); - - // Make an additional transform that applies a small rotation angle in the surface frame + // Make a transform that applies small translations in the surface frame for(unsigned int itrans = 0; itrans < 3; ++itrans) { // creates transform that adds a perturbation translation along one axis, uses it to estimate derivative wrt perturbation translation @@ -341,37 +446,36 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac << " sensorTransl " << theseTransl[0] << " " << theseTransl[1] << " " << theseTransl[2] << std::endl; } Acts::Transform3 perturbationTranslation = makePerturbationTranslation(theseTransl); - Acts::Transform3 overallTransformation = perturbationTranslation * transform; // transform the cluster local position to global coords with this additional translation added auto x = cluster->getLocalX() * 10; // mm auto y = cluster->getLocalY() * 10; if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } - Eigen::Vector3d clusterLocalPosition (x,y,0); // follows the convention for the acts transform of local = (x,z,y) - Eigen::Vector3d finalCoords = overallTransformation*clusterLocalPosition; // result in mm + Eigen::Vector3d clusterLocalPosition (x,0,y); // follows our convention for local coords + Eigen::Vector3d finalCoords = perturbationTranslation*clusterLocalPosition; // result in mm finalCoords /= 10.0; // convert mm back to cm // have to add corrections for TPC clusters after transformation to global - if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } + // if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } - // note that global cancels out here + // note that x and y cancel out here if(ip == 0) { - keeper(0) = (finalCoords(0) - global(0)); - keeper(1) = (finalCoords(1) - global(1)); - keeper(2) = (finalCoords(2) - global(2)); + keeper(0) = (finalCoords(0) - x); + keeper(1) = 0; + keeper(2) = (finalCoords(2) - y); } else { - keeper(0) -= (finalCoords(0) - global(0)); - keeper(1) -= (finalCoords(1) - global(1)); - keeper(2) -= (finalCoords(2) - global(2)); + keeper(0) -= (finalCoords(0) - x); + keeper(1) -= 0; + keeper(2) -= (finalCoords(2) - y); } if(Verbosity() > 1) { - std::cout << " finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " + std::cout << " AlignmentTranslationsDerives: finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " << finalCoords(1) << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) << " global(2) " << global(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " @@ -398,17 +502,12 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac return derivs_vector; } -std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing) +std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) { - // The value of global is from the geocontext transformation - // we add to that transformation a small rotation around the relevant axis in the surface frame + // Wev want the effect of a small rotation around the relevant axis in the local frame on the local coords std::vector derivs_vector; - // get the transformation from the geocontext - Acts::Transform3 transform = surface->transform(_tGeometry->geometry().getGeoContext()); - - // Make an additional transform that applies a small rotation angle in the surface frame for(unsigned int iangle = 0; iangle < 3; ++iangle) { // creates transform that adds a perturbation rotation around one axis, uses it to estimate derivative wrt perturbation rotation @@ -430,52 +529,47 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve << " sensorAngles " << theseAngles[0] << " " << theseAngles[1] << " " << theseAngles[2] << std::endl; } Acts::Transform3 perturbationTransformation = makePerturbationTransformation(theseAngles); - Acts::Transform3 overallTransformation = transform * perturbationTransformation; - - // transform the cluster local position to global coords with this additional rotation added + + // transform the cluster local position using this additional rotation auto x = cluster->getLocalX() * 10; // mm auto y = cluster->getLocalY() * 10; if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } - Eigen::Vector3d clusterLocalPosition (x,y,0); // follows the convention for the acts transform of local = (x,z,y) - Eigen::Vector3d finalCoords = overallTransformation*clusterLocalPosition; // result in mm - finalCoords /= 10.0; // convert mm back to cm + Eigen::Vector3d clusterLocalPosition (x,0,y); // our convention, applies until Acts global rotation occurs + Eigen::Vector3d finalLocalPosition = perturbationTransformation*clusterLocalPosition; // result in mm + finalLocalPosition /= 10.0; // convert mm back to cm // have to add corrections for TPC clusters after transformation to global - if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } - // note that global cancels out here + // note that x and y cancel out here if(ip == 0) { - keeper(0) = (finalCoords(0) - global(0)); - keeper(1) = (finalCoords(1) - global(1)); - keeper(2) = (finalCoords(2) - global(2)); + keeper(0) = (finalLocalPosition(0) - x); + keeper(2) = (finalLocalPosition(2) - y); } else { - keeper(0) -= (finalCoords(0) - global(0)); - keeper(1) -= (finalCoords(1) - global(1)); - keeper(2) -= (finalCoords(2) - global(2)); + keeper(0) -= (finalLocalPosition(0) - x); + keeper(2) -= (finalLocalPosition(2) - y); } if(Verbosity() > 1) { - std::cout << " finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " << finalCoords(1) - << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) << " global(2) " << global(2) << std::endl; + std::cout << " AliognmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " global(0) " << global(0) << " finalLocalPosition(1) " << finalLocalPosition(1) + << " global(1) " << global(1) << " finalLocalPosition(2) " << finalLocalPosition(2) << " global(2) " << global(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; } } // derivs vector contains: - // (dx/dalpha, dy/dalpha, dz/dalpha) (for iangle = 0) - // (dx/dbeta, dy/dbeta, dz/dbeta) (for iangle = 1) - // (dx/dgamma, dy/dgamma, dz/dgamma) (for iangle = 2) + // (dx/dalpha, dz/dalpha) (for iangle = 0) + // (dx/dbeta, dz/dbeta) (for iangle = 1) + // (dx/dgamma, dz/dgamma) (for iangle = 2) // Average the changes to get the estimate of the derivative derivs(0) = keeper(0) / (2.0 * fabs(theseAngles[iangle])); if( isnan(derivs(0)) ) { derivs(0) = 0; } - derivs(1) = keeper(1) / (2.0 * fabs(theseAngles[iangle])); - if( isnan(derivs(1)) ) { derivs(1) = 0; } + derivs(1) = 0.0; // this would be the unused y axis in the local coord frame derivs(2) = keeper(2) / (2.0 * fabs(theseAngles[iangle])); if( isnan(derivs(2)) ) { derivs(2) = 0; } derivs_vector.push_back(derivs); @@ -488,15 +582,15 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve Acts::Transform3 HelicalFitter::makePerturbationTranslation(Acts::Vector3 translations) { - // combine unit rotation and perturbation translation into an affine matrix + // combine unit rotation and perturbation translations in the local frame into an affine matrix Acts::Transform3 perturbationTransformation; Eigen::AngleAxisd alpha(0.0, Eigen::Vector3d::UnitX()); Eigen::AngleAxisd beta(0.0, Eigen::Vector3d::UnitY()); Eigen::AngleAxisd gamma(0.0, Eigen::Vector3d::UnitZ()); Eigen::Quaternion q = gamma*beta*alpha; - Eigen::Matrix3d perturbationRotation = q.matrix(); - perturbationTransformation.linear() = perturbationRotation; + Eigen::Matrix3d nullRotation = q.matrix(); + perturbationTransformation.linear() = nullRotation; perturbationTransformation.translation() = translations; @@ -508,8 +602,8 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve // Note: Here beta is applied to the z axis and gamma is applied to the y axis because the geocontext transform // will flip those axes when transforming to global coordinates Eigen::AngleAxisd alpha(angles(0), Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(angles(2), Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(angles(1), Eigen::Vector3d::UnitZ()); + Eigen::AngleAxisd beta(angles(1), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(angles(2), Eigen::Vector3d::UnitZ()); Eigen::Quaternion q = gamma*beta*alpha; Eigen::Matrix3d perturbationRotation = q.matrix(); @@ -725,32 +819,44 @@ Acts::Vector3 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu return clus_sigma; } -void HelicalFitter::getLocalDerivativesX(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[5]) +void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5]) { float radius = fitpars[0]; float x0 = fitpars[1]; float y0 = fitpars[2]; - float x = pca(0); - float y = pca(1); - float dr = 0.2; - float dy0 = 0.05; + float x = fitpoint_local(0); + float y = fitpoint_local(2); + // fitpoint is in global coords, fitpoint local in local coords + // local x is unaffected by the z fit + // we only need to consider the circle fit paramaters // Do these numerically // dx/dradius - // increasing R changes both x and y - float phi = atan2(y-y0, x-x0); - float dxr = dr * cos(phi); - float dx_dr = dxr/dr; + // increasing R changes both local x and local y very little! + float dx_dr = 0; + /* + OR: change R and transform fitpoint to local coords + */ // dx/dx0 - float dx_dx0 = 1; - - // dx/dy0 - // x = x0 + sqrt(pow(radius, 2) + pow(y-y0, 2)) - float dxy0 = sqrt(pow(radius, 2) + pow(y-y0+dy0, 2)) - - sqrt(pow(radius, 2) + pow(y-y0, 2)); - float dx_dy0 = dxy0/dy0; + // changing x0 changes global x by the same amount + float dx0 = 0.01; + Acts::Vector3 fitpoint_now(fitpoint(0)+dx0, fitpoint(1), fitpoint(2)); + Acts::Vector3 fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); + fitpoint_local_now /= Acts::UnitConstants::cm; + Acts::Vector3 dres = fitpoint_local_now - fitpoint_local; + float dx_dx0 = dres(0) / dx0; + + float dy0 = 0.01; + // changing y0 changes global y by the same amount + fitpoint_now(0) = fitpoint(0); + fitpoint_now(1) = fitpoint(1)+dy0; + fitpoint_now(2) = fitpoint(2); + fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); + fitpoint_local_now /= Acts::UnitConstants::cm; + dres = fitpoint_local_now - fitpoint_local; + float dx_dy0 = dres(0) / dy0; if(Verbosity() > 1) { std::cout << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; @@ -798,10 +904,13 @@ void HelicalFitter::getLocalDerivativesY(Acts::Vector3& pca, std::vector& lcl_derivative[3] = dy_dr; } -void HelicalFitter::getLocalDerivativesZ(Acts::Vector3& global, std::vector& fitpars, float lcl_derivative[5]) +void HelicalFitter::getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vector& fitpars, float lcl_derivative[5]) { + // the local coord corresponding to z is local-y. + // changes in z global translate directly to y-local + float zslope = fitpars[3]; - float cluster_radius = sqrt(global(0)*global(0)+global(1)*global(1)); + float cluster_radius = sqrt(fitpoint(0)*fitpoint(0)+fitpoint(1)*fitpoint(1)); float z0 = fitpars[4]; // z = z0 + zslope * cluster_radius @@ -809,7 +918,7 @@ void HelicalFitter::getLocalDerivativesZ(Acts::Vector3& global, std::vector 1) { - std::cout << " x " << global(0)<<" y "< angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { - // x - relevant global pars are alpha, beta, gamma, dx (ipar 0,1,2,3), relevant local pars are x_x0, x_radius + // local-x: relevant global pars are alpha, beta, gamma, dx, dy (ipar 0,1,2,3) for(int i=0;i angleDeriv glbl_derivative[1] = angleDerivs[1](2); // dz/dbeta glbl_derivative[2] = angleDerivs[2](2); // dz/dgamma - glbl_derivative[3] = translDerivs[0](2); // dz/dx - glbl_derivative[4] = translDerivs[1](2); // dz/dy + glbl_derivative[3] = translDerivs[0](2); // dz/dx = 0 + glbl_derivative[4] = translDerivs[1](2); // dz/dy = 0 glbl_derivative[5] = translDerivs[2](2); // dz/dz for(int i=0; i< NGL; ++i) @@ -890,7 +999,7 @@ void HelicalFitter::getGlobalDerivativesZ( std::vector angleDeriv } } -void HelicalFitter::printBuffers(int index, Acts::Vector3 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) +void HelicalFitter::printBuffers(int index, Acts::Vector2 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) { std::cout << " float buffer: " << " residual " << " " << residual(index); for (int il=0;il get_helix_tangent(std::vector& fitpars, Acts::Vector3 global); + Acts::Vector3 get_helix_surface_intersection(Surface surf, std::vector& fitpars, Acts::Vector3 global); int getLabelBase(Acts::GeometryIdentifier id); Acts::Transform3 makePerturbationTransformation(Acts::Vector3 angles); Acts::Transform3 makePerturbationTranslation(Acts::Vector3 translations); - std::vector getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing); - std::vector getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing); + std::vector getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); + std::vector getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); void makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global); int getTpcRegion(int layer); Acts::Vector3 getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global); void getGlobalLabels(Surface surf, int glbl_label[]); - void getLocalDerivativesX(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[]); + void getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5]); void getLocalDerivativesY(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[]); - void getLocalDerivativesZ(Acts::Vector3& global, std::vector& fitpars, float lcl_derivative[]); + void getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vector& fitpars, float lcl_derivative[5]); void getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - void printBuffers(int index, Acts::Vector3 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); + void printBuffers(int index, Acts::Vector2 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 81794f481c..126e5328da 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -32,6 +32,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { + localVerbosity = 0; + getNodes(topNode); // Use construction transforms as a reference for making the map @@ -47,7 +49,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) if(datafile.is_open()) { std::cout << "AlignmentTransformation: Reading alignment parameters from disk file: " - << alignmentParamsFile << std::endl; + << alignmentParamsFile << " localVerbosity = " << localVerbosity << std::endl; } else { @@ -86,14 +88,15 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); + Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) { std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; - std::cout << "mvtx transform" << transform.matrix() << std::endl; + std::cout << "mvtx transform:" << std::endl << transform.matrix() << std::endl; + std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; } transformMap->addTransform(id,transform); } @@ -296,9 +299,11 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: Eigen::Matrix3d nullRotation = qnull.matrix(); // Create alignment rotation matrix + // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) + // So we apply alpha to x, gamma to y, and beta to z in the local frame Eigen::AngleAxisd alpha(sensorAngles(0), Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(sensorAngles(1), Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(sensorAngles(2), Eigen::Vector3d::UnitZ()); + Eigen::AngleAxisd beta(sensorAngles(2), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(sensorAngles(1), Eigen::Vector3d::UnitZ()); Eigen::Quaternion q = gamma*beta*alpha; Eigen::Matrix3d millepedeRotation = q.matrix(); @@ -306,7 +311,6 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: mpRotationAffine.linear() = millepedeRotation; mpRotationAffine.translation() = nullTranslation; - // create alignment translation matrix Acts::Transform3 mpTranslationAffine; mpTranslationAffine.linear() = nullRotation; @@ -317,12 +321,10 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: Eigen::Matrix3d actsRotationPart = actsTransform.rotation(); Eigen::Vector3d actsTranslationPart = actsTransform.translation(); - // modify actsRotationPart so that it rotates (x,y,z)->(x',y',z') instead of (x,z,y)->(x',y',z') - Eigen::Matrix3d modifiedActsRotationPart = modifyRotationConvention(actsRotationPart); - // and make affine matrices from each Acts::Transform3 actsRotationAffine; - actsRotationAffine.linear() = modifiedActsRotationPart; + // actsRotationAffine.linear() = modifiedActsRotationPart; + actsRotationAffine.linear() = actsRotationPart; actsRotationAffine.translation() = nullTranslation; Acts::Transform3 actsTranslationAffine; actsTranslationAffine.linear() = nullRotation; @@ -330,14 +332,19 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: //Put them together into a combined transform - Acts::Transform3 transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; + // EITHER: put the translations in the global frame + // Acts::Transform3 transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; + // OR: put the translations in the local coordinate frame + Acts::Transform3 transform = actsTranslationAffine * actsRotationAffine * mpTranslationAffine * mpRotationAffine; if(localVerbosity > 2) { + std::cout << "newMakeTransform" << std::endl; std::cout << "mpRotationAffine: "<< std::endl<< mpRotationAffine.matrix() < 2) { + std::cout << "makeTransform:" << std::endl; std::cout << "sensor center: " << sensorCenter << " millepede translation: " << millepedeTranslation < Date: Mon, 10 Apr 2023 21:12:46 -0400 Subject: [PATCH 185/468] remove CaloTowerCalib.cc to build without dbtools --- offline/packages/CaloReco/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/CaloReco/Makefile.am b/offline/packages/CaloReco/Makefile.am index d0777c79e1..0b7ff200c7 100644 --- a/offline/packages/CaloReco/Makefile.am +++ b/offline/packages/CaloReco/Makefile.am @@ -28,7 +28,6 @@ libcalo_reco_la_LIBADD = \ -lsph_onnx \ -lcaloCalibDBFile \ -lcdbobjects \ - -ldbtools \ -lphparameter endif @@ -70,7 +69,6 @@ libcalo_reco_la_SOURCES = \ CaloWaveformFitting.cc \ CaloWaveformProcessing.cc \ CaloTowerBuilder.cc \ - CaloTowerCalib.cc \ RawClusterBuilderGraph.cc \ RawClusterBuilderTopo.cc \ RawClusterBuilderTemplate.cc \ From 5d79f8732d96bc25c9ae4c2b0dd13d3505acf24c Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 10 Apr 2023 23:14:45 -0400 Subject: [PATCH 186/468] Diagnostic output changes. --- .../HelicalFitter.cc | 26 +++++++------ .../trackbase/AlignmentTransformation.cc | 39 ++++++++++++------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index e4c224698a..9c16980468 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -176,16 +176,18 @@ int HelicalFitter::process_event(PHCompositeNode*) // fitpoint is the point where the helical fit intersects the plane of the surface // this is what we need to get the residuals - - if(Verbosity() > 1) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) - << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl;} - + // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; Acts::Vector2 residual(cluster->getLocalX() - fitpoint_local(0), cluster->getLocalY() - fitpoint_local(1)); - + + if(Verbosity() > 1) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl + << " fitpoint_local " << fitpoint_local(0) << " " << fitpoint_local(1) << " " << fitpoint_local(2) << std::endl + << " cluster local x " << cluster->getLocalX() << " cluster local y " << cluster->getLocalY() << std::endl + << " cluster local residual x " << residual(0) << " cluster local residual y " < HelicalFitter::getDerivativesAlignmentTranslations(Ac keeper(2) -= (finalCoords(2) - y); } - if(Verbosity() > 1) + if(Verbosity() > 5) { - std::cout << " AlignmentTranslationsDerives: finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " + std::cout << " AlignmentTranslationsDerivs: finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " << finalCoords(1) << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) << " global(2) " << global(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " @@ -497,7 +499,7 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac if( isnan(derivs(2)) ) { derivs(2) = 0; } derivs_vector.push_back(derivs); - if(Verbosity() > 1) { std::cout << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } + if(Verbosity() > 1) { std::cout << " AlignmentTranslationsDerivs: itrans " << itrans << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } } return derivs_vector; } @@ -540,6 +542,8 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve finalLocalPosition /= 10.0; // convert mm back to cm // have to add corrections for TPC clusters after transformation to global + // The helical fit is to corrected data, so if we transform back to local, can + // we compare with the cluster local? What is needed here for the TPC? // note that x and y cancel out here if(ip == 0) @@ -553,9 +557,9 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve keeper(2) -= (finalLocalPosition(2) - y); } - if(Verbosity() > 1) + if(Verbosity() > 5) { - std::cout << " AliognmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " global(0) " << global(0) << " finalLocalPosition(1) " << finalLocalPosition(1) + std::cout << " AlignmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " global(0) " << global(0) << " finalLocalPosition(1) " << finalLocalPosition(1) << " global(1) " << global(1) << " finalLocalPosition(2) " << finalLocalPosition(2) << " global(2) " << global(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; } @@ -574,7 +578,7 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve if( isnan(derivs(2)) ) { derivs(2) = 0; } derivs_vector.push_back(derivs); - if(Verbosity() > 1) { std::cout << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } + if(Verbosity() > 1) { std::cout << " AlignmentAngleDerivs: iangle " << iangle << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } } return derivs_vector; diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 126e5328da..c07eaea5bb 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -88,19 +88,19 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) { - std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; - std::cout << "mvtx transform:" << std::endl << transform.matrix() << std::endl; - std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; + //Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); + std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; + std::cout << " final mvtx transform:" << std::endl << transform.matrix() << std::endl; + // std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; } transformMap->addTransform(id,transform); } - + else if(trkrId == TrkrDefs::inttId) { @@ -189,6 +189,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } +// no longer used Eigen::Matrix3d AlignmentTransformation::rotateToGlobal(Surface surf) { /* @@ -236,6 +237,7 @@ Eigen::Matrix3d AlignmentTransformation::rotateToGlobal(Surface surf) return globalRotation; } +// no longer used Eigen::Matrix3d AlignmentTransformation::modifyRotationConvention(Eigen::Matrix3d rotationMatrix) { // Acts uses a rotation matrix that transforms local position (x,z,y) into global position (x',y',z') @@ -260,6 +262,7 @@ Eigen::Matrix3d AlignmentTransformation::modifyRotationConvention(Eigen::Matrix3 return actsRotationMatrix; } +// no longer used Acts::Transform3 AlignmentTransformation::makeAffineMatrix(Eigen::Matrix3d rotationMatrix, Eigen::Vector3d translationVector) { // Acts uses a rotation matrix that transforms local position (x,z,y) into global position (x',y',z') @@ -299,11 +302,18 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: Eigen::Matrix3d nullRotation = qnull.matrix(); // Create alignment rotation matrix + // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) - // So we apply alpha to x, gamma to y, and beta to z in the local frame + //===================================================== + // So our beginning local position vector should be (x,z,y) + // and our MP (local) alignment translation vector should be (dx,dz,dy) + // We don't worry about the angle parameter order, since they are + // just arbitrary parameters that will be fitted to data + //===================================================== + Eigen::AngleAxisd alpha(sensorAngles(0), Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(sensorAngles(2), Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(sensorAngles(1), Eigen::Vector3d::UnitZ()); + Eigen::AngleAxisd beta(sensorAngles(1), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(sensorAngles(2), Eigen::Vector3d::UnitZ()); Eigen::Quaternion q = gamma*beta*alpha; Eigen::Matrix3d millepedeRotation = q.matrix(); @@ -323,7 +333,6 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: // and make affine matrices from each Acts::Transform3 actsRotationAffine; - // actsRotationAffine.linear() = modifiedActsRotationPart; actsRotationAffine.linear() = actsRotationPart; actsRotationAffine.translation() = nullTranslation; Acts::Transform3 actsTranslationAffine; @@ -332,24 +341,26 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: //Put them together into a combined transform - // EITHER: put the translations in the global frame + // EITHER: put the mp translations in the global frame // Acts::Transform3 transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; - // OR: put the translations in the local coordinate frame + // OR (new): put the mp translations in the local coordinate frame Acts::Transform3 transform = actsTranslationAffine * actsRotationAffine * mpTranslationAffine * mpRotationAffine; if(localVerbosity > 2) { std::cout << "newMakeTransform" << std::endl; std::cout << "mpRotationAffine: "<< std::endl<< mpRotationAffine.matrix() < 2) { std::cout << "makeTransform:" << std::endl; - std::cout << "sensor center: " << sensorCenter << " millepede translation: " << millepedeTranslation < Date: Tue, 11 Apr 2023 00:20:57 -0400 Subject: [PATCH 187/468] adapt to new TPC hit format: cluster ntuple --- .../g4simulation/g4eval/SvtxEvaluator.cc | 152 +++++++++++------- .../g4simulation/g4eval/SvtxEvaluator.h | 1 + 2 files changed, 94 insertions(+), 59 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 359f6ea3e7..88fe7f1133 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -65,6 +65,74 @@ using namespace std; +namespace sumClusterEnergyFromHits +{ + void calc( + TrkrClusterHitAssoc* clusterhitmap, + TrkrDefs::cluskey cluster_key, + const std::map& hitsetsmap, + float& sumadc, + float& maxadc, + float& size) + { + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key); + sumadc = 0; + + auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); + if (hitsetsmap_iter != hitsetsmap.end()) + { + TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; + assert(hitsets); + + if (dynamic_cast(hitsets->findHitSet(hitsetkey))) + { + // specialized hit container for TPCs + + TrkrHitSetTpc* hitset = dynamic_cast(hitsets->findHitSet(hitsetkey)); + + std::pair::const_iterator, std::multimap::const_iterator> + hitrange = clusterhitmap->getHits(cluster_key); + for (std::multimap::const_iterator + clushititer = hitrange.first; + clushititer != hitrange.second; ++clushititer) + { + auto adc = hitset->getTpcADC(clushititer->second); + if (adc <= 0) continue; + + ++size; + sumadc += (adc - 70); + if ((adc - 70) > maxadc) + maxadc = (adc - 70); + } + + } // if (dynamic_cast(hitsets->findHitSet(hitsetkey))) + else + { + TrkrHitSet* hitset = hitsets->findHitSet(hitsetkey); + + std::pair::const_iterator, std::multimap::const_iterator> + hitrange = clusterhitmap->getHits(cluster_key); + for (std::multimap::const_iterator + clushititer = hitrange.first; + clushititer != hitrange.second; ++clushititer) + { + TrkrHit* hit = hitset->getHit(clushititer->second); + if (!hit) continue; + + ++size; + sumadc += (hit->getAdc() ); + if ((hit->getAdc() ) > maxadc) + maxadc = (hit->getAdc()); + } + + } // else -> if (dynamic_cast(hitsets->findHitSet(hitsetkey))) + + } // if (hitsetsmap_iter != hitsetsmap.end()) + + } // void calc( + +} // namespace sumClusterEnergyFromHits + SvtxEvaluator::SvtxEvaluator(const string& /*name*/, const string& filename, const string& trackmapname, unsigned int nlayers_maps, unsigned int nlayers_intt, @@ -1946,6 +2014,14 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) _timer->restart(); } + std::map hitsetsmap; + for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + { + TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + if (hitsets) + hitsetsmap[trkrID] = hitsets; + } + if (_ntp_cluster && !_scan_for_embedded) { if (Verbosity() > 1) cout << "Filling ntp_cluster (all of them) " << endl; @@ -1955,13 +2031,6 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - std::map hitsetsmap; - for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) - { - TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); - if (hitsets) - hitsetsmap[trkrID] = hitsets; - } TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); ClusterErrorPara ClusErrPara; @@ -2066,31 +2135,15 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) cout << "Good hitset layer " << hitsetlayer << "| " << hitsetlayer2 << " layer " << layer << endl; } */ - float sumadc = 0; - - auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); - if (hitsetsmap_iter != hitsetsmap.end()) - { - TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; - assert(hitsets); - TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); - std::pair::const_iterator, std::multimap::const_iterator> - hitrange = clusterhitmap->getHits(cluster_key); - for (std::multimap::const_iterator - clushititer = hitrange.first; - clushititer != hitrange.second; ++clushititer) - { - TrkrHit* hit = hitset->second->getHit(clushititer->second); - if (!hit) continue; - - ++size; - sumadc += (hit->getAdc() - 70); - if ((hit->getAdc() - 70) > maxadc) - maxadc = (hit->getAdc() - 70); - } - } - e = sumadc; + sumClusterEnergyFromHits::calc( + clusterhitmap, + cluster_key, + hitsetsmap, + e, + maxadc, + size + ); float trackID = NAN; if (track!=NULL) trackID = track->get_id(); @@ -2281,14 +2334,6 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) TrkrClusterHitAssoc* clusterhitmap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - std::map hitsetsmap; - for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) - { - TrkrHitSetContainer * hitsets = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); - if (hitsets) - hitsetsmap[trkrID] = hitsets; - } - TrkrClusterIterationMapv1* _iteration_map = findNode::getClass(topNode, "CLUSTER_ITERATION_MAP"); if (trackmap != nullptr && clustermap != nullptr && clusterhitmap != nullptr && hitsetsmap.size() != 0){ @@ -2392,28 +2437,17 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) // count all hits for this cluster float maxadc = -999; + float sumadc = 0; + sumClusterEnergyFromHits::calc( + clusterhitmap, + cluster_key, + hitsetsmap, + sumadc, + maxadc, + size + ); - // count all hits for this cluster - TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key); - auto hitsetsmap_iter = hitsetsmap.find(TrkrDefs::getTrkrId(hitsetkey)); - if (hitsetsmap_iter != hitsetsmap.end()) - { - TrkrHitSetContainer* hitsets = hitsetsmap_iter->second; - assert(hitsets); - TrkrHitSetContainer::Iterator hitset = hitsets->findOrAddHitSet(hitsetkey); - std::pair::const_iterator, std::multimap::const_iterator> - hitrange = clusterhitmap->getHits(cluster_key); - for (std::multimap::const_iterator - clushititer = hitrange.first; - clushititer != hitrange.second; ++clushititer) - { - TrkrHit* hit = hitset->second->getHit(clushititer->second); - ++size; - if (hit->getAdc() > maxadc) - maxadc = hit->getAdc(); - } - } float trackID = NAN; trackID = track->get_id(); diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.h b/simulation/g4simulation/g4eval/SvtxEvaluator.h index ca3b58189a..18f791138b 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.h +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.h @@ -139,6 +139,7 @@ class SvtxEvaluator : public SubsysReco void printInputInfo(PHCompositeNode *topNode); ///< print out the input object information (debugging upstream components) void printOutputInfo(PHCompositeNode *topNode); ///< print out the ancestry information for detailed diagnosis int m_cluster_version = 4; + }; #endif // G4EVAL_SVTXEVALUATOR_H From 589e786aa62694210b2ae0df1f7bc1665ca4a76f Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 09:33:47 -0400 Subject: [PATCH 188/468] clean up --- offline/packages/tpccalib/TpcDirectLaserReconstruction.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc index d1f0884852..59b030dda5 100644 --- a/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc +++ b/offline/packages/tpccalib/TpcDirectLaserReconstruction.cc @@ -388,11 +388,6 @@ void TpcDirectLaserReconstruction::process_track( SvtxTrack* track ) const unsigned short NTBins = (unsigned short)layergeom->get_zbins(); const float tdriftmax = AdcClockPeriod * NTBins / 2.0; - // get corresponding hits - TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - -// for (auto hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) - const TrkrHitSetTpc::TimeFrameADCDataType &dataframe = hitset->getTimeFrameAdcData(); for (unsigned int local_pad = 0; local_pad < dataframe.size(); ++local_pad) From 46e3ae6a87d061b3d7c0a1b5fc94ec0275db8c2b Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 11:47:24 -0400 Subject: [PATCH 189/468] clean up --- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc | 2 -- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h | 3 --- 2 files changed, 5 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index f57e4bf876..25120b9a2c 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -33,8 +33,6 @@ PHG4TpcDigitizer::PHG4TpcDigitizer(const std::string &name) : SubsysReco(name) - , TpcMinLayer(7) - , TpcNLayers(48) , ADCThreshold(2700) // electrons , TpcEnc(670) // electrons , Pedestal(50000) // electrons diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index 35b3963d8c..2f9a0c5941 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -41,7 +41,6 @@ class PHG4TpcDigitizer : public SubsysReco _energy_scale.insert(std::make_pair(layer, energy_per_adc)); } - void SetTpcMinLayer(const int minlayer) { TpcMinLayer = minlayer; }; void SetADCThreshold(const float thresh) { ADCThreshold = thresh; }; void SetENC(const float enc) { TpcEnc = enc; }; void set_drift_velocity(float vd) {_drift_velocity = vd;} @@ -55,8 +54,6 @@ class PHG4TpcDigitizer : public SubsysReco float added_noise(); float add_noise_to_bin(float signal); - unsigned int TpcMinLayer; - unsigned int TpcNLayers; float ADCThreshold; float ADCThreshold_mV = 0; float TpcEnc; From 4691ac832df1c1a8b24005ef1e6c08f9b65c3280 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 24 Mar 2022 11:44:20 -0400 Subject: [PATCH 190/468] - allow to configure minimum pT for calculating track residuals - print configuration at ::Init --- offline/packages/tpccalib/PHTpcResiduals.cc | 11 +++++-- offline/packages/tpccalib/PHTpcResiduals.h | 33 ++++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 90f81724ac..64d501917d 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -107,6 +107,13 @@ PHTpcResiduals::PHTpcResiduals(const std::string &name) int PHTpcResiduals::Init(PHCompositeNode */*topNode*/) { if( m_savehistograms ) makeHistograms(); + + // configuration printout + std::cout << "PHTpcResiduals::Init - m_maxTAlpha: " << m_maxTAlpha << std::endl; + std::cout << "PHTpcResiduals::Init - m_maxTBeta: " << m_maxTBeta << std::endl; + std::cout << "PHTpcResiduals::Init - m_maxResidualDrphi: " << m_maxResidualDrphi << " cm" << std::endl; + std::cout << "PHTpcResiduals::Init - m_maxResidualDz: " << m_maxResidualDz << " cm" << std::endl; + std::cout << "PHTpcResiduals::Init - m_minPt: " << m_minPt << " GeV/c" << std::endl; // reset counters m_total_tracks = 0; @@ -215,8 +222,8 @@ bool PHTpcResiduals::checkTrack(SvtxTrack* track) const if(Verbosity() > 2) { std::cout << "PHTpcResiduals::checkTrack - pt: " << track->get_pt() << std::endl; } - if(track->get_pt() < 0.5) - return false; + if(track->get_pt() < m_minPt) + { return false; } // ignore tracks with too few mvtx, intt and micromegas hits const auto cluster_keys( get_cluster_keys( track ) ); diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 7acdfb4f00..b44f4958f6 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -46,27 +46,40 @@ class PHTpcResiduals : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - /// Option for setting distortion correction calculation limits + ///@name Option for setting distortion correction calculation limits + //@{ void setMaxTrackAlpha(float maxTAlpha) - { m_maxTAlpha = maxTAlpha;} + { m_maxTAlpha = maxTAlpha;} + void setMaxTrackBeta(float maxTBeta) - { m_maxTBeta = maxTBeta; } + { m_maxTBeta = maxTBeta; } + void setMaxTrackResidualDrphi(float maxResidualDrphi) - { m_maxResidualDrphi = maxResidualDrphi;} + { m_maxResidualDrphi = maxResidualDrphi;} void setMaxTrackResidualDz(float maxResidualDz) - { m_maxResidualDz = maxResidualDz; } + { m_maxResidualDz = maxResidualDz; } + //@} + + /// track min pT + void setMinPt( double value ) + { m_minPt = value; } + + /// Grid dimensions void setGridDimensions(const int phiBins, const int rBins, const int zBins); /// set to true to store evaluation histograms and ntuples - void setSavehistograms( bool value ) { m_savehistograms = value; } + void setSavehistograms( bool value ) + { m_savehistograms = value; } /// output file name for evaluation histograms - void setHistogramOutputfile(const std::string &outputfile) {m_histogramfilename = outputfile;} + void setHistogramOutputfile(const std::string &outputfile) + {m_histogramfilename = outputfile;} /// output file name for storing the space charge reconstruction matrices - void setOutputfile(const std::string &outputfile) {m_outputfile = outputfile;} + void setOutputfile(const std::string &outputfile) + {m_outputfile = outputfile;} /// require micromegas to be present when extrapolating tracks to the TPC void setUseMicromegas( bool value ) @@ -170,6 +183,10 @@ class PHTpcResiduals : public SubsysReco /// require micromegas to be present when extrapolating tracks to the TPC bool m_useMicromegas = true; + /// minimum pT required for track to be considered in residuals calculation (GeV/c) + double m_minPt = 0.5; + + /// output file std::string m_outputfile = "TpcSpaceChargeMatrices.root"; /// running track crossing id From d1514674e5dbd9fcafa9620418e698f21c56445a Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 11 Apr 2023 11:50:27 -0400 Subject: [PATCH 191/468] removed all evaluation code. It is now part of QAG4SimulationDistortions. --- offline/packages/tpccalib/PHTpcResiduals.cc | 243 ++++---------------- offline/packages/tpccalib/PHTpcResiduals.h | 61 +---- 2 files changed, 44 insertions(+), 260 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 64d501917d..776fa7c416 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -106,7 +106,6 @@ PHTpcResiduals::PHTpcResiduals(const std::string &name) //___________________________________________________________________________________ int PHTpcResiduals::Init(PHCompositeNode */*topNode*/) { - if( m_savehistograms ) makeHistograms(); // configuration printout std::cout << "PHTpcResiduals::Init - m_maxTAlpha: " << m_maxTAlpha << std::endl; @@ -158,22 +157,6 @@ int PHTpcResiduals::End(PHCompositeNode */*topNode*/) outputfile->cd(); m_matrix_container->Write( "TpcSpaceChargeMatrixContainer" ); } - - // save histograms - if( m_savehistograms && m_histogramfile ) - { - m_histogramfile->cd(); - for( const auto o:std::initializer_list({ h_rphiResid, h_zResid, h_etaResidLayer, h_zResidLayer, h_etaResid, h_index, h_alpha, h_beta, h_deltarphi_layer, h_deltaz_layer, residTup }) ) - { if( o ) o->Write(); } - - // also write histograms from vectors - for( const auto& [cell,h]:h_drphi ) { if(h) h->Write(); } - for( const auto& [cell,h]:h_dz ) { if(h) h->Write(); } - for( const auto& [cell,h]:h_drphi_alpha ) { if(h) h->Write(); } - for( const auto& [cell,h]:h_dz_beta ) { if(h) h->Write(); } - - m_histogramfile->Close(); - } // print counters std::cout @@ -280,12 +263,9 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) m_crossing = track->get_crossing(); assert( m_crossing != SHRT_MAX ); - for( const auto& key:get_cluster_keys( track ) ) + for( const auto& cluskey:get_cluster_keys( track ) ) { - // assign to static cluskey - cluskey = key; - // increment counter ++m_total_clusters; @@ -330,16 +310,18 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << std::endl; } - addTrackState( track, key, pathLength, trackStateParams ); + addTrackState( track, cluskey, pathLength, trackStateParams ); // calculate residuals with respect to cluster // Get all the relevant information for residual calculation const auto globClusPos = getGlobalPosition(cluskey, cluster, m_crossing); - clusR = get_r(globClusPos(0),globClusPos(1)); - clusPhi = std::atan2(globClusPos(1), globClusPos(0)); - clusZ = globClusPos(2); + const double clusR = get_r(globClusPos(0),globClusPos(1)); + const double clusPhi = std::atan2(globClusPos(1), globClusPos(0)); + const double clusZ = globClusPos(2); // cluster errors + double clusRPhiErr = 0; + double clusZErr = 0; if( m_cluster_version == 4 ) { const auto errors_square = m_cluster_error_parametrization.get_cluster_error( track->get_tpc_seed(), cluster, clusR, cluskey ); @@ -379,58 +361,46 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) const auto globalStateMom = trackStateParams.momentum(); const auto globalStateCov = *trackStateParams.covariance(); - stateRPhiErr = std::sqrt(globalStateCov(Acts::eBoundLoc0, Acts::eBoundLoc0))/Acts::UnitConstants::cm; - stateZErr = sqrt(globalStateCov(Acts::eBoundLoc1, Acts::eBoundLoc1))/Acts::UnitConstants::cm; - - stateZ = globalStatePos.z()/Acts::UnitConstants::cm; + const double trackRPhiErr = std::sqrt(globalStateCov(Acts::eBoundLoc0, Acts::eBoundLoc0))/Acts::UnitConstants::cm; + const double trackZErr = sqrt(globalStateCov(Acts::eBoundLoc1, Acts::eBoundLoc1))/Acts::UnitConstants::cm; - const auto globStateX = globalStatePos.x()/Acts::UnitConstants::cm; - const auto globStateY = globalStatePos.y()/Acts::UnitConstants::cm; - const auto globStateZ = stateZ; + const double globStateX = globalStatePos.x()/Acts::UnitConstants::cm; + const double globStateY = globalStatePos.y()/Acts::UnitConstants::cm; + const double globStateZ = globalStatePos.z()/Acts::UnitConstants::cm; - stateR = std::sqrt(square(globStateX) + square(globStateY)); + const double trackR = std::sqrt(square(globStateX) + square(globStateY)); - const auto dr = clusR - stateR; - const auto trackDrDt = (globStateX * globalStateMom(0) + globStateY * globalStateMom(1)) / stateR; - const auto trackDxDr = globalStateMom(0) / trackDrDt; - const auto trackDyDr = globalStateMom(1) / trackDrDt; - const auto trackDzDr = globalStateMom(2) / trackDrDt; + const double dr = clusR - trackR; + const double trackDrDt = (globStateX * globalStateMom(0) + globStateY * globalStateMom(1)) / trackR; + const double trackDxDr = globalStateMom(0) / trackDrDt; + const double trackDyDr = globalStateMom(1) / trackDrDt; + const double trackDzDr = globalStateMom(2) / trackDrDt; - const auto trackX = globStateX + dr * trackDxDr; - const auto trackY = globStateY + dr * trackDyDr; - const auto trackZ = globStateZ + dr * trackDzDr; + const double trackX = globStateX + dr * trackDxDr; + const double trackY = globStateY + dr * trackDyDr; + const double trackZ = globStateZ + dr * trackDzDr; + const double trackPhi = std::atan2(trackY, trackX); if(Verbosity() > 2) { std::cout << "PHTpcResiduals::processTrack -" - << " stateR: " << stateR + << " trackR: " << trackR << " dr: " << dr << " trackDrDt: " << trackDrDt << " trackDxDr: " << trackDxDr << " trackDyDr: " << trackDyDr << " trackDzDr: " << trackDzDr + << " trackPhi: " << trackPhi << "+/-" << trackRPhiErr << " track position: (" << trackX << ", " << trackY << ", " << trackZ << ")" << std::endl; } - - statePhi = std::atan2(trackY, trackX); - stateZ = trackZ; - - if(Verbosity() > 3) - { - std::cout << "PHTpcResiduals::processTrack -" - << " stateR: " << stateR - << " statePhi: " << statePhi << "+/-" << stateRPhiErr - << " stateZ: " << stateZ << "+/-" << stateZErr - << std::endl; - } - - const auto erp = square(clusRPhiErr) + square(stateRPhiErr); - const auto ez = square(clusZErr) + square(stateZErr); + + const double erp = square(clusRPhiErr) + square(trackRPhiErr); + const double ez = square(clusZErr) + square(trackZErr); // Calculate residuals - drphi = clusR * deltaPhi(clusPhi - statePhi); - dz = clusZ - stateZ; + const double drphi = clusR * deltaPhi(clusPhi - trackPhi); + const double dz = clusZ - trackZ; if(Verbosity() > 3) { @@ -439,19 +409,13 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << " dz: " << dz << std::endl; } + + const double trackPPhi = -trackStateParams.momentum()(0) * std::sin(trackPhi) + trackStateParams.momentum()(1) * std::cos(trackPhi); + const double trackPR = trackStateParams.momentum()(0) * std::cos(trackPhi) + trackStateParams.momentum()(1) * std::sin(trackPhi); + const double trackPZ = trackStateParams.momentum()(2); - const auto trackEta = std::atanh(trackStateParams.momentum().z() / trackStateParams.absoluteMomentum()); - const auto clusEta = std::atanh(clusZ / std::sqrt( - square(globClusPos(0)) + - square(globClusPos(1)) + - square(globClusPos(2)))); - - const auto trackPPhi = -trackStateParams.momentum()(0) * std::sin(statePhi) + trackStateParams.momentum()(1) * std::cos(statePhi); - const auto trackPR = trackStateParams.momentum()(0) * std::cos(statePhi) + trackStateParams.momentum()(1) * std::sin(statePhi); - const auto trackPZ = trackStateParams.momentum()(2); - - const auto trackAlpha = -trackPPhi / trackPR; - const auto trackBeta = -trackPZ / trackPR; + const double trackAlpha = -trackPPhi / trackPR; + const double trackBeta = -trackPZ / trackPR; if(Verbosity() > 3) { @@ -464,10 +428,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << " trackBeta: " << trackBeta << std::endl; } - - tanBeta = trackBeta; - tanAlpha = trackAlpha; - + // get cell index const auto index = getCell(globClusPos); if(Verbosity() > 3) @@ -477,43 +438,20 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) if(Verbosity() > 3) { - std::cout << "PHTpcResiduals::processTrack - layer: " << (int) TrkrDefs::getLayer(key) << std::endl; + std::cout << "PHTpcResiduals::processTrack - layer: " << (int) TrkrDefs::getLayer(cluskey) << std::endl; std::cout << "PHTpcResiduals::processTrack -" << " cluster: (" << clusR << ", " << clusR*clusPhi << ", " << clusZ << ")" << " (" << clusRPhiErr << ", " << clusZErr << ")" << std::endl; std::cout << "PHTpcResiduals::processTrack -" - << " track: (" << stateR << ", " << clusR*statePhi << ", " << stateZ << ")" - << " (" << tanAlpha << ", " << tanBeta << ")" - << " (" << stateRPhiErr << ", " << stateZErr << ")" + << " track: (" << trackR << ", " << clusR*trackPhi << ", " << trackZ << ")" + << " (" << trackAlpha << ", " << trackBeta << ")" + << " (" << trackRPhiErr << ", " << trackZErr << ")" << std::endl; std::cout << std::endl; } - if( m_savehistograms ) - { - h_index->Fill(index); - h_alpha->Fill(tanAlpha, drphi); - h_beta->Fill(tanBeta, dz); - h_rphiResid->Fill(clusR , drphi); - h_zResid->Fill(stateZ , dz); - h_etaResid->Fill(trackEta, clusEta - trackEta); - h_zResidLayer->Fill(clusR , dz); - h_etaResidLayer->Fill(clusR , clusEta - trackEta); - - const auto layer = TrkrDefs::getLayer(key); - h_deltarphi_layer->Fill( layer, drphi ); - h_deltaz_layer->Fill( layer, dz ); - - { const auto iter = h_drphi.find( index ); if( iter != h_drphi.end() ) iter->second->Fill( drphi ); } - { const auto iter = h_drphi_alpha.find( index ); if( iter != h_drphi_alpha.end() ) iter->second->Fill( tanAlpha, drphi ); } - { const auto iter = h_dz.find( index ); if( iter != h_dz.end() ) iter->second->Fill( dz ); } - { const auto iter = h_dz_beta.find( index ); if( iter != h_dz_beta.end() ) iter->second->Fill( tanBeta, dz ); } - - residTup->Fill(); - } - // check track angles and residuals agains cuts if(std::abs(trackAlpha) > m_maxTAlpha || std::abs(drphi) > m_maxResidualDrphi) { continue; } @@ -716,107 +654,6 @@ Acts::Vector3 PHTpcResiduals::getGlobalPosition( TrkrDefs::cluskey key, TrkrClus return globalPosition; } -//_______________________________________________________________________________ -void PHTpcResiduals::makeHistograms() -{ - - m_histogramfile.reset( new TFile(m_histogramfilename.c_str(), "RECREATE") ); - m_histogramfile->cd(); - - const auto total_bins = m_matrix_container->get_grid_size(); - h_beta = new TH2F("betadz",";tan#beta; #Deltaz [cm]",100,-0.5,0.5,100,-0.5,0.5); - h_alpha = new TH2F("alphardphi",";tan#alpha; r#Delta#phi [cm]", 100,-0.5,0.5,100,-0.5,0.5); - h_index = new TH1F("index",";index",total_bins, 0, total_bins); - h_rphiResid = new TH2F("rphiResid", ";r [cm]; #Deltar#phi [cm]", 60, 20, 80, 500, -2, 2); - h_zResid = new TH2F("zResid", ";z [cm]; #Deltaz [cm]", 200, -100, 100, 1000, -2, 2); - h_etaResid = new TH2F("etaResid", ";#eta;#Delta#eta", 20, -1, 1, 500, -0.2, 0.2); - h_etaResidLayer = new TH2F("etaResidLayer", ";r [cm]; #Delta#eta", 60, 20, 80, 500, -0.2, 0.2); - h_zResidLayer = new TH2F("zResidLayer", ";r [cm]; #Deltaz [cm]", 60, 20, 80, 1000, -2, 2); - h_deltarphi_layer = new TH2F( "deltarphi_layer", ";layer; r.#Delta#phi_{track-cluster} (cm)", 57, 0, 57, 500, -2, 2 ); - h_deltaz_layer = new TH2F( "deltaz_layer", ";layer; #Deltaz_{track-cluster} (cm)", 57, 0, 57, 100, -2, 2 ); - - { - - // get grid dimensions from matrix container - int phibins = 0; - int rbins = 0; - int zbins = 0; - m_matrix_container->get_grid_dimensions( phibins, rbins, zbins ); - - // get bins corresponding to selected angles - std::set phibin_rec; - std::transform( phi_rec.begin(), phi_rec.end(), std::inserter( phibin_rec, phibin_rec.end() ), [&]( const float& phi ) { return phibins*(phi-m_phiMin)/(m_phiMax-m_phiMin); } ); - - std::set zbin_rec; - std::transform( z_rec.begin(), z_rec.end(), std::inserter( zbin_rec, zbin_rec.end() ), [&]( const float& z ) { return zbins*(z-m_zMin)/(m_zMax-m_zMin); } ); - - // keep track of all cell ids that match selected histograms - for( int iphi = 0; iphi < phibins; ++iphi ) - for( int ir = 0; ir < rbins; ++ir ) - for( int iz = 0; iz < zbins; ++iz ) - { - - if( phibin_rec.find( iphi ) == phibin_rec.end() || zbin_rec.find( iz ) == zbin_rec.end() ) continue; - const auto icell = m_matrix_container->get_cell_index( iphi, ir, iz ); - - { - // rphi residuals - const auto hname = Form( "residual_drphi_p%i_r%i_z%i", iphi, ir, iz ); - auto h = new TH1F( hname, hname, 100, -m_maxResidualDrphi, +m_maxResidualDrphi ); - h->GetXaxis()->SetTitle( "r.#Delta#phi_{cluster-track} (cm)" ); - h_drphi.insert( std::make_pair( icell, h ) ); - } - - { - // 2D histograms - const auto hname = Form( "residual_2d_drphi_p%i_r%i_z%i", iphi, ir, iz ); - auto h = new TH2F( hname, hname, 100, -m_maxTAlpha, m_maxTAlpha, 100, -m_maxResidualDrphi, +m_maxResidualDrphi ); - h->GetXaxis()->SetTitle( "tan#alpha" ); - h->GetYaxis()->SetTitle( "r.#Delta#phi_{cluster-track} (cm)" ); - h_drphi_alpha.insert( std::make_pair( icell, h ) ); - } - - { - // z residuals - const auto hname = Form( "residual_dz_p%i_r%i_z%i", iphi, ir, iz ); - auto h = new TH1F( hname, hname, 100, -m_maxResidualDz, +m_maxResidualDz ); - h->GetXaxis()->SetTitle( "#Deltaz_{cluster-track} (cm)" ); - h_dz.insert( std::make_pair( icell, h ) ); - } - - { - // 2D histograms - static constexpr double maxTBeta = 0.5; - const auto hname = Form( "residual_2d_dz_p%i_r%i_z%i", iphi, ir, iz ); - auto h = new TH2F( hname, hname, 100, -maxTBeta, maxTBeta, 100, -m_maxResidualDz, +m_maxResidualDz ); - h->GetXaxis()->SetTitle( "tan#beta" ); - h->GetYaxis()->SetTitle( "#Deltaz_{cluster-track} (cm)" ); - h_dz_beta.insert( std::make_pair( icell, h ) ); - } - } - - } - - residTup = new TTree("residTree","tpc residual info"); - residTup->Branch("tanAlpha",&tanAlpha,"tanAlpha/D"); - residTup->Branch("tanBeta",&tanBeta,"tanBeta/D"); - residTup->Branch("drphi",&drphi,"drphi/D"); - residTup->Branch("dz",&dz,"dz/D"); - residTup->Branch("clusR",&clusR,"clusR/D"); - residTup->Branch("clusPhi",&clusPhi,"clusPhi/D"); - residTup->Branch("clusZ",&clusZ,"clusZ/D"); - residTup->Branch("statePhi",&statePhi,"statePhi/D"); - residTup->Branch("stateZ",&stateZ,"stateZ/D"); - residTup->Branch("stateR",&stateR,"stateR/D"); - residTup->Branch("stateRPhiErr",&stateRPhiErr,"stateRPhiErr/D"); - residTup->Branch("stateZErr",&stateZErr,"stateZErr/D"); - residTup->Branch("clusRPhiErr",&clusRPhiErr,"clusRPhiErr/D"); - residTup->Branch("clusZErr",&clusZErr,"clusZErr/D"); - residTup->Branch("cluskey",&cluskey,"cluskey/l"); - residTup->Branch("event",&m_event,"event/I"); - -} - void PHTpcResiduals::setGridDimensions(const int phiBins, const int rBins, const int zBins) { m_matrix_container->set_grid_dimensions( phiBins, rBins, zBins ); } diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index b44f4958f6..2c5ff6513d 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -70,12 +70,10 @@ class PHTpcResiduals : public SubsysReco void setGridDimensions(const int phiBins, const int rBins, const int zBins); /// set to true to store evaluation histograms and ntuples - void setSavehistograms( bool value ) - { m_savehistograms = value; } + void setSavehistograms( bool ) {} /// output file name for evaluation histograms - void setHistogramOutputfile(const std::string &outputfile) - {m_histogramfilename = outputfile;} + void setHistogramOutputfile(const std::string&) {} /// output file name for storing the space charge reconstruction matrices void setOutputfile(const std::string &outputfile) @@ -125,10 +123,8 @@ class PHTpcResiduals : public SubsysReco /// Gets distortion cell for identifying bins in TPC int getCell(const Acts::Vector3& loc); - /// create histograms - void makeHistograms(); - - Acts::BoundTrackParameters makeTrackParams(SvtxTrack* track) const; + //! create ACTS track parameters from Svtx track + Acts::BoundTrackParameters makeTrackParams(SvtxTrack* ) const; /// actis transformation ActsTransformations m_transformer; @@ -201,55 +197,6 @@ class PHTpcResiduals : public SubsysReco int m_accepted_clusters = 0; //@} - /// Output root histograms - bool m_savehistograms = false; - TH2 *h_rphiResid = nullptr; - TH2 *h_zResid = nullptr; - TH2 *h_etaResidLayer = nullptr; - TH2 *h_zResidLayer = nullptr; - TH2 *h_etaResid = nullptr; - TH1 *h_index = nullptr; - TH2 *h_alpha = nullptr; - TH2 *h_beta = nullptr; - - //@name additional histograms that copy the per-cell data used to extract the distortions - //@{ - using TH1_map_t = std::map; - using TH2_map_t = std::map; - - TH1_map_t h_drphi; - TH1_map_t h_dz; - TH2_map_t h_drphi_alpha; - TH2_map_t h_dz_beta; - //@} - - TTree *residTup = nullptr; - - /// delta rphi vs layer number - TH2 *h_deltarphi_layer = nullptr; - - /// delta z vs layer number - TH2 *h_deltaz_layer = nullptr; - - std::string m_histogramfilename = "PHTpcResiduals.root"; - std::unique_ptr m_histogramfile = nullptr; - - /// For diagnostics - double tanAlpha = 0; - double tanBeta = 0; - double drphi = 0; - double dz = 0; - double clusR = 0; - double clusPhi = 0; - double clusZ = 0; - double statePhi = 0; - double stateZ = 0; - double stateRPhiErr = 0; - double stateZErr = 0; - double clusRPhiErr = 0; - double clusZErr = 0; - double stateR = 0; - TrkrDefs::cluskey cluskey = 0; }; #endif From 3174301cb40663f9fbb43e1167ce876ca9018d92 Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 11 Apr 2023 13:27:30 -0400 Subject: [PATCH 192/468] Updating TPCHitTrackDisplay to output multiple json files if multiple events are run --- .../TPCHitTrackDisplay/TPCHitTrackDisplay.cc | 12 +++++++++--- .../packages/TPCHitTrackDisplay/TPCHitTrackDisplay.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.cc b/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.cc index b8c90e6734..293075db88 100644 --- a/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.cc +++ b/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.cc @@ -60,10 +60,10 @@ using namespace std; TPCHitTrackDisplay::TPCHitTrackDisplay(const string &name) : SubsysReco(name) - , m_cut_ADC(200.0) + , m_cut_ADC(75.0) , m_trackless_clusters(true) , _pdgcode(0) - , outfile1((name + ".json").c_str(), std::ios::app) + , _fileName(name) { //initialize _event = 0; @@ -215,6 +215,10 @@ return; // write json file from simulation data for silicon and tpc clusters/tracks void TPCHitTrackDisplay::SimulationOut(PHCompositeNode *topNode) { + stringstream fname; + fname << _fileName << "event" << _event << ".json"; + fstream outfile1(fname.str(), ios_base::out); + cout << _event << endl; TrkrClusterContainer *clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); @@ -443,7 +447,9 @@ void TPCHitTrackDisplay::SimulationOut(PHCompositeNode *topNode) outfile1 << "}" << endl; outfile1 << "}" << endl; -return; + usedClusters.clear(); + + return; } diff --git a/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.h b/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.h index 02706b2bb7..3e9c31bcc6 100644 --- a/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.h +++ b/offline/packages/TPCHitTrackDisplay/TPCHitTrackDisplay.h @@ -63,7 +63,7 @@ class TPCHitTrackDisplay: public SubsysReco //Event counter int _event; int _pdgcode; - std::ofstream outfile1; + std::string _fileName; //bool isRawData; From 5d832c6a3450a8ae7e87286af90e69d7ab7ecea3 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 13:49:46 -0400 Subject: [PATCH 193/468] fix ambiguity of SvtxHitEval --- .../g4simulation/g4eval/SvtxEvaluator.cc | 8 +- simulation/g4simulation/g4eval/SvtxHitEval.cc | 847 +++++------------- simulation/g4simulation/g4eval/SvtxHitEval.h | 49 +- 3 files changed, 257 insertions(+), 647 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 88fe7f1133..30126bcbd8 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1670,7 +1670,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) TrkrDefs::hitkey hit_key = hitset->getHitKeyfromLocalBin(local_pad, local_tbin); - PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); + PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hitset_key, hit_key); PHG4Particle* g4particle = trutheval->get_particle(g4hit); float event = _ievent; float hitID = hit_key; @@ -1773,7 +1773,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) if (g4particle) { - efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); + efromtruth = hiteval->get_energy_contribution(hitset_key, hit_key, g4particle); } float hit_data[] = { @@ -1839,7 +1839,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) { TrkrDefs::hitkey hit_key = hitr->first; TrkrHit* hit = hitr->second; - PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hit_key); + PHG4Hit* g4hit = hiteval->max_truth_hit_by_energy(hitset_key, hit_key); PHG4Particle* g4particle = trutheval->get_particle(g4hit); float event = _ievent; float hitID = hit_key; @@ -1942,7 +1942,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) if (g4particle) { - efromtruth = hiteval->get_energy_contribution(hit_key, g4particle); + efromtruth = hiteval->get_energy_contribution(hitset_key, hit_key, g4particle); } float hit_data[] = { diff --git a/simulation/g4simulation/g4eval/SvtxHitEval.cc b/simulation/g4simulation/g4eval/SvtxHitEval.cc index bd9e56f589..afd82b4e6b 100644 --- a/simulation/g4simulation/g4eval/SvtxHitEval.cc +++ b/simulation/g4simulation/g4eval/SvtxHitEval.cc @@ -1,9 +1,9 @@ #include "SvtxHitEval.h" +#include #include #include #include -#include #include #include @@ -18,7 +18,7 @@ #include #include #include -#include // for operator<<, endl, basic_... +#include // for operator<<, endl, basic_... #include #include @@ -28,9 +28,9 @@ using namespace std; SvtxHitEval::SvtxHitEval(PHCompositeNode* topNode) : _trutheval(topNode) - // , _g4cells_svtx(nullptr) - // , _g4cells_tracker(nullptr) - //, _g4cells_maps(nullptr) + // , _g4cells_svtx(nullptr) + // , _g4cells_tracker(nullptr) + //, _g4cells_maps(nullptr) , _g4hits_tpc(nullptr) , _g4hits_intt(nullptr) , _g4hits_mvtx(nullptr) @@ -81,54 +81,12 @@ void SvtxHitEval::next_event(PHCompositeNode* topNode) get_node_pointers(topNode); } -/* -PHG4Cell* SvtxHitEval::get_cell(SvtxHit* hit) +std::set SvtxHitEval::all_truth_hits(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key) { if (!has_node_pointers()) { ++_errors; - cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } - - if (_strict) - { - assert(hit); - } - else if (!hit) - { - ++_errors; - cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } - - // hop from reco hit to g4cell - PHG4Cell* cell = nullptr; - if (_g4cells_svtx) cell = _g4cells_svtx->findCell(hit->get_cellid()); - if (!cell && _g4cells_tracker) cell = _g4cells_tracker->findCell(hit->get_cellid()); - if (!cell && _g4cells_maps) cell = _g4cells_maps->findCell(hit->get_cellid()); - - // only noise hits (cellid left at default value) should not trace - if ((_strict) && (hit->get_cellid() != 0xFFFFFFFF)) - { - assert(cell); - } - else if (!cell) - { - ++_errors; - cout << PHWHERE << " nerr: " << _errors << endl; - } - - return cell; -} -*/ - -std::set SvtxHitEval::all_truth_hits(TrkrDefs::hitkey hit_key) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return std::set(); } @@ -139,213 +97,69 @@ std::set SvtxHitEval::all_truth_hits(TrkrDefs::hitkey hit_key) else if (!hit_key) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return std::set(); } - if (_do_cache) - { - std::map >::iterator iter = - _cache_all_truth_hits.find(hit_key); - if (iter != _cache_all_truth_hits.end()) - { - return iter->second; - } - } - - std::set truth_hits; - - /* - // hop from reco hit to g4cell - PHG4Cell* cell = nullptr; - if (_g4cells_svtx) cell = _g4cells_svtx->findCell(hit->get_cellid()); - if (!cell && _g4cells_tracker) cell = _g4cells_tracker->findCell(hit->get_cellid()); - if (!cell && _g4cells_maps) cell = _g4cells_maps->findCell(hit->get_cellid()); - - // only noise hits (cellid left at default value) should not trace - if ((_strict) && (hit->get_cellid() != 0xFFFFFFFF)) - assert(cell); - else if (!cell) - { - ++_errors; - cout << PHWHERE << " nerr: " << _errors << endl; - return truth_hits; - } - - //cout << "Eval: hitid " << hit->get_id() << " cellid " << cell->get_cellid() << endl; - // loop over all the g4hits in this cell - for (PHG4Cell::EdepConstIterator g4iter = cell->get_g4hits().first; - g4iter != cell->get_g4hits().second; - ++g4iter) - { - //cout << " Looking for hit " << g4iter->first << " in layer " << cell->get_layer() << " with edep " << g4iter->second << endl; - PHG4Hit* g4hit = nullptr; - if (_g4hits_svtx) g4hit = _g4hits_svtx->findHit(g4iter->first); - if (!g4hit && _g4hits_tracker) g4hit = _g4hits_tracker->findHit(g4iter->first); - if (!g4hit && _g4hits_maps) g4hit = _g4hits_maps->findHit(g4iter->first); - if (!g4hit) cout << " Failed to find g4hit " << g4iter->first << " with edep " << g4iter->second << endl; - if (_strict) - assert(g4hit); - else if (!g4hit) - { - ++_errors; - cout << PHWHERE << " nerr: " << _errors << endl; - continue; - } - */ - - // get all of the g4hits for this hit_key - // have to start with all hitsets, unfortunately - for (const auto& [trkrID, _hitmap] : _hitmaps) - { - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) - { - TrkrDefs::hitsetkey hitset_key = iter->first; - unsigned int trkrid = TrkrDefs::getTrkrId(hitset_key); - TrkrHitSet* hitset = iter->second; - - // does this hitset contain our hitkey? - TrkrHit* hit = nullptr; - hit = hitset->getHit(hit_key); - if (hit) - { - // get g4hits for this hit - - std::multimap > temp_map; - _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only - for (std::multimap >::iterator htiter = temp_map.begin(); - htiter != temp_map.end(); ++htiter) - { - // extract the g4 hit key here and add the g4hit to the set - PHG4HitDefs::keytype g4hitkey = htiter->second.second; - // cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; - PHG4Hit* g4hit = nullptr; - switch (trkrid) - { - case TrkrDefs::tpcId: - g4hit = _g4hits_tpc->findHit(g4hitkey); - break; - case TrkrDefs::inttId: - g4hit = _g4hits_intt->findHit(g4hitkey); - break; - case TrkrDefs::mvtxId: - g4hit = _g4hits_mvtx->findHit(g4hitkey); - break; - case TrkrDefs::micromegasId: - g4hit = _g4hits_mms->findHit(g4hitkey); - break; - default: - break; - } - // fill output set - if (g4hit) truth_hits.insert(g4hit); - } - } - } - } - - if (_do_cache) _cache_all_truth_hits.insert(make_pair(hit_key, truth_hits)); - - return truth_hits; -} - -std::set SvtxHitEval::all_truth_hits(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_strict) - { - assert(hit_key); - } - else if (!hit_key) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } + const std::pair key(hitset_key, hit_key); if (_do_cache) { - std::map >::iterator iter = - _cache_all_truth_hits.find(hit_key); + const auto & iter = + _cache_all_truth_hits.find(key); if (iter != _cache_all_truth_hits.end()) { return iter->second; } } + const uint8_t trkrid = TrkrDefs::getTrkrId(hitset_key); std::set truth_hits; - if (_hitmaps.find(trkrid) != _hitmaps.end()) - { - TrkrHitSetContainer* _hitmap = _hitmaps[trkrid]; - assert(_hitmap); - - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(trkrid); + assert(_hit_truth_map); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; iter != all_hitsets.second; ++iter) + std::multimap > temp_map; + _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only + for (std::multimap >::iterator htiter = temp_map.begin(); + htiter != temp_map.end(); ++htiter) + { + // extract the g4 hit key here and add the g4hit to the set + PHG4HitDefs::keytype g4hitkey = htiter->second.second; + // cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; + PHG4Hit* g4hit = nullptr; + switch (trkrid) { - TrkrDefs::hitsetkey hitset_key = iter->first; - TrkrHitSet* hitset = iter->second; - - // does this hitset contain our hitkey? - TrkrHit* hit = nullptr; - hit = hitset->getHit(hit_key); - if (hit) - { - // get g4hits for this hit - - std::multimap > temp_map; - _hit_truth_map->getG4Hits(hitset_key, hit_key, temp_map); // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only - for (std::multimap >::iterator htiter = temp_map.begin(); - htiter != temp_map.end(); ++htiter) - { - // extract the g4 hit key here and add the g4hit to the set - PHG4HitDefs::keytype g4hitkey = htiter->second.second; - // cout << " hitkey " << hitkey << " g4hitkey " << g4hitkey << endl; - PHG4Hit* g4hit = nullptr; - switch (trkrid) - { - case TrkrDefs::tpcId: - g4hit = _g4hits_tpc->findHit(g4hitkey); - break; - case TrkrDefs::inttId: - g4hit = _g4hits_intt->findHit(g4hitkey); - break; - case TrkrDefs::mvtxId: - g4hit = _g4hits_mvtx->findHit(g4hitkey); - break; - case TrkrDefs::micromegasId: - g4hit = _g4hits_mms->findHit(g4hitkey); - break; - default: - break; - } - // fill output set - if (g4hit) truth_hits.insert(g4hit); - } - } + case TrkrDefs::tpcId: + g4hit = _g4hits_tpc->findHit(g4hitkey); + break; + case TrkrDefs::inttId: + g4hit = _g4hits_intt->findHit(g4hitkey); + break; + case TrkrDefs::mvtxId: + g4hit = _g4hits_mvtx->findHit(g4hitkey); + break; + case TrkrDefs::micromegasId: + g4hit = _g4hits_mms->findHit(g4hitkey); + break; + default: + break; } + // fill output set + if (g4hit) truth_hits.insert(g4hit); } - if (_do_cache) _cache_all_truth_hits.insert(make_pair(hit_key, truth_hits)); + if (_do_cache) _cache_all_truth_hits.insert(make_pair(key, truth_hits)); return truth_hits; } -PHG4Hit* SvtxHitEval::max_truth_hit_by_energy(TrkrDefs::hitkey hit_key) +PHG4Hit* SvtxHitEval::max_truth_hit_by_energy(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key) { if (!has_node_pointers()) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return nullptr; } @@ -356,71 +170,23 @@ PHG4Hit* SvtxHitEval::max_truth_hit_by_energy(TrkrDefs::hitkey hit_key) else if (!hit_key) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } - - if (_do_cache) - { - std::map::iterator iter = - _cache_max_truth_hit_by_energy.find(hit_key); - if (iter != _cache_max_truth_hit_by_energy.end()) - { - return iter->second; - } - } - - std::set hits = all_truth_hits(hit_key); - PHG4Hit* max_hit = nullptr; - float max_e = FLT_MAX * -1.0; - for (std::set::iterator iter = hits.begin(); - iter != hits.end(); - ++iter) - { - PHG4Hit* hit = *iter; - if (hit->get_edep() > max_e) - { - max_e = hit->get_edep(); - max_hit = hit; - } - } - - if (_do_cache) _cache_max_truth_hit_by_energy.insert(make_pair(hit_key, max_hit)); - - return max_hit; -} - -PHG4Hit* SvtxHitEval::max_truth_hit_by_energy(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return nullptr; } - if (_strict) - { - assert(hit_key); - } - else if (!hit_key) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } + const std::pair key(hitset_key, hit_key); if (_do_cache) { - std::map::iterator iter = - _cache_max_truth_hit_by_energy.find(hit_key); + const auto & iter = + _cache_max_truth_hit_by_energy.find(key); if (iter != _cache_max_truth_hit_by_energy.end()) { return iter->second; } } - std::set hits = all_truth_hits(hit_key, trkrid); + std::set hits = all_truth_hits(hitset_key, hit_key); PHG4Hit* max_hit = nullptr; float max_e = FLT_MAX * -1.0; for (std::set::iterator iter = hits.begin(); @@ -435,17 +201,17 @@ PHG4Hit* SvtxHitEval::max_truth_hit_by_energy(TrkrDefs::hitkey hit_key, const Tr } } - if (_do_cache) _cache_max_truth_hit_by_energy.insert(make_pair(hit_key, max_hit)); + if (_do_cache) _cache_max_truth_hit_by_energy.insert(make_pair(key, max_hit)); return max_hit; } -std::set SvtxHitEval::all_truth_particles(TrkrDefs::hitkey hit_key) +std::set SvtxHitEval::all_truth_particles(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key) { if (!has_node_pointers()) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return std::set(); } @@ -456,72 +222,16 @@ std::set SvtxHitEval::all_truth_particles(TrkrDefs::hitkey hit_ke else if (!hit_key) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return std::set(); } - if (_do_cache) - { - std::map >::iterator iter = - _cache_all_truth_particles.find(hit_key); - if (iter != _cache_all_truth_particles.end()) - { - return iter->second; - } - } - - std::set truth_particles; - - std::set g4hits = all_truth_hits(hit_key); - - for (std::set::iterator iter = g4hits.begin(); - iter != g4hits.end(); - ++iter) - { - PHG4Hit* g4hit = *iter; - PHG4Particle* particle = get_truth_eval()->get_particle(g4hit); - - if (_strict) - assert(particle); - else if (!particle) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - continue; - } - - truth_particles.insert(particle); - } - - if (_do_cache) _cache_all_truth_particles.insert(make_pair(hit_key, truth_particles)); - - return truth_particles; -} - -std::set SvtxHitEval::all_truth_particles(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_strict) - { - assert(hit_key); - } - else if (!hit_key) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } + const std::pair key(hitset_key, hit_key); if (_do_cache) { - std::map >::iterator iter = - _cache_all_truth_particles.find(hit_key); + const auto & iter = + _cache_all_truth_particles.find(key); if (iter != _cache_all_truth_particles.end()) { return iter->second; @@ -530,7 +240,7 @@ std::set SvtxHitEval::all_truth_particles(TrkrDefs::hitkey hit_ke std::set truth_particles; - std::set g4hits = all_truth_hits(hit_key, trkrid); + std::set g4hits = all_truth_hits(hitset_key, hit_key); for (std::set::iterator iter = g4hits.begin(); iter != g4hits.end(); @@ -544,77 +254,24 @@ std::set SvtxHitEval::all_truth_particles(TrkrDefs::hitkey hit_ke else if (!particle) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; continue; } truth_particles.insert(particle); } - if (_do_cache) _cache_all_truth_particles.insert(make_pair(hit_key, truth_particles)); + if (_do_cache) _cache_all_truth_particles.insert(make_pair(key, truth_particles)); return truth_particles; } -PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(TrkrDefs::hitkey hit_key) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } - - if (_strict) - { - assert(hit_key); - } - else if (!hit_key) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return nullptr; - } - - if (_do_cache) - { - std::map::iterator iter = - _cache_max_truth_particle_by_energy.find(hit_key); - if (iter != _cache_max_truth_particle_by_energy.end()) - { - return iter->second; - } - } - - // loop over all particles associated with this hit and - // get the energy contribution for each one, record the max - PHG4Particle* max_particle = nullptr; - float max_e = FLT_MAX * -1.0; - std::set particles = all_truth_particles(hit_key); - for (std::set::iterator iter = particles.begin(); - iter != particles.end(); - ++iter) - { - PHG4Particle* particle = *iter; - float e = get_energy_contribution(hit_key, particle); - if (e > max_e) - { - max_e = e; - max_particle = particle; - } - } - - if (_do_cache) _cache_max_truth_particle_by_energy.insert(make_pair(hit_key, max_particle)); - - return max_particle; -} - -PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid) +PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key) { if (!has_node_pointers()) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return nullptr; } @@ -625,14 +282,15 @@ PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(TrkrDefs::hitkey hit_key else if (!hit_key) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return nullptr; } + const std::pair key(hitset_key, hit_key); if (_do_cache) { - std::map::iterator iter = - _cache_max_truth_particle_by_energy.find(hit_key); + const auto & iter = + _cache_max_truth_particle_by_energy.find(key); if (iter != _cache_max_truth_particle_by_energy.end()) { return iter->second; @@ -643,13 +301,13 @@ PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(TrkrDefs::hitkey hit_key // get the energy contribution for each one, record the max PHG4Particle* max_particle = nullptr; float max_e = FLT_MAX * -1.0; - std::set particles = all_truth_particles(hit_key, trkrid); + std::set particles = all_truth_particles(hitset_key, hit_key); for (std::set::iterator iter = particles.begin(); iter != particles.end(); ++iter) { PHG4Particle* particle = *iter; - float e = get_energy_contribution(hit_key, particle); + float e = get_energy_contribution(hitset_key, hit_key, particle); if (e > max_e) { max_e = e; @@ -657,206 +315,157 @@ PHG4Particle* SvtxHitEval::max_truth_particle_by_energy(TrkrDefs::hitkey hit_key } } - if (_do_cache) _cache_max_truth_particle_by_energy.insert(make_pair(hit_key, max_particle)); + if (_do_cache) _cache_max_truth_particle_by_energy.insert(make_pair(key, max_particle)); return max_particle; } -std::set SvtxHitEval::all_hits_from(PHG4Particle* g4particle) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_strict) - { - assert(g4particle); - } - else if (!g4particle) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_do_cache) - { - std::map >::iterator iter = - _cache_all_hits_from_particle.find(g4particle); - if (iter != _cache_all_hits_from_particle.end()) - { - return iter->second; - } - } - - std::set hits; - - for (const auto& [trkrID, _hitmap] : _hitmaps) - { - // loop over all the hits - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) - { - TrkrHitSet::ConstRange range = iter->second->getHits(); - for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) - { - TrkrDefs::hitkey hit_key = hitr->first; - - // loop over all truth hits connected to this hit - std::set g4hits = all_truth_hits(hit_key, trkrID); - for (std::set::iterator jter = g4hits.begin(); - jter != g4hits.end(); - ++jter) - { - PHG4Hit* candidate = *jter; - PHG4Particle* particle = _truthinfo->GetParticle(candidate->get_trkid()); - if (g4particle->get_track_id() == particle->get_track_id()) - { - hits.insert(hit_key); - } - } - } - } - } - - if (_do_cache) _cache_all_hits_from_particle.insert(make_pair(g4particle, hits)); - - return hits; -} - -std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_strict) - { - assert(g4hit); - } - else if (!g4hit) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return std::set(); - } - - if (_do_cache) - { - std::map >::iterator iter = - _cache_all_hits_from_g4hit.find(g4hit); - if (iter != _cache_all_hits_from_g4hit.end()) - { - return iter->second; - } - } - - std::set hits; - - unsigned int hit_layer = g4hit->get_layer(); - - // loop over all the hits - for (const auto& [trkrID, _hitmap] : _hitmaps) - { - TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); - for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; - iter != all_hitsets.second; - ++iter) - { - TrkrHitSet::ConstRange range = iter->second->getHits(); - for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) - { - TrkrDefs::hitkey hit_key = hitr->first; - - if (TrkrDefs::getLayer(hit_key) != hit_layer) continue; - - // loop over all truth hits connected to this hit - std::set g4hits = all_truth_hits(hit_key); - for (std::set::iterator jter = g4hits.begin(); - jter != g4hits.end(); - ++jter) - { - PHG4Hit* candidate = *jter; - if (candidate->get_hit_id() == g4hit->get_hit_id()) - { - hits.insert(hit_key); - } - } - } - } - } - - if (_do_cache) _cache_all_hits_from_g4hit.insert(make_pair(g4hit, hits)); - - return hits; -} - - TrkrDefs::hitkey SvtxHitEval::best_hit_from(PHG4Hit* g4hit) -{ - if (!has_node_pointers()) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return 0; - } - - if (_strict) - { - assert(g4hit); - } - else if (!g4hit) - { - ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; - return 0; - } - - if (_do_cache) - { - std::map::iterator iter = - _cache_best_hit_from_g4hit.find(g4hit); - if (iter != _cache_best_hit_from_g4hit.end()) - { - return iter->second; - } - } - - TrkrDefs::hitkey best_hit = 0; - float best_energy = 0.0; - std::set hits = all_hits_from(g4hit); - for (std::set::iterator iter = hits.begin(); - iter != hits.end(); - ++iter) - { - TrkrDefs::hitkey hit_key = *iter; - float energy = get_energy_contribution(hit_key, g4hit); - if (energy > best_energy) - { - best_hit = hit_key; - best_energy = energy; - } - } - - if (_do_cache) _cache_best_hit_from_g4hit.insert(make_pair(g4hit, best_hit)); - - return best_hit; -} +//std::set > SvtxHitEval::all_hits_from(PHG4Particle* g4particle) +//{ +// if (!has_node_pointers()) +// { +// ++_errors; +// if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; +// return std::set >(); +// } +// +// if (_strict) +// { +// assert(g4particle); +// } +// else if (!g4particle) +// { +// ++_errors; +// if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; +// return std::set >(); +// } +// +// if (_do_cache) +// { +// const auto & iter = +// _cache_all_hits_from_particle.find(g4particle); +// if (iter != _cache_all_hits_from_particle.end()) +// { +// return iter->second; +// } +// } +// +// std::set > hits; +// +// assert(_hit_truth_map); +// +// for (const auto& [trkrID, _hitmap] : _hitmaps) +// { +// // loop over all the hits +// TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); +// for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; +// iter != all_hitsets.second; +// ++iter) +// { +// TrkrHitSet::ConstRange range = iter->second->getHits(); +// for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) +// { +// TrkrDefs::hitkey hit_key = hitr->first; +// +// // loop over all truth hits connected to this hit +// std::set g4hits = all_truth_hits(hit_key, trkrID); +// for (std::set::iterator jter = g4hits.begin(); +// jter != g4hits.end(); +// ++jter) +// { +// PHG4Hit* candidate = *jter; +// PHG4Particle* particle = _truthinfo->GetParticle(candidate->get_trkid()); +// if (g4particle->get_track_id() == particle->get_track_id()) +// { +// hits.insert(make_pair(iter->first, hit_key)); +// } +// } +// } +// } +// } +// +// if (_do_cache) _cache_all_hits_from_particle.insert(make_pair(g4particle, hits)); +// +// return hits; +//} + +//std::set > SvtxHitEval::all_hits_from(PHG4Hit* g4hit) +//{ +// if (!has_node_pointers()) +// { +// ++_errors; +// if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; +// return std::set >(); +// } +// +// if (_strict) +// { +// assert(g4hit); +// } +// else if (!g4hit) +// { +// ++_errors; +// if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; +// return std::set >(); +// } +// +// if (_do_cache) +// { +// const auto & iter = +// _cache_all_hits_from_g4hit.find(g4hit); +// if (iter != _cache_all_hits_from_g4hit.end()) +// { +// return iter->second; +// } +// } +// +// std::set hits; +// +// unsigned int hit_layer = g4hit->get_layer(); +// +// // loop over all the hits +// for (const auto& [trkrID, _hitmap] : _hitmaps) +// { +// TrkrHitSetContainer::ConstRange all_hitsets = _hitmap->getHitSets(); +// for (TrkrHitSetContainer::ConstIterator iter = all_hitsets.first; +// iter != all_hitsets.second; +// ++iter) +// { +// TrkrHitSet::ConstRange range = iter->second->getHits(); +// for (TrkrHitSet::ConstIterator hitr = range.first; hitr != range.second; ++hitr) +// { +// TrkrDefs::hitkey hit_key = hitr->first; +// +// if (TrkrDefs::getLayer(hit_key) != hit_layer) continue; +// +// // loop over all truth hits connected to this hit +// std::set g4hits = all_truth_hits(iter->first, hit_key); +// for (std::set::iterator jter = g4hits.begin(); +// jter != g4hits.end(); +// ++jter) +// { +// PHG4Hit* candidate = *jter; +// if (candidate->get_hit_id() == g4hit->get_hit_id()) +// { +// hits.insert(make_pair(iter->first, hit_key)); +// } +// } +// } +// } +// } +// +// if (_do_cache) _cache_all_hits_from_g4hit.insert(make_pair(g4hit, hits)); +// +// return hits; +//} // overlap calculations - float SvtxHitEval::get_energy_contribution(TrkrDefs::hitkey hit_key, PHG4Particle* particle) +float SvtxHitEval::get_energy_contribution(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key, PHG4Particle* particle) { if (!has_node_pointers()) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return NAN; } @@ -868,14 +477,16 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) else if (!hit_key || !particle) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return NAN; } + const std::pair key(hitset_key, hit_key); + if (_do_cache) { - std::map, float>::iterator iter = - _cache_get_energy_contribution_g4particle.find(make_pair(hit_key, particle)); + const auto & iter = + _cache_get_energy_contribution_g4particle.find(make_pair(key, particle)); if (iter != _cache_get_energy_contribution_g4particle.end()) { return iter->second; @@ -883,7 +494,7 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) } float energy = 0.0; - std::set g4hits = all_truth_hits(hit_key); + std::set g4hits = all_truth_hits(hitset_key, hit_key); for (std::set::iterator iter = g4hits.begin(); iter != g4hits.end(); ++iter) @@ -895,17 +506,22 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) } } - if (_do_cache) _cache_get_energy_contribution_g4particle.insert(make_pair(make_pair(hit_key, particle), energy)); + if (_do_cache) _cache_get_energy_contribution_g4particle.insert( + make_pair( + make_pair( + key, + particle), + energy)); return energy; } - float SvtxHitEval::get_energy_contribution(TrkrDefs::hitkey hit_key, PHG4Hit* g4hit) +float SvtxHitEval::get_energy_contribution(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key, PHG4Hit* g4hit) { if (!has_node_pointers()) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return NAN; } @@ -917,14 +533,15 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) else if (!hit_key || !g4hit) { ++_errors; - if(_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; + if (_verbosity > 0) cout << PHWHERE << " nerr: " << _errors << endl; return NAN; } + const std::pair key(hitset_key, hit_key); if (_do_cache) { - std::map, float>::iterator iter = - _cache_get_energy_contribution_g4hit.find(make_pair(hit_key, g4hit)); + const auto & iter = + _cache_get_energy_contribution_g4hit.find(make_pair(key, g4hit)); if (iter != _cache_get_energy_contribution_g4hit.end()) { return iter->second; @@ -935,7 +552,7 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) // complex in the future, so this is here mostly as future-proofing. float energy = 0.0; - std::set g4hits = all_truth_hits(hit_key); + std::set g4hits = all_truth_hits(hitset_key, hit_key); for (std::set::iterator iter = g4hits.begin(); iter != g4hits.end(); ++iter) @@ -945,7 +562,7 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) energy += candidate->get_edep(); } - if (_do_cache) _cache_get_energy_contribution_g4hit.insert(make_pair(make_pair(hit_key, g4hit), energy)); + if (_do_cache) _cache_get_energy_contribution_g4hit.insert(make_pair(make_pair(key, g4hit), energy)); return energy; } @@ -953,18 +570,18 @@ std::set SvtxHitEval::all_hits_from(PHG4Hit* g4hit) void SvtxHitEval::get_node_pointers(PHCompositeNode* topNode) { // need things off of the DST... - for (const auto & [trkrID, trkrName] : TrkrDefs::TrkrNames) + for (const auto& [trkrID, trkrName] : TrkrDefs::TrkrNames) { - TrkrHitSetContainer * _hitmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); + TrkrHitSetContainer* _hitmap = findNode::getClass(topNode, "TRKR_HITSET_" + trkrName); if (_hitmap) _hitmaps[trkrID] = _hitmap; } - + _clustermap = findNode::getClass(topNode, "CORRECTED_TRKR_CLUSTER"); - if(!_clustermap) + if (!_clustermap) _clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); - - _hit_truth_map = findNode::getClass(topNode,"TRKR_HITTRUTHASSOC"); + + _hit_truth_map = findNode::getClass(topNode, "TRKR_HITTRUTHASSOC"); // need things off of the DST... _g4hits_tpc = findNode::getClass(topNode, "G4HIT_TPC"); diff --git a/simulation/g4simulation/g4eval/SvtxHitEval.h b/simulation/g4simulation/g4eval/SvtxHitEval.h index 8d1db965c8..3b9b7d2036 100644 --- a/simulation/g4simulation/g4eval/SvtxHitEval.h +++ b/simulation/g4simulation/g4eval/SvtxHitEval.h @@ -46,36 +46,29 @@ class SvtxHitEval // access the clustereval (and its cached values) SvtxTruthEval* get_truth_eval() { return &_trutheval; } - //PHG4Cell* get_cell(SvtxHit* hit); + // PHG4Cell* get_cell(SvtxHit* hit); // backtrace through to PHG4Hits - std::set all_truth_hits(TrkrDefs::hitkey hit_key); - PHG4Hit* max_truth_hit_by_energy(TrkrDefs::hitkey hit_key); - - // backtrace through to PHG4Hits for a specific tracker - std::set all_truth_hits(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid); - PHG4Hit* max_truth_hit_by_energy(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid); + std::set all_truth_hits(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key); + PHG4Hit* max_truth_hit_by_energy(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key); // backtrace through to PHG4Particles - std::set all_truth_particles(TrkrDefs::hitkey hit_key); - PHG4Particle* max_truth_particle_by_energy(TrkrDefs::hitkey hit_key); - - // backtrace through to PHG4Particles for a specific tracker - std::set all_truth_particles(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid); - PHG4Particle* max_truth_particle_by_energy(TrkrDefs::hitkey hit_key, const TrkrDefs::TrkrId trkrid); + std::set all_truth_particles(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key); + PHG4Particle* max_truth_particle_by_energy(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey hit_key); - // forwardtrace through to SvtxHits - std::set all_hits_from(PHG4Particle* truthparticle); - std::set all_hits_from(PHG4Hit* truthhit); - TrkrDefs::hitkey best_hit_from(PHG4Hit* truthhit); + // retire unused functions. Nonetheless, kept in comment at the moment in case some non-daily built class still uses them +// // forwardtrace through to SvtxHits +// std::set > all_hits_from(PHG4Particle* truthparticle); +// std::set > all_hits_from(PHG4Hit* truthhit); // overlap calculations - float get_energy_contribution(TrkrDefs::hitkey, PHG4Particle* truthparticle); - float get_energy_contribution(TrkrDefs::hitkey, PHG4Hit* truthhit); + float get_energy_contribution(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey, PHG4Particle* truthparticle); + float get_energy_contribution(const TrkrDefs::hitsetkey hitset_key, TrkrDefs::hitkey, PHG4Hit* truthhit); unsigned int get_errors() { return _errors + _trutheval.get_errors(); } private: + void get_node_pointers(PHCompositeNode* topNode); bool has_node_pointers(); @@ -96,15 +89,15 @@ class SvtxHitEval unsigned int _errors; bool _do_cache; - std::map > _cache_all_truth_hits; - std::map _cache_max_truth_hit_by_energy; - std::map > _cache_all_truth_particles; - std::map _cache_max_truth_particle_by_energy; - std::map > _cache_all_hits_from_particle; - std::map > _cache_all_hits_from_g4hit; - std::map _cache_best_hit_from_g4hit; - std::map, float> _cache_get_energy_contribution_g4particle; - std::map, float> _cache_get_energy_contribution_g4hit; + std::map, std::set > _cache_all_truth_hits; + std::map, PHG4Hit*> _cache_max_truth_hit_by_energy; + std::map, std::set > _cache_all_truth_particles; + std::map, PHG4Particle*> _cache_max_truth_particle_by_energy; + std::map> > _cache_all_hits_from_particle; + std::map> > _cache_all_hits_from_g4hit; + std::map> _cache_best_hit_from_g4hit; + std::map, PHG4Particle*>, float> _cache_get_energy_contribution_g4particle; + std::map, PHG4Hit*>, float> _cache_get_energy_contribution_g4hit; }; #endif // G4EVAL_SVTXHITEVAL_H From a855462b62d5d588478f3a78ba241c18b8f11b0d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 15:07:25 -0400 Subject: [PATCH 194/468] clean up --- simulation/g4simulation/g4eval/DSTEmulator.cc | 4 ---- simulation/g4simulation/g4eval/DSTEmulator.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/simulation/g4simulation/g4eval/DSTEmulator.cc b/simulation/g4simulation/g4eval/DSTEmulator.cc index d1101f3920..be05cac475 100644 --- a/simulation/g4simulation/g4eval/DSTEmulator.cc +++ b/simulation/g4simulation/g4eval/DSTEmulator.cc @@ -570,10 +570,6 @@ int DSTEmulator::load_nodes( PHCompositeNode* topNode ) // local container m_container = findNode::getClass(topNode, "TrackEvaluationContainer"); - // hitset container - // TRKR_HITSET are now split for each subsystem - // m_hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); - // g4hits m_g4hits_tpc = findNode::getClass(topNode, "G4HIT_TPC"); m_g4hits_intt = findNode::getClass(topNode, "G4HIT_INTT"); diff --git a/simulation/g4simulation/g4eval/DSTEmulator.h b/simulation/g4simulation/g4eval/DSTEmulator.h index 26929b0e8a..2a8d0f353e 100644 --- a/simulation/g4simulation/g4eval/DSTEmulator.h +++ b/simulation/g4simulation/g4eval/DSTEmulator.h @@ -80,9 +80,6 @@ class DSTEmulator : public SubsysReco //! evaluation node TrackEvaluationContainerv1* m_container = nullptr; - //! hits - TrkrHitSetContainer* m_hitsetcontainer = nullptr; - //! clusters TrkrClusterContainer* m_cluster_map = nullptr; From 7d63f5ee2e06bd194104413375e55a465717a90e Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 15:17:17 -0400 Subject: [PATCH 195/468] avoid a macros update with warning --- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc | 6 ++++++ simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index 25120b9a2c..38b6f38631 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -322,3 +322,9 @@ float PHG4TpcDigitizer::added_noise() return noise; } + +void PHG4TpcDigitizer:: +SetTpcMinLayer(const int ) +{ + std::cout <<__PRETTY_FUNCTION__<<" is deprecated. Ignore this call"< Date: Tue, 11 Apr 2023 16:27:47 -0400 Subject: [PATCH 196/468] fix sizing issues --- .../trackbase/TrkrHitSetContainerv2.cc | 47 +++++++++++-------- .../trackbase/TrkrHitSetContainerv2.h | 4 +- .../g4tpc/PHG4TpcElectronDrift.cc | 2 +- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc index 64cdffcf02..b4f95b83de 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.cc +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -15,8 +15,8 @@ #include TrkrHitSetContainerv2:: - TrkrHitSetContainerv2(const std::string& hitsetclass) - : m_hitArray(hitsetclass.c_str()) + TrkrHitSetContainerv2(const std::string& hitsetclass, const size_t estimated_size) + : m_hitArray(hitsetclass.c_str(), estimated_size) { } @@ -68,15 +68,7 @@ void TrkrHitSetContainerv2::removeHitSet(TrkrDefs::hitsetkey key) std::cout << __PRETTY_FUNCTION__ << " : deprecated. This function still works but slows down operation." << std::endl; - syncMapArray(); - auto iter = m_hitmap.find(key); - if (iter != m_hitmap.end()) - { - TrkrHitSet* hitset = iter->second; - // delete hitset; - m_hitArray.Remove(hitset); - m_hitmap.erase(iter); - } + exit(1); } void TrkrHitSetContainerv2::removeHitSet(TrkrHitSet* hitset) @@ -116,7 +108,7 @@ TrkrHitSetContainerv2::findOrAddHitSet(TrkrDefs::hitsetkey key) auto it = m_hitmap.lower_bound(key); if (it == m_hitmap.end() || (key < it->first)) { - TrkrHitSet* hitset = (TrkrHitSet*) m_hitArray.ConstructedAt(m_hitArray.GetSize()); + TrkrHitSet* hitset = (TrkrHitSet*) m_hitArray.ConstructedAt(m_hitArray.GetLast() + 1); assert(hitset); it = m_hitmap.insert(it, std::make_pair(key, hitset)); @@ -142,21 +134,36 @@ TrkrHitSetContainerv2::findHitSet(TrkrDefs::hitsetkey key) void TrkrHitSetContainerv2::syncMapArray(void) const { - if (m_hitmap.size() == (size_t) m_hitArray.GetSize()) return; + if (m_hitmap.size() == (size_t) size()) return; if (m_hitmap.size() > 0) { std::cout << __PRETTY_FUNCTION__ << " Error: m_hitmap and m_hitArray get out of sync, which should not happen unless DST readback. " - << "m_hitmap.size( ) = " << m_hitmap.size() << " m_hitArray.GetSize() = " << m_hitArray.GetSize() << std::endl; + << " size() = " << size() + << " m_hitmap.size( ) = " << m_hitmap.size() + << " m_hitArray.GetSize() = " << m_hitArray.GetSize() + << " m_hitArray.GetLast() = " << m_hitArray.GetLast() + << " m_hitArray.GetEntries() = " << m_hitArray.GetEntries() + << std::endl; } - for (int i = 0; i < m_hitArray.GetSize(); ++i) + for (unsigned int i = 0; i < size(); ++i) { - TrkrHitSet* hitset = static_cast(m_hitArray[i]); - - assert(hitset); - - m_hitmap[hitset->getHitSetKey()] = hitset; + TrkrHitSet* hitset = dynamic_cast(m_hitArray[i]); + + if (hitset == nullptr) + { + std::cout << __PRETTY_FUNCTION__ << " : fatal error, invalid hitset in m_hitArray at position " << i << ". " + << " size() = " << size() + << " m_hitmap.size( ) = " << m_hitmap.size() + << " m_hitArray.GetSize() = " << m_hitArray.GetSize() + << " m_hitArray.GetLast() = " << m_hitArray.GetLast() + << " m_hitArray.GetEntries() = " << m_hitArray.GetEntries() + << std::endl; + assert(hitset); + } + else + m_hitmap[hitset->getHitSetKey()] = hitset; } } diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.h b/offline/packages/trackbase/TrkrHitSetContainerv2.h index f8897432c8..28ff3892cc 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.h +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.h @@ -23,7 +23,7 @@ class TrkrHitSetContainerv2 final : public TrkrHitSetContainer TrkrHitSetContainerv2() = default; public: - TrkrHitSetContainerv2(const std::string& hitsetclass); + TrkrHitSetContainerv2(const std::string& hitsetclass, const size_t estimated_size); ~TrkrHitSetContainerv2() override { @@ -56,7 +56,7 @@ class TrkrHitSetContainerv2 final : public TrkrHitSetContainer unsigned int size() const override { - return m_hitArray.GetSize(); + return m_hitArray.GetEntriesFast(); } private: diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index a732f7c763..4818050ae9 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -140,7 +140,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) dstNode->addNode(DetNode); } - hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1"); + hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1", 24*48 /*estimated number of TPC hitsets for pre-allocated memory*/); auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_TPC", "PHObject"); DetNode->addNode(newNode); } From b0844eae8497de280cdef62eb47dbe328aa79764 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 16:56:31 -0400 Subject: [PATCH 197/468] debug --- .../trackbase/TrkrHitSetContainerv2.cc | 4 +- .../g4tpc/PHG4TpcElectronDrift.cc | 43 ++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc index b4f95b83de..a9e943ce7d 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.cc +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -63,7 +63,7 @@ TrkrHitSetContainerv2::addHitSetSpecifyKey(const TrkrDefs::hitsetkey key, TrkrHi return TrkrHitSetContainer::addHitSetSpecifyKey(key, newhit); } -void TrkrHitSetContainerv2::removeHitSet(TrkrDefs::hitsetkey key) +void TrkrHitSetContainerv2::removeHitSet(TrkrDefs::hitsetkey ) { std::cout << __PRETTY_FUNCTION__ << " : deprecated. This function still works but slows down operation." << std::endl; @@ -146,6 +146,8 @@ void TrkrHitSetContainerv2::syncMapArray(void) const << " m_hitArray.GetLast() = " << m_hitArray.GetLast() << " m_hitArray.GetEntries() = " << m_hitArray.GetEntries() << std::endl; + + assert(m_hitmap.size() == 0); } for (unsigned int i = 0; i < size(); ++i) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 4818050ae9..d7228e6c4f 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -140,7 +140,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) dstNode->addNode(DetNode); } - hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1", 24*48 /*estimated number of TPC hitsets for pre-allocated memory*/); + hitsetcontainer = new TrkrHitSetContainerv2("TrkrHitSetTpcv1", 24 * 48 /*estimated number of TPC hitsets for pre-allocated memory*/); auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET_TPC", "PHObject"); DetNode->addNode(newNode); } @@ -631,6 +631,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // ensure the hitset is prepared and consistent { + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side << std::endl; + } + assert(seggeo); PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); assert(layer_geometry); @@ -643,6 +650,14 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } else { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setNPads " << npad + << std::endl; + } hitset->setNPads(npad); } if (hitset->getPadIndexStart()) @@ -651,6 +666,14 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } else { + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setPadIndexStart " << start_pad + << std::endl; + } hitset->setPadIndexStart(start_pad); } @@ -663,6 +686,14 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } else { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setTBins " << ntbin + << std::endl; + } hitset->setTBins(ntbin); } if (hitset->getTBinIndexStart()) @@ -671,6 +702,14 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } else { + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setTBinIndexStart " << start_tbin + << std::endl; + } hitset->setTBinIndexStart(start_tbin); } } // ensure the hitset is prepared and consistent @@ -683,7 +722,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { TrkrDefs::hitkey temp_hitkey = temp_hit_iter->first; TrkrHit *temp_tpchit = temp_hit_iter->second; - if (Verbosity() > 10 && layer == print_layer) + if ((Verbosity() > 10 && layer == print_layer) or Verbosity() > 100) { std::cout << " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) << " z bin " << TpcDefs::getTBin(temp_hitkey) From a1516835dcf18e2b3a58f8d8fbc6ae7bbb71f683 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 11 Apr 2023 17:19:55 -0400 Subject: [PATCH 198/468] Add sphenix cdb client --- offline/database/sphenixnpc/Makefile.am | 52 ++++++++++++ offline/database/sphenixnpc/autogen.sh | 8 ++ offline/database/sphenixnpc/configure.ac | 13 +++ offline/database/sphenixnpc/sphenixnpc.cc | 97 +++++++++++++++++++++++ offline/database/sphenixnpc/sphenixnpc.h | 49 ++++++++++++ 5 files changed, 219 insertions(+) create mode 100644 offline/database/sphenixnpc/Makefile.am create mode 100755 offline/database/sphenixnpc/autogen.sh create mode 100644 offline/database/sphenixnpc/configure.ac create mode 100644 offline/database/sphenixnpc/sphenixnpc.cc create mode 100644 offline/database/sphenixnpc/sphenixnpc.h diff --git a/offline/database/sphenixnpc/Makefile.am b/offline/database/sphenixnpc/Makefile.am new file mode 100644 index 0000000000..b229eb8fd4 --- /dev/null +++ b/offline/database/sphenixnpc/Makefile.am @@ -0,0 +1,52 @@ +AUTOMAKE_OPTIONS = foreign + +# List of shared libraries to produce +lib_LTLIBRARIES = \ + libsphenixnpc.la + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +libsphenixnpc_la_SOURCES = \ + sphenixnpc.cc + + +libsphenixnpc_la_LIBADD = \ + -lnopayloadclient + +############################################## +# please add new classes in alphabetical order + +pkginclude_HEADERS = \ + sphenixnpc.h + +################################################ +# linking tests + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libsphenixnpc.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +############################################## +# please add new classes in alphabetical order + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/database/sphenixnpc/autogen.sh b/offline/database/sphenixnpc/autogen.sh new file mode 100755 index 0000000000..be614cda0c --- /dev/null +++ b/offline/database/sphenixnpc/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/offline/database/sphenixnpc/configure.ac b/offline/database/sphenixnpc/configure.ac new file mode 100644 index 0000000000..75794b946c --- /dev/null +++ b/offline/database/sphenixnpc/configure.ac @@ -0,0 +1,13 @@ +AC_INIT(sphenixnpc,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) +LT_INIT([disable-static]) + +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc new file mode 100644 index 0000000000..bfda85331d --- /dev/null +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -0,0 +1,97 @@ +#include "sphenixnpc.h" + +sphenixnpc *sphenixnpc::__instance = nullptr; + +sphenixnpc *sphenixnpc::instance(const std::string &globaltag) +{ + if (! __instance) + { + __instance = new sphenixnpc(); + } + __instance->setGlobalTag(globaltag); + return __instance; +} + +sphenixnpc::~sphenixnpc() +{ + clearCache(); + __instance = nullptr; +} + +json sphenixnpc::createGlobalTag(const std::string &tagname) +{ + setGlobalTag(tagname); + return nopayloadclient::Client::createGlobalTag(); +} + +json sphenixnpc::deleteGlobalTag(const std::string &tagname) +{ + setGlobalTag(tagname); + return nopayloadclient::Client::deleteGlobalTag(); +} + +json sphenixnpc::getUrlDict(long long iov) { + return nopayloadclient::Client::getUrlDict(0, iov); +} + +json sphenixnpc::get(std::string pl_type, long long iov) { + if (url_dict_.is_null()) { + json resp = getUrlDict(iov); + if (resp["code"] != 0) return resp; + url_dict_ = resp["msg"]; + } + if (not url_dict_.contains(pl_type)) { + return DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); + } + return makeResp(url_dict_[pl_type]); +} + +json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, + long long iov_start) { + return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); +} + +json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, + long long iov_start, long long iov_end) { + return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); +} + +json sphenixnpc::setGlobalTag(std::string name) { + if (name != m_CachedGlobalTag) + { + url_dict_ = json {}; + m_CachedGlobalTag = name; + } + return nopayloadclient::Client::setGlobalTag(name); +} + +json sphenixnpc::clearCache() { + url_dict_ = json {}; + return nopayloadclient::Client::clearCache(); +} + +std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov) +{ + nlohmann::json result = get(type, iov); + return result.at("msg"); +} + +int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start) +{ + json ret = insertPayload(payloadtype, fname, iov_start); + if (Verbosity()) + { + std::cout << ret << std::endl; + } + return 0; +} + +int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start, uint64_t iov_end) +{ + json ret = insertPayload(payloadtype, fname, iov_start, iov_end); + if (Verbosity()) + { + std::cout << ret << std::endl; + } + return 0; +} diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h new file mode 100644 index 0000000000..681a065f4b --- /dev/null +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -0,0 +1,49 @@ +#ifndef DBTOOLS_SPHENIXNPC_H +#define DBTOOLS_SPHENIXNPC_H + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic pop + +#include + +#include + +using json = nlohmann::json; + +//namespace sphenixnpc { + +class sphenixnpc : public nopayloadclient::Client +{ + +public: + static sphenixnpc *instance(const std::string &globaltag = "NONE"); + ~sphenixnpc(); + json getUrlDict(long long iov); + json createGlobalTag(const std::string &tagname); + + json deleteGlobalTag(const std::string&); + json get(std::string pl_type, long long iov); + json insertPayload(std::string pl_type, std::string file_url, + long long iov_start); + json insertPayload(std::string pl_type, std::string file_url, + long long iov_start, long long iov_end); + json setGlobalTag(std::string name); + json clearCache(); + std::string getCalibrationFile(const std::string &type, uint64_t iov); + int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start); + int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start, uint64_t iov_end); + void Verbosity(int i) {m_Verbosity = i;} + int Verbosity() const {return m_Verbosity;} + +private: + static sphenixnpc *__instance; + int m_Verbosity = 0; + json url_dict_; // valid until global tag is switched + std::string m_CachedGlobalTag; +}; + +//} +#endif // DBTOOLS_SPHENIXNPC_H From 319c63435a2b97c9b16b66406bd71639a4994ea2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 11 Apr 2023 17:37:22 -0400 Subject: [PATCH 199/468] clang-format --- offline/database/sphenixnpc/sphenixnpc.cc | 66 +++++++++++++---------- offline/database/sphenixnpc/sphenixnpc.h | 63 ++++++++++------------ 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index bfda85331d..bca906c876 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -4,7 +4,7 @@ sphenixnpc *sphenixnpc::__instance = nullptr; sphenixnpc *sphenixnpc::instance(const std::string &globaltag) { - if (! __instance) + if (!__instance) { __instance = new sphenixnpc(); } @@ -18,56 +18,64 @@ sphenixnpc::~sphenixnpc() __instance = nullptr; } -json sphenixnpc::createGlobalTag(const std::string &tagname) +nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) { setGlobalTag(tagname); return nopayloadclient::Client::createGlobalTag(); } -json sphenixnpc::deleteGlobalTag(const std::string &tagname) +nlohmann::json sphenixnpc::deleteGlobalTag(const std::string &tagname) { setGlobalTag(tagname); return nopayloadclient::Client::deleteGlobalTag(); } -json sphenixnpc::getUrlDict(long long iov) { - return nopayloadclient::Client::getUrlDict(0, iov); +nlohmann::json sphenixnpc::getUrlDict(long long iov) +{ + return nopayloadclient::Client::getUrlDict(0, iov); } -json sphenixnpc::get(std::string pl_type, long long iov) { - if (url_dict_.is_null()) { - json resp = getUrlDict(iov); - if (resp["code"] != 0) return resp; - url_dict_ = resp["msg"]; - } - if (not url_dict_.contains(pl_type)) { - return DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); - } - return makeResp(url_dict_[pl_type]); +nlohmann::json sphenixnpc::get(std::string pl_type, long long iov) +{ + if (url_dict_.is_null()) + { + nlohmann::json resp = getUrlDict(iov); + if (resp["code"] != 0) return resp; + url_dict_ = resp["msg"]; + } + if (not url_dict_.contains(pl_type)) + { + return DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); + } + return makeResp(url_dict_[pl_type]); } -json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, - long long iov_start) { - return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); +nlohmann::json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, + long long iov_start) +{ + return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); } -json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, - long long iov_start, long long iov_end) { - return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); +nlohmann::json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, + long long iov_start, long long iov_end) +{ + return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); } -json sphenixnpc::setGlobalTag(std::string name) { +nlohmann::json sphenixnpc::setGlobalTag(std::string name) +{ if (name != m_CachedGlobalTag) { - url_dict_ = json {}; + url_dict_ = nlohmann::json{}; m_CachedGlobalTag = name; } - return nopayloadclient::Client::setGlobalTag(name); + return nopayloadclient::Client::setGlobalTag(name); } -json sphenixnpc::clearCache() { - url_dict_ = json {}; - return nopayloadclient::Client::clearCache(); +nlohmann::json sphenixnpc::clearCache() +{ + url_dict_ = nlohmann::json{}; + return nopayloadclient::Client::clearCache(); } std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov) @@ -78,7 +86,7 @@ std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start) { - json ret = insertPayload(payloadtype, fname, iov_start); + nlohmann::json ret = insertPayload(payloadtype, fname, iov_start); if (Verbosity()) { std::cout << ret << std::endl; @@ -88,7 +96,7 @@ int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &f int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start, uint64_t iov_end) { - json ret = insertPayload(payloadtype, fname, iov_start, iov_end); + nlohmann::json ret = insertPayload(payloadtype, fname, iov_start, iov_end); if (Verbosity()) { std::cout << ret << std::endl; diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 681a065f4b..2095b8d7b5 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -1,6 +1,5 @@ -#ifndef DBTOOLS_SPHENIXNPC_H -#define DBTOOLS_SPHENIXNPC_H - +#ifndef SPHENIXNPC_SPHENIXNPC_H +#define SPHENIXNPC_SPHENIXNPC_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -11,39 +10,33 @@ #include -using json = nlohmann::json; - -//namespace sphenixnpc { - -class sphenixnpc : public nopayloadclient::Client +class sphenixnpc : public nopayloadclient::Client { - -public: + public: static sphenixnpc *instance(const std::string &globaltag = "NONE"); - ~sphenixnpc(); - json getUrlDict(long long iov); - json createGlobalTag(const std::string &tagname); - - json deleteGlobalTag(const std::string&); - json get(std::string pl_type, long long iov); - json insertPayload(std::string pl_type, std::string file_url, - long long iov_start); - json insertPayload(std::string pl_type, std::string file_url, - long long iov_start, long long iov_end); - json setGlobalTag(std::string name); - json clearCache(); - std::string getCalibrationFile(const std::string &type, uint64_t iov); - int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start); - int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start, uint64_t iov_end); - void Verbosity(int i) {m_Verbosity = i;} - int Verbosity() const {return m_Verbosity;} - -private: - static sphenixnpc *__instance; - int m_Verbosity = 0; - json url_dict_; // valid until global tag is switched - std::string m_CachedGlobalTag; + ~sphenixnpc(); + nlohmann::json getUrlDict(long long iov); + nlohmann::json createGlobalTag(const std::string &tagname); + + nlohmann::json deleteGlobalTag(const std::string &); + nlohmann::json get(std::string pl_type, long long iov); + nlohmann::json insertPayload(std::string pl_type, std::string file_url, + long long iov_start); + nlohmann::json insertPayload(std::string pl_type, std::string file_url, + long long iov_start, long long iov_end) override; + nlohmann::json setGlobalTag(std::string name) override; + nlohmann::json clearCache() override; + std::string getCalibrationFile(const std::string &type, uint64_t iov); + int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start); + int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start, uint64_t iov_end); + void Verbosity(int i) { m_Verbosity = i; } + int Verbosity() const { return m_Verbosity; } + + private: + static sphenixnpc *__instance; + int m_Verbosity = 0; + nlohmann::json url_dict_; // valid until global tag is switched + std::string m_CachedGlobalTag; }; -//} -#endif // DBTOOLS_SPHENIXNPC_H +#endif // SPHENIXNPC_SPHENIXNPC_H From 7f0415f651a64d87d76d88402bb7c52153a4ccda Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 11 Apr 2023 17:53:27 -0400 Subject: [PATCH 200/468] fix cppcheck warnings --- offline/database/sphenixnpc/sphenixnpc.cc | 1 - offline/database/sphenixnpc/sphenixnpc.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index bca906c876..cdee4e2111 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -14,7 +14,6 @@ sphenixnpc *sphenixnpc::instance(const std::string &globaltag) sphenixnpc::~sphenixnpc() { - clearCache(); __instance = nullptr; } diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 2095b8d7b5..225ebc6425 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -27,8 +27,8 @@ class sphenixnpc : public nopayloadclient::Client nlohmann::json setGlobalTag(std::string name) override; nlohmann::json clearCache() override; std::string getCalibrationFile(const std::string &type, uint64_t iov); - int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start); - int insertcalib(const std::string &fname, const std::string &payloadtype, uint64_t iov_start, uint64_t iov_end); + int insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start); + int insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start, uint64_t iov_end); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } From fe04cd7019ef34e187ca994ff141fc0a2711d978 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 21:27:48 -0400 Subject: [PATCH 201/468] fix init, add checks --- offline/packages/trackbase/TrkrHitSetTpc.cc | 4 ++-- offline/packages/trackbase/TrkrHitSetTpc.h | 7 ++++--- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 15 ++++++++++---- offline/packages/trackbase/TrkrHitSetTpcv1.h | 20 ++++++++++--------- .../g4tpc/PHG4TpcElectronDrift.cc | 6 +++--- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpc.cc b/offline/packages/trackbase/TrkrHitSetTpc.cc index febef73fdd..76d492a98c 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.cc +++ b/offline/packages/trackbase/TrkrHitSetTpc.cc @@ -47,7 +47,7 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke const uint16_t local_tbin = tbin - getTBinIndexStart(); assert(local_pad < getNPads()); - assert(local_tbin < getTBins()); + assert(local_tbin < getNTBins()); return std::make_pair(local_pad, local_tbin); } @@ -57,7 +57,7 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke const uint16_t local_tbin = -tbin + getTBinIndexStart(); assert(local_pad < getNPads()); - assert(local_tbin < getTBins()); + assert(local_tbin < getNTBins()); return std::make_pair(local_pad, local_tbin); } diff --git a/offline/packages/trackbase/TrkrHitSetTpc.h b/offline/packages/trackbase/TrkrHitSetTpc.h index 1c52b12dd2..06bb388185 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.h +++ b/offline/packages/trackbase/TrkrHitSetTpc.h @@ -27,7 +27,8 @@ class TrkrHitSetTpc : public TrkrHitSet virtual void identify(std::ostream& os = std::cout) const override; - virtual void Resize(const uint16_t /*n_pad*/, const uint16_t /*n_tbin*/) {} + //! resize to fit getNPads and getNTBins + virtual void Resize() {} //! global -> local conversion std::pair getLocalPhiTBin(const TrkrDefs::hitkey) const; @@ -77,12 +78,12 @@ class TrkrHitSetTpc : public TrkrHitSet { } - virtual uint16_t getTBins() const + virtual uint16_t getNTBins() const { return 0; } - virtual void setTBins(uint16_t /*tBins*/) + virtual void setNTBins(uint16_t /*tBins*/) { } diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 805dd6aefd..d4cb388975 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -22,8 +22,11 @@ void TrkrHitSetTpcv1::Reset() std::fill(pad.begin(), pad.end(), 0); } } -void TrkrHitSetTpcv1::Resize(const uint16_t n_pad, const uint16_t n_tbin) +void TrkrHitSetTpcv1::Resize() { + const uint16_t n_pad = getNPads(); + const uint16_t n_tbin = getNTBins(); + if (n_pad != m_timeFrameADCData.size()) m_timeFrameADCData.resize(n_pad); @@ -47,7 +50,7 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const << " TrkrId: " << trkrid << " layer: " << layer << " m_nPads: " << m_nPads - << " n_tBins: " << n_tBins + << " n_tBins: " << m_nTBins << " m_padIndexStart: " << m_padIndexStart << " m_tBinIndexStart: " << m_tBinIndexStart << " m_StartingBCO: " << m_StartingBCO @@ -77,7 +80,9 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint16_t tbin) { assert(pad < m_nPads); - assert(tbin < n_tBins); + assert(tbin < m_nTBins); + assert(m_timeFrameADCData.size() == m_nPads); + assert(m_timeFrameADCData[pad].size() == m_nTBins); return m_timeFrameADCData[pad][tbin]; } @@ -85,7 +90,9 @@ TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint1 const TpcDefs::ADCDataType& TrkrHitSetTpcv1::getTpcADC(const uint16_t pad, const uint16_t tbin) const { assert(pad < m_nPads); - assert(tbin < n_tBins); + assert(tbin < m_nTBins); + assert(m_timeFrameADCData.size() == m_nPads); + assert(m_timeFrameADCData[pad].size() == m_nTBins); return m_timeFrameADCData[pad][tbin]; } diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.h b/offline/packages/trackbase/TrkrHitSetTpcv1.h index 02bd66cc20..025230f4e4 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.h +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.h @@ -16,9 +16,9 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc TrkrHitSetTpcv1() = default; TrkrHitSetTpcv1(const uint16_t n_pad, const uint16_t n_tbin) - : TrkrHitSetTpc(n_pad, n_tbin) + : TrkrHitSetTpc(n_pad, n_tbin), m_nPads(n_pad), m_nTBins(n_tbin) { - Resize(n_pad, n_tbin); + Resize(); } ~TrkrHitSetTpcv1() override @@ -27,7 +27,7 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc void identify(std::ostream& os = std::cout) const override; - void Resize(const uint16_t n_pad, const uint16_t n_tbin) override; + void Resize() override; //! For ROOT TClonesArray end of event Operation void Clear(Option_t* /*option*/ = "") override { Reset(); } @@ -61,7 +61,7 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc unsigned int size() const override { - return m_nPads * n_tBins; + return m_nPads * m_nTBins; } uint16_t getNPads() const override @@ -72,16 +72,18 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc void setNPads(uint16_t nPads = 0) override { m_nPads = nPads; + Resize(); } - uint16_t getTBins() const override + uint16_t getNTBins() const override { - return n_tBins; + return m_nTBins; } - void setTBins(uint16_t tBins = 0) override + void setNTBins(uint16_t tBins = 0) override { - n_tBins = tBins; + m_nTBins = tBins; + Resize(); } uint16_t getPadIndexStart() const override @@ -147,7 +149,7 @@ class TrkrHitSetTpcv1 final : public TrkrHitSetTpc //! size of the local index uint16_t m_nPads = 0; - uint16_t n_tBins = 0; + uint16_t m_nTBins = 0; ClassDefOverride(TrkrHitSetTpcv1, 1); }; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index d7228e6c4f..64c5559992 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -680,9 +680,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. const int ntbin = layer_geometry->get_zbins(); const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); - if (hitset->getTBins()) + if (hitset->getNTBins()) { - assert(hitset->getTBins() == ntbin); + assert(hitset->getNTBins() == ntbin); } else { @@ -694,7 +694,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) << " : setTBins " << ntbin << std::endl; } - hitset->setTBins(ntbin); + hitset->setNTBins(ntbin); } if (hitset->getTBinIndexStart()) { From d4167b76d72c8d5761eaebe82c89c7ac37a4aab2 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 22:00:15 -0400 Subject: [PATCH 202/468] more checks --- offline/packages/trackbase/TrkrHitSetTpc.cc | 49 ++++++++++++++----- .../g4tpc/PHG4TpcElectronDrift.cc | 1 + 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpc.cc b/offline/packages/trackbase/TrkrHitSetTpc.cc index 76d492a98c..85073267da 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.cc +++ b/offline/packages/trackbase/TrkrHitSetTpc.cc @@ -41,26 +41,51 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke const uint16_t tbin = TpcDefs ::getTBin(key); const uint8_t side = TpcDefs::getSide(getHitSetKey()); + uint16_t local_pad = 0; + uint16_t local_tbin = 0; + if (side == 0) { - const uint16_t local_pad = pad - getPadIndexStart(); - const uint16_t local_tbin = tbin - getTBinIndexStart(); - - assert(local_pad < getNPads()); - assert(local_tbin < getNTBins()); - - return std::make_pair(local_pad, local_tbin); + local_pad = pad - getPadIndexStart(); + local_tbin = tbin - getTBinIndexStart(); } else { - const uint16_t local_pad = getNPads() - 1 - pad + getPadIndexStart(); - const uint16_t local_tbin = -tbin + getTBinIndexStart(); + local_pad = getNPads() - 1 - pad + getPadIndexStart(); + local_tbin = -tbin + getTBinIndexStart(); + } - assert(local_pad < getNPads()); - assert(local_tbin < getNTBins()); + if (local_pad >= getNPads()) + { + std::cout << __PRETTY_FUNCTION__ << " fatal error local_pad >= getNPads()" + << " getHitSetKey() = " << getHitSetKey() + << " pad = " << pad + << " tbin = " << tbin + << " side = " << side + << " local_pad = " << local_pad + << " local_tbin = " << local_tbin + << " getPadIndexStart() = " << getPadIndexStart() + << " getTBinIndexStart() = " << getTBinIndexStart() + << std::endl; + } + assert(local_pad < getNPads()); - return std::make_pair(local_pad, local_tbin); + if (local_tbin >= getNTBins()) + { + std::cout << __PRETTY_FUNCTION__ << " fatal error local_tbin >= getNTBins()" + << " getHitSetKey() = " << getHitSetKey() + << " pad = " << pad + << " tbin = " << tbin + << " side = " << side + << " local_pad = " << local_pad + << " local_tbin = " << local_tbin + << " getPadIndexStart() = " << getPadIndexStart() + << " getTBinIndexStart() = " << getTBinIndexStart() + << std::endl; } + assert(local_tbin < getNTBins()); + + return std::make_pair(local_pad, local_tbin); } TrkrDefs::hitkey TrkrHitSetTpc::getHitKeyfromLocalBin( diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 64c5559992..7fb46d4a90 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -628,6 +628,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey); TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); assert(hitset); + assert(hitset->getHitSetKey() == node_hitsetkey); // ensure the hitset is prepared and consistent { From e6ff4bcc92cdaac5d04b24b1d7985f2e8d675622 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 11 Apr 2023 23:59:41 -0400 Subject: [PATCH 203/468] more checks --- .../trackbase/TrkrHitSetContainerv2.cc | 3 +- offline/packages/trackbase/TrkrHitSetTpc.cc | 4 +- .../g4tpc/PHG4TpcElectronDrift.cc | 38 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc index a9e943ce7d..bef971220e 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.cc +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -110,9 +110,8 @@ TrkrHitSetContainerv2::findOrAddHitSet(TrkrDefs::hitsetkey key) { TrkrHitSet* hitset = (TrkrHitSet*) m_hitArray.ConstructedAt(m_hitArray.GetLast() + 1); assert(hitset); - + hitset -> setHitSetKey(key); it = m_hitmap.insert(it, std::make_pair(key, hitset)); - it->second->setHitSetKey(key); } return it; } diff --git a/offline/packages/trackbase/TrkrHitSetTpc.cc b/offline/packages/trackbase/TrkrHitSetTpc.cc index 85073267da..c9baf7116b 100644 --- a/offline/packages/trackbase/TrkrHitSetTpc.cc +++ b/offline/packages/trackbase/TrkrHitSetTpc.cc @@ -39,7 +39,7 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke { const uint16_t pad = TpcDefs ::getPad(key); const uint16_t tbin = TpcDefs ::getTBin(key); - const uint8_t side = TpcDefs::getSide(getHitSetKey()); + const uint16_t side = TpcDefs::getSide(getHitSetKey()); uint16_t local_pad = 0; uint16_t local_tbin = 0; @@ -67,6 +67,7 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke << " getPadIndexStart() = " << getPadIndexStart() << " getTBinIndexStart() = " << getTBinIndexStart() << std::endl; + identify(); } assert(local_pad < getNPads()); @@ -82,6 +83,7 @@ std::pair TrkrHitSetTpc::getLocalPhiTBin(TrkrDefs::hitkey ke << " getPadIndexStart() = " << getPadIndexStart() << " getTBinIndexStart() = " << getTBinIndexStart() << std::endl; + identify(); } assert(local_tbin < getNTBins()); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 7fb46d4a90..a3146d7ca2 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -629,6 +629,12 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); assert(hitset); assert(hitset->getHitSetKey() == node_hitsetkey); + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " filling hitset from node_hitsetkey = "<identify(); + } // ensure the hitset is prepared and consistent { @@ -661,6 +667,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } hitset->setNPads(npad); } + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done npad hitset from node_hitsetkey = "<identify(); + } + if (hitset->getPadIndexStart()) { assert(hitset->getPadIndexStart() == start_pad); @@ -677,6 +690,12 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } hitset->setPadIndexStart(start_pad); } + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done start_pad hitset from node_hitsetkey = "<identify(); + } // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. const int ntbin = layer_geometry->get_zbins(); @@ -697,6 +716,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } hitset->setNTBins(ntbin); } + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done ntbin hitset from node_hitsetkey = "<identify(); + } + if (hitset->getTBinIndexStart()) { assert(hitset->getTBinIndexStart() == start_tbin); @@ -713,7 +739,19 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } hitset->setTBinIndexStart(start_tbin); } + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done start_tbin hitset from node_hitsetkey = "<identify(); + } } // ensure the hitset is prepared and consistent + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done initializing hitset from node_hitsetkey = "<identify(); + } // get all of the hits from the temporary hitset TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits(); From ba3cdb0f3e262dd911f520245b600a208dd628a5 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 12 Apr 2023 09:59:14 -0400 Subject: [PATCH 204/468] Turn on Gain Maps by default --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 1 - simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 445b86c34e..a6db2e32bf 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -746,7 +746,6 @@ void PHG4TpcPadPlaneReadout::UseGain(const int flagToUseGain) // Reading TPC Gain Maps from the file if(m_flagToUseGain==1){ std::string gain_maps_filename = std::string(getenv("CALIBRATIONROOT"))+std::string("/TPC/GainMaps/TPCGainMaps.root"); - std::cout<<"PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout :::"<Get("RadPhiPlot0")->Clone(); h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index 0e6053f65d..caf8c45e6d 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -91,8 +91,8 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array NTpcLayers; std::array SectorPhi; int m_NHits = 0; - - int m_flagToUseGain = 0; + // Using Gain maps is turned on by default + int m_flagToUseGain = 1; // gaussian sampling static constexpr double _nsigmas = 5; From e8d96e3b651d3e1e35d0e6aa56f2bc43de54a1f9 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 12 Apr 2023 10:24:21 -0400 Subject: [PATCH 205/468] Separated turn ON/OFF gain maps and map reading function --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 8 ++++++-- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index a6db2e32bf..5605db52ed 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -62,6 +62,7 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) : PHG4TpcPadPlane(name) { InitializeParameters(); + if(m_flagToUseGain==1)ReadGain(); RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion @@ -285,7 +286,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( double gain_weight = 1.0; if(m_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm nelec = nelec*gain_weight; - + std::cout<<"gain_weight = "<0) std::cout << "PHG4TpcPadPlaneReadout: UseGain: TRUE " << std::endl; +} + +void PHG4TpcPadPlaneReadout::ReadGain() +{ // Reading TPC Gain Maps from the file if(m_flagToUseGain==1){ std::string gain_maps_filename = std::string(getenv("CALIBRATIONROOT"))+std::string("/TPC/GainMaps/TPCGainMaps.root"); @@ -753,7 +758,6 @@ void PHG4TpcPadPlaneReadout::UseGain(const int flagToUseGain) h_gain[1]->SetDirectory(0); fileGain->Close(); } - //return; } void PHG4TpcPadPlaneReadout::SetDefaultParameters() { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index caf8c45e6d..36e1383c8d 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -31,6 +31,7 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane ~PHG4TpcPadPlaneReadout() override; void UseGain(const int flagToUseGain); + void ReadGain(); void SetDriftVelocity(double vd) override { drift_velocity = vd; } From a5db23b39f321804773823ac938fe4ee24085d18 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 12 Apr 2023 10:37:54 -0400 Subject: [PATCH 206/468] Separated turn ON/OFF gain maps and map reading function --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 5605db52ed..c3e974baf8 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -286,7 +286,6 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( double gain_weight = 1.0; if(m_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm nelec = nelec*gain_weight; - std::cout<<"gain_weight = "< Date: Wed, 12 Apr 2023 11:12:29 -0400 Subject: [PATCH 207/468] remove obsolete tpcresponse --- .../g4simulation/tpcresponse/Makefile.am | 47 ----- simulation/g4simulation/tpcresponse/TpcRS.cc | 193 ------------------ simulation/g4simulation/tpcresponse/TpcRS.h | 71 ------- .../g4simulation/tpcresponse/autogen.sh | 8 - .../g4simulation/tpcresponse/configure.ac | 16 -- 5 files changed, 335 deletions(-) delete mode 100644 simulation/g4simulation/tpcresponse/Makefile.am delete mode 100644 simulation/g4simulation/tpcresponse/TpcRS.cc delete mode 100644 simulation/g4simulation/tpcresponse/TpcRS.h delete mode 100755 simulation/g4simulation/tpcresponse/autogen.sh delete mode 100644 simulation/g4simulation/tpcresponse/configure.ac diff --git a/simulation/g4simulation/tpcresponse/Makefile.am b/simulation/g4simulation/tpcresponse/Makefile.am deleted file mode 100644 index 25d7bd7140..0000000000 --- a/simulation/g4simulation/tpcresponse/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = \ - -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include - -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 \ - `root-config --libs` - -pkginclude_HEADERS = \ - TpcRS.h - -lib_LTLIBRARIES = \ - libtpcresponse.la - -libtpcresponse_la_SOURCES = \ - TpcRS.cc - -libtpcresponse_la_LIBADD = \ - -lphg4hit \ - -lphool \ - -lSubsysReco \ - -ltpcrs \ - -lGeom \ - -lMathMore - -BUILT_SOURCES = testexternals.cc - -noinst_PROGRAMS = \ - testexternals - -testexternals_SOURCES = testexternals.cc -testexternals_LDADD = libtpcresponse.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ - -clean-local: - rm -f $(BUILT_SOURCES) diff --git a/simulation/g4simulation/tpcresponse/TpcRS.cc b/simulation/g4simulation/tpcresponse/TpcRS.cc deleted file mode 100644 index 35d7dbc8ba..0000000000 --- a/simulation/g4simulation/tpcresponse/TpcRS.cc +++ /dev/null @@ -1,193 +0,0 @@ -//____________________________________________________________________________.. -// -// This is a template for a Fun4All SubsysReco module with all methods from the -// $OFFLINE_MAIN/include/fun4all/SubsysReco.h baseclass -// You do not have to implement all of them, you can just remove unused methods -// here and in TpcRS.h. -// -// TpcRS(const std::string &name = "TpcRS") -// everything is keyed to TpcRS, duplicate names do work but it makes -// e.g. finding culprits in logs difficult or getting a pointer to the module -// from the command line -// -// TpcRS::~TpcRS() -// this is called when the Fun4AllServer is deleted at the end of running. Be -// mindful what you delete - you do loose ownership of object you put on the node tree -// -// int TpcRS::Init(PHCompositeNode *topNode) -// This method is called when the module is registered with the Fun4AllServer. You -// can create historgrams here or put objects on the node tree but be aware that -// modules which haven't been registered yet did not put antyhing on the node tree -// -// int TpcRS::InitRun(PHCompositeNode *topNode) -// This method is called when the first event is read (or generated). At -// this point the run number is known (which is mainly interesting for raw data -// processing). Also all objects are on the node tree in case your module's action -// depends on what else is around. Last chance to put nodes under the DST Node -// We mix events during readback if branches are added after the first event -// -// int TpcRS::process_event(PHCompositeNode *topNode) -// called for every event. Return codes trigger actions, you find them in -// $OFFLINE_MAIN/include/fun4all/Fun4AllReturnCodes.h -// everything is good: -// return Fun4AllReturnCodes::EVENT_OK -// abort event reconstruction, clear everything and process next event: -// return Fun4AllReturnCodes::ABORT_EVENT; -// proceed but do not save this event in output (needs output manager setting): -// return Fun4AllReturnCodes::DISCARD_EVENT; -// abort processing: -// return Fun4AllReturnCodes::ABORT_RUN -// all other integers will lead to an error and abort of processing -// -// int TpcRS::ResetEvent(PHCompositeNode *topNode) -// If you have internal data structures (arrays, stl containers) which needs clearing -// after each event, this is the place to do that. The nodes under the DST node are cleared -// by the framework -// -// int TpcRS::EndRun(const int runnumber) -// This method is called at the end of a run when an event from a new run is -// encountered. Useful when analyzing multiple runs (raw data). Also called at -// the end of processing (before the End() method) -// -// int TpcRS::End(PHCompositeNode *topNode) -// This is called at the end of processing. It needs to be called by the macro -// by Fun4AllServer::End(), so do not forget this in your macro -// -// int TpcRS::Reset(PHCompositeNode *topNode) -// not really used - it is called before the dtor is called -// -// void TpcRS::Print(const std::string &what) const -// Called from the command line - useful to print information when you need it -// -//____________________________________________________________________________.. - -#include "TpcRS.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -//____________________________________________________________________________.. -TpcRS::TpcRS(const std::string &name) - : SubsysReco(name) -{ - std::cout << "TpcRS::TpcRS(const std::string &name) Calling ctor" << std::endl; -} - -//____________________________________________________________________________.. -TpcRS::~TpcRS() -{ - delete simulator; - std::cout << "TpcRS::~TpcRS() Calling dtor" << std::endl; -} - -//____________________________________________________________________________.. -int TpcRS::Init(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::Init(PHCompositeNode *topNode) Initializing" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::InitRun(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::process_event(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::process_event(PHCompositeNode *topNode)" << std::endl; - PHG4TruthInfoContainer *TruthInfo = findNode::getClass(topNode, "G4TruthInfo"); - if (!TruthInfo) - { - std::cout << PHWHERE << " ERROR: Can't find G4TruthInfo" << std::endl; - gSystem->Exit(-1); - } - - PHG4HitContainer *hits = findNode::getClass(topNode, "G4HIT_TPC"); - if (!hits) - { - std::cout << "no G4HITS_TPC node" << std::endl; - gSystem->Exit(-1); - } - PHG4HitContainer::ConstRange hit_range = hits->getHits(); - for (PHG4HitContainer::ConstIterator hit_iter = hit_range.first; hit_iter != hit_range.second; hit_iter++) - { - PHG4Particle *particle = TruthInfo->GetParticle(hit_iter->second->get_trkid()); - tpcrs::SimulatedHit simu_hit; - if (hit_iter->second->get_trkid() == 0) - { - std::cout << "trackid=0, x: " << hit_iter->second->get_avg_x() << std::endl; - } - simu_hit.track_id = hit_iter->second->get_trkid(); - simu_hit.particle_id = particle->get_pid(); - simu_hit.x = hit_iter->second->get_avg_x(); - simu_hit.y = hit_iter->second->get_avg_y(); - simu_hit.z = hit_iter->second->get_avg_z(); - simu_hit.px = 0.5 * (hit_iter->second->get_px(0) + hit_iter->second->get_px(1)); - simu_hit.py = 0.5 * (hit_iter->second->get_py(0) + hit_iter->second->get_py(1)); - simu_hit.pz = 0.5 * (hit_iter->second->get_pz(0) + hit_iter->second->get_pz(1)); - simu_hit.de = hit_iter->second->get_edep(); - simu_hit.ds = hit_iter->second->get_path_length(); - simu_hit.tof = hit_iter->second->get_avg_t(); - simu_hits.push_back(simu_hit); - } - simulator->Distort(begin(simu_hits), end(simu_hits), std::back_inserter(dist_hits)); - - // simulator->Digitize(begin(simu_hits), end(simu_hits), std::back_inserter(digi_hits)); - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::ResetEvent(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl; - simu_hits.clear(); - dist_hits.clear(); - digi_hits.clear(); - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::EndRun(const int runnumber) -{ - std::cout << "TpcRS::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::End(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::End(PHCompositeNode *topNode) This is the End..." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TpcRS::Reset(PHCompositeNode *topNode) -{ - std::cout << "TpcRS::Reset(PHCompositeNode *topNode) being Reset" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -void TpcRS::Print(const std::string &what) const -{ - std::cout << "TpcRS::Print(const std::string &what) const Printing info for " << what << std::endl; -} - -void TpcRS::SetupConfigurator(const std::string &filename) -{ - cfg = new tpcrs::Configurator("simple", filename); - simulator = new tpcrs::Simulator(*cfg); -} diff --git a/simulation/g4simulation/tpcresponse/TpcRS.h b/simulation/g4simulation/tpcresponse/TpcRS.h deleted file mode 100644 index 0039a8a046..0000000000 --- a/simulation/g4simulation/tpcresponse/TpcRS.h +++ /dev/null @@ -1,71 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef TPCRS_H -#define TPCRS_H - -#include - -//#if defined(__CLING__) -//namespace tpcrs { -//template< typename Base_t, typename Chair_t, typename Struct_t > -// std::string ConfigStruct< Base_t, Chair_t, Struct_t >::name{}; -//} -//#endif -#include - -#include -#include - -class PHCompositeNode; - -class TpcRS : public SubsysReco -{ - public: - TpcRS(const std::string &name = "TpcRS"); - - virtual ~TpcRS(); - - /** Called during initialization. - Typically this is where you can book histograms, and e.g. - register them to Fun4AllServer (so they can be output to file - using Fun4AllServer::dumpHistos() method). - */ - int Init(PHCompositeNode *topNode) override; - - /** Called for first event when run number is known. - Typically this is where you may want to fetch data from - database, because you know the run number. A place - to book histograms which have to know the run number. - */ - int InitRun(PHCompositeNode *topNode) override; - - /** Called for each event. - This is where you do the real work. - */ - int process_event(PHCompositeNode *topNode) override; - - /// Clean up internals after each event. - int ResetEvent(PHCompositeNode *topNode) override; - - /// Called at the end of each run. - int EndRun(const int runnumber) override; - - /// Called at the end of all processing. - int End(PHCompositeNode *topNode) override; - - /// Reset - int Reset(PHCompositeNode * /*topNode*/) override; - - void Print(const std::string &what = "ALL") const override; - - void SetupConfigurator(const std::string &filename); - - private: - tpcrs::Configurator *cfg = nullptr; - tpcrs::Simulator *simulator = nullptr; - std::vector simu_hits; - std::vector dist_hits; - std::vector digi_hits; -}; - -#endif // TPCRS_H diff --git a/simulation/g4simulation/tpcresponse/autogen.sh b/simulation/g4simulation/tpcresponse/autogen.sh deleted file mode 100755 index dea267bbfd..0000000000 --- a/simulation/g4simulation/tpcresponse/autogen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) - -$srcdir/configure "$@" diff --git a/simulation/g4simulation/tpcresponse/configure.ac b/simulation/g4simulation/tpcresponse/configure.ac deleted file mode 100644 index 82f255e112..0000000000 --- a/simulation/g4simulation/tpcresponse/configure.ac +++ /dev/null @@ -1,16 +0,0 @@ -AC_INIT(tpcresponse,[1.00]) -AC_CONFIG_SRCDIR([configure.ac]) - -AM_INIT_AUTOMAKE -AC_PROG_CXX(CC g++) - -LT_INIT([disable-static]) - -dnl no point in suppressing warnings people should -dnl at least see them, so here we go for g++: -Wall -if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra" -fi - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT From e089e2d698a2b1554ea6e401867fc94770ac00cc Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 12 Apr 2023 11:20:39 -0400 Subject: [PATCH 208/468] save state at calo radius --- offline/packages/trackreco/PHActsTrackProjection.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrackProjection.cc b/offline/packages/trackreco/PHActsTrackProjection.cc index b9263c2001..288554242a 100644 --- a/offline/packages/trackreco/PHActsTrackProjection.cc +++ b/offline/packages/trackreco/PHActsTrackProjection.cc @@ -147,8 +147,8 @@ void PHActsTrackProjection::updateSvtxTrack( { float pathlength = parameters.first / Acts::UnitConstants::cm; auto params = parameters.second; - - SvtxTrackState_v1 out(pathlength); + float calorad = m_caloRadii.find(m_caloTypes.at(caloLayer))->second; + SvtxTrackState_v1 out(calorad); auto projectionPos = params.position(m_tGeometry->geometry().getGeoContext()); const auto momentum = params.momentum(); @@ -162,7 +162,7 @@ void PHActsTrackProjection::updateSvtxTrack( if (Verbosity() > 1) { std::cout << "Adding track state for caloLayer " << caloLayer - << " with position " << projectionPos.transpose() << std::endl; + << " at pathlength " << pathlength << " with position " << projectionPos.transpose() << std::endl; } ActsTransformations transformer; From d950dac3e1f12f01f471dbe3ccf0b8dc8017b6b9 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 12 Apr 2023 11:59:15 -0400 Subject: [PATCH 209/468] Fixed cluster residual errors in local frame. --- .../HelicalFitter.cc | 227 +++++++----------- .../TrackerMillepedeAlignment/HelicalFitter.h | 7 +- 2 files changed, 93 insertions(+), 141 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 9c16980468..1fab941148 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -172,7 +172,7 @@ int HelicalFitter::process_event(PHCompositeNode*) Surface surf = _tGeometry->maps().getSurface(cluskey, cluster); Acts::Vector3 fitpoint = get_helix_surface_intersection(surf, fitpars, global); - std::cout << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl; + //std::cout << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl; // fitpoint is the point where the helical fit intersects the plane of the surface // this is what we need to get the residuals @@ -190,72 +190,49 @@ int HelicalFitter::process_event(PHCompositeNode*) << " cluster local residual x " << residual(0) << " cluster local residual y " < 2) + if(Verbosity() > 1) { - if(layer < 2) + if(layer < 7) { - std::cout << " Global residuals: layer " << layer << " phi " << phi - << " dx " << global(0) - fitpoint(0) - << " dy " << global(1) - fitpoint(1) - << std::endl; - /* - Acts::Vector3 pca = TrackFitUtils::get_helix_pca(fitpars, global); - std::cout << " layer " << layer << " phi " << phi - << " dx " << global(0) - pca(0) - << " dy " << global(1) - pca(1) - << std::endl; - */ - /* - // check - float phirel = atan2( (global(0) - fitpars[1]), (global(1) - fitpars[2])); - float pdist = sqrt( pow(global(0) - fitpars[1], 2) + pow(global(1) - fitpars[2], 2)); - float pcadist = sqrt( pow(fitpoint(0) - fitpars[1], 2) + pow(fitpoint(1) - fitpars[2], 2)); - std::cout << " helix fitpoint:layer " << layer << " phi " << phi << " phirel " << phirel << " pdist " << pdist << " pcadist " << pcadist - << " R " << fitpars[0] << std::endl; - */ + std::cout << "Local residuals: layer " << layer << " phi " << phi << " dx " << residual(0) << " dy " << residual(1) << std::endl; } } // need standard deviation of measurements - Acts::Vector3 clus_sigma = getClusterError(cluster, cluskey, global); - if(isnan(clus_sigma(0)) || isnan(clus_sigma(1)) || isnan(clus_sigma(2))) { continue; } + Acts::Vector2 clus_sigma = getClusterError(cluster, cluskey, global); + if(isnan(clus_sigma(0)) || isnan(clus_sigma(1))) { continue; } int glbl_label[NGL]; getGlobalLabels(surf, glbl_label); // these depend on the sensor grouping - float lcl_derivative[NLC]; - float glbl_derivative[NGL]; + // These derivatives are for the local parameters // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); + float lcl_derivative[NLC]; + float glbl_derivative[NGL]; + // Add the measurement separately for each coordinate direction to Mille // set the derivatives non-zero only for parameters we want to be optimized + // local parameter numbering is arbitrary: + // using 0=x0, 1=y0, 2=z0, 3=R, 4=zslope getLocalDerivativesX(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative); getGlobalDerivativesX(angleDerivs, translDerivs, glbl_derivative, layer); - if(Verbosity() > 3) + if(Verbosity() > 1) { std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} - /* - getLocalDerivativesY(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative); - getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); - if(Verbosity() > 3) - { std::cout << "layer " << layer << " Y buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } - if( !isnan(residual(1)) && clus_sigma(1) < 1.0) // discards crazy clusters - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} - */ - unsigned int trkrid = TrkrDefs::getTrkrId(cluskey); getLocalDerivativesZ(fitpoint, fitpars, lcl_derivative); getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); - if(Verbosity() > 3) - { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(2, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } - if(!isnan(residual(1)) && clus_sigma(2) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(2));} + if(Verbosity() > 1) + { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } + if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) + {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} } @@ -282,7 +259,7 @@ Acts::Vector3 HelicalFitter::get_helix_surface_intersection(Surface surf, std::v Acts::Vector3 pca = line.first; Acts::Vector3 tangent = line.second; - std::cout << " pca: " << pca(0) << " " << pca(1) << " " << pca(2) << " " << std::endl; + // std::cout << " pca: " << pca(0) << " " << pca(1) << " " << pca(2) << " " << std::endl; Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal); @@ -301,9 +278,9 @@ Acts::Vector3 HelicalFitter::get_line_plane_intersection(Acts::Vector3 PCA, Acts // The solution is: float d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal); Acts::Vector3 intersection = PCA + d * tangent; - std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; - std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; - std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; + //std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; + //std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; + //std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; return intersection; } @@ -426,14 +403,19 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac { std::vector derivs_vector; + unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); + unsigned int layer = TrkrDefs::getLayer(cluster_key); + + auto x = cluster->getLocalX() * 10; // mm + auto z = cluster->getLocalY() * 10; + if(trkrId == TrkrDefs::tpcId) { z = convertTimeToZ(cluster_key, cluster); } + float y = 0.0; // y is unused in local coordinates + // Make a transform that applies small translations in the surface frame for(unsigned int itrans = 0; itrans < 3; ++itrans) { // creates transform that adds a perturbation translation along one axis, uses it to estimate derivative wrt perturbation translation - unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); - unsigned int layer = TrkrDefs::getLayer(cluster_key); - Acts::Vector3 derivs(0,0,0); Eigen::Vector3d theseTransl(0,0,0); theseTransl[itrans] = sensorTransl[itrans]; // set the one we want to be non-zero @@ -449,40 +431,36 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac Acts::Transform3 perturbationTranslation = makePerturbationTranslation(theseTransl); - // transform the cluster local position to global coords with this additional translation added - auto x = cluster->getLocalX() * 10; // mm - auto y = cluster->getLocalY() * 10; - if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } - - Eigen::Vector3d clusterLocalPosition (x,0,y); // follows our convention for local coords - Eigen::Vector3d finalCoords = perturbationTranslation*clusterLocalPosition; // result in mm + Eigen::Vector3d clusterLocalPosition (x,y,z); // follows our convention for local coords, where x and z are non zero + Eigen::Vector3d finalCoords = perturbationTranslation*(clusterLocalPosition * 10.0); // clusterLocalPosition and result both in mm finalCoords /= 10.0; // convert mm back to cm // have to add corrections for TPC clusters after transformation to global // if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } - // note that x and y cancel out here + // note that x, y and z cancel out here if(ip == 0) { keeper(0) = (finalCoords(0) - x); - keeper(1) = 0; - keeper(2) = (finalCoords(2) - y); + keeper(1) = (finalCoords(1) - y); + keeper(2) = (finalCoords(2) - z); } else { keeper(0) -= (finalCoords(0) - x); - keeper(1) -= 0; - keeper(2) -= (finalCoords(2) - y); + keeper(1) -= (finalCoords(1) - y); + keeper(2) -= (finalCoords(2) - z); } if(Verbosity() > 5) { - std::cout << " AlignmentTranslationsDerivs: finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " - << finalCoords(1) << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) - << " global(2) " << global(2) << std::endl; + std::cout << " AlignmentTranslationsDerivs: finalCoords(0) " << finalCoords(0) << " finalCoords(1) " + << finalCoords(1) << " finalCoords(2) " << finalCoords(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; } + + if(Verbosity() > 20) { std::cout << " global " << global << std::endl; } } // derivs vector contains: @@ -506,16 +484,29 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) { - // Wev want the effect of a small rotation around the relevant axis in the local frame on the local coords + // We want the effect of a small rotation around the relevant axis in the local frame on the local coords std::vector derivs_vector; + // transform the cluster local position using this additional rotation + auto x = cluster->getLocalX(); // cm + auto z = cluster->getLocalY(); + float y = 0; + + unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); + unsigned int layer = TrkrDefs::getLayer(cluster_key); + if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } + + if(Verbosity() > 1) + { + std::cout << " AlignmentAngleDerivs: clusterLocalPosition(0) " << x << " clusterLocalPosition(1) " << y + << " clusterLocalPosition(2) " << z << std::endl; + } + for(unsigned int iangle = 0; iangle < 3; ++iangle) { // creates transform that adds a perturbation rotation around one axis, uses it to estimate derivative wrt perturbation rotation - unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); - unsigned int layer = TrkrDefs::getLayer(cluster_key); Acts::Vector3 derivs(0,0,0); Eigen::Vector3d theseAngles(0,0,0); @@ -531,38 +522,37 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve << " sensorAngles " << theseAngles[0] << " " << theseAngles[1] << " " << theseAngles[2] << std::endl; } Acts::Transform3 perturbationTransformation = makePerturbationTransformation(theseAngles); - - // transform the cluster local position using this additional rotation - auto x = cluster->getLocalX() * 10; // mm - auto y = cluster->getLocalY() * 10; - if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } - Eigen::Vector3d clusterLocalPosition (x,0,y); // our convention, applies until Acts global rotation occurs - Eigen::Vector3d finalLocalPosition = perturbationTransformation*clusterLocalPosition; // result in mm + Eigen::Vector3d clusterLocalPosition (x,0,z); // our convention has (x,z) as local, applies until Acts global rotation occurs + Eigen::Vector3d finalLocalPosition = perturbationTransformation*(clusterLocalPosition * 10.0); // clusterLocalPosition and result both in mm finalLocalPosition /= 10.0; // convert mm back to cm - // have to add corrections for TPC clusters after transformation to global + // Added corrections for TPC clusters after transformation to global // The helical fit is to corrected data, so if we transform back to local, can // we compare with the cluster local? What is needed here for the TPC? - // note that x and y cancel out here + // note that x, y and z cancel out here if(ip == 0) { keeper(0) = (finalLocalPosition(0) - x); - keeper(2) = (finalLocalPosition(2) - y); + keeper(1) = (finalLocalPosition(1) - y); + keeper(2) = (finalLocalPosition(2) - z); } else { keeper(0) -= (finalLocalPosition(0) - x); - keeper(2) -= (finalLocalPosition(2) - y); + keeper(1) -= (finalLocalPosition(1) - y); + keeper(2) -= (finalLocalPosition(2) - z); } if(Verbosity() > 5) { - std::cout << " AlignmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " global(0) " << global(0) << " finalLocalPosition(1) " << finalLocalPosition(1) - << " global(1) " << global(1) << " finalLocalPosition(2) " << finalLocalPosition(2) << " global(2) " << global(2) << std::endl; + std::cout << " AlignmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " finalLocalPosition(1) " << finalLocalPosition(1) + << " finalLocalPosition(2) " << finalLocalPosition(2) << std::endl; std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; } + + if(Verbosity() > 20) { std::cout << " global " << global << std::endl; } } // derivs vector contains: @@ -573,7 +563,8 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve // Average the changes to get the estimate of the derivative derivs(0) = keeper(0) / (2.0 * fabs(theseAngles[iangle])); if( isnan(derivs(0)) ) { derivs(0) = 0; } - derivs(1) = 0.0; // this would be the unused y axis in the local coord frame + derivs(1) = keeper(1) / (2.0 * fabs(theseAngles[iangle])); // this would be the unused y axis in the local coord frame + if( isnan(derivs(1)) ) { derivs(1) = 0; } derivs(2) = keeper(2) / (2.0 * fabs(theseAngles[iangle])); if( isnan(derivs(2)) ) { derivs(2) = 0; } derivs_vector.push_back(derivs); @@ -788,15 +779,14 @@ std::vector HelicalFitter::fitClusters(std::vector& global return TrackFitUtils::fitClusters(global_vec, cluskey_vec); // do helical fit } -Acts::Vector3 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global) +Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global) { - Acts::Vector3 clus_sigma(0,0,0); + Acts::Vector2 clus_sigma(0,0); if(_cluster_version==3) { - clus_sigma(2) = cluster->getZError(); - clus_sigma(0) = cluster->getRPhiError() / sqrt(2); - clus_sigma(1) = cluster->getRPhiError() / sqrt(2); + clus_sigma(1) = cluster->getZError(); + clus_sigma(0) = cluster->getRPhiError(); } else if(_cluster_version==4) { @@ -804,9 +794,8 @@ Acts::Vector3 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu auto para_errors = _ClusErrPara.get_simple_cluster_error(cluster,clusRadius,cluskey); float exy2 = para_errors.first * Acts::UnitConstants::cm2; float ez2 = para_errors.second * Acts::UnitConstants::cm2; - clus_sigma(2) = sqrt(ez2); - clus_sigma(0) = sqrt(exy2 / 2.0); - clus_sigma(1) = sqrt(exy2 / 2.0); + clus_sigma(1) = sqrt(ez2); + clus_sigma(0) = sqrt(exy2); } else if(_cluster_version == 5) { @@ -815,9 +804,8 @@ Acts::Vector3 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,cluskey); double phierror = sqrt(para_errors.first); double zerror = sqrt(para_errors.second); - clus_sigma(2) = zerror; - clus_sigma(0) = phierror/ sqrt(2); - clus_sigma(1) = phierror/ sqrt(2); + clus_sigma(1) = zerror; + clus_sigma(0) = phierror; } return clus_sigma; @@ -831,10 +819,10 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A float x = fitpoint_local(0); float y = fitpoint_local(2); - // fitpoint is in global coords, fitpoint local in local coords + // fitpoint is in global coords, fitpoint_local in local coords // local x is unaffected by the z fit - // we only need to consider the circle fit paramaters - // Do these numerically + // We only need to consider the circle fit paramaters + // Do these numerically // dx/dradius // increasing R changes both local x and local y very little! @@ -873,41 +861,6 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A lcl_derivative[3] = dx_dr; } -void HelicalFitter::getLocalDerivativesY(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[5]) -{ - float radius = fitpars[0]; - float x0 = fitpars[1]; - float y0 = fitpars[2]; - float x = pca(0); - float y = pca(1); - float dr = 0.2; - float dx0 = 0.05; - - // dy/dradius - float phi = atan2(y-y0, x-x0); - float dy = dr * sin(phi); - float dy_dr = dy/dr; - - // dy/dy0 - float dy_dy0 = 1.0; - - // dy/dx0 - // y = y0 + sqrt(pow(radius, 2) + pow(x-x0, 2)) - float dyx0 = sqrt(pow(radius, 2) + pow(x-x0+dx0, 2)) - - sqrt(pow(radius, 2) + pow(x-x0, 2)); - float dy_dx0 = dyx0/dx0; - - if(Verbosity() > 1) { - std::cout << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; - std::cout << " LclDerivsY: dy_dy0 " << dy_dy0 << " dy_dx0 " << dy_dx0 << " dy_dr " << dy_dr << std::endl; - } - - for(int i=0;i& fitpars, float lcl_derivative[5]) { // the local coord corresponding to z is local-y. @@ -920,32 +873,30 @@ void HelicalFitter::getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vector 1) { std::cout << " x " << fitpoint(0)<<" y "< angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { - // local-x: relevant global pars are alpha, beta, gamma, dx, dy (ipar 0,1,2,3) + // local-x: relevant global pars are alpha, beta, gamma, dx (ipar 0,1,2,3) + // Because x is local x (i.e. r*phi) it is independent of local y (i.e. local z) for(int i=0;i angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { // y - relevant global pars are alpha, beta, gamma, dy (ipar 0,1,2,4) @@ -979,6 +931,7 @@ void HelicalFitter::getGlobalDerivativesY( std::vector angleDeriv } } } +*/ void HelicalFitter::getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { @@ -1003,11 +956,11 @@ void HelicalFitter::getGlobalDerivativesZ( std::vector angleDeriv } } -void HelicalFitter::printBuffers(int index, Acts::Vector2 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) +void HelicalFitter::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) { std::cout << " float buffer: " << " residual " << " " << residual(index); for (int il=0;il& fitpars, float lcl_derivative[5]); - void getLocalDerivativesY(Acts::Vector3& pca, std::vector& fitpars, float lcl_derivative[]); void getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vector& fitpars, float lcl_derivative[5]); void getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); + // void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - void printBuffers(int index, Acts::Vector2 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); + void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); From 8d6bca2e1b45a949a80e76479fbadbdf1deaa57b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 12 Apr 2023 14:56:48 -0400 Subject: [PATCH 210/468] add misalignment parameters --- .../trackreco/PHActsSiliconSeeding.cc | 13 ++++++++-- .../packages/trackreco/PHActsSiliconSeeding.h | 24 ++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index f99f154bb5..b2921d8287 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -170,10 +170,12 @@ GridSeeds PHActsSiliconSeeding::runSeeder(std::vector& spVec) /// Covariance converter functor needed by seed finder auto covConverter = - [=](const SpacePoint& sp, float, float, float) + [=](const SpacePoint& sp, float zAlign, float rAlign, float sigmaError) -> std::pair { Acts::Vector3 position{sp.x(), sp.y(), sp.z()}; - Acts::Vector2 cov{sp.m_varianceR, sp.m_varianceZ}; + Acts::Vector2 cov; + cov[0] = (sp.m_varianceR + rAlign*rAlign) * sigmaError; + cov[1] = (sp.m_varianceZ + zAlign*zAlign) * sigmaError; return std::make_pair(position, cov); }; @@ -729,6 +731,13 @@ Acts::SeedFinderConfig PHActsSiliconSeeding::configureSeeder() /// Maximum impact parameter must be smaller than rMin config.impactMax = m_impactMax; + /// Configurations for dealing with misalignment + config.zAlign = m_zalign; + config.rAlign = m_ralign; + config.toleranceParam = m_tolerance; + config.maxPtScattering = m_maxPtScattering; + config.sigmaError = m_sigmaError; + return config; } diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index 4b0a858351..87bd6c6366 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -85,6 +85,20 @@ class PHActsSiliconSeeding : public SubsysReco {m_gridFactor = gridFactor;} void sigmaScattering(const float sigma) { m_sigmaScattering = sigma; } + void maxPtScattering(const float pt) + { m_maxPtScattering = pt; } + void sigmaError(const float sigma) + { m_sigmaError = sigma; } + void zalign(const float z) + { m_zalign = z; } + void ralign(const float r) + { m_ralign = r; } + void tolerance(const float tolerance) + { m_tolerance = tolerance; } + void helixcut(const float cut) + { m_helixcut = cut; } + + /// A function to run the seeder with large (true) /// or small (false) grid spacing void largeGridSpacing(const bool spacing); @@ -154,7 +168,6 @@ class PHActsSiliconSeeding : public SubsysReco /// MVTX can only have the middle layer be the middle hit int m_maxSeedsPerSpM = 1; - float m_sigmaScattering = 5.; /// Limiting location of measurements (e.g. detector constraints) /// We limit to the MVTX float m_rMax = 200. * Acts::UnitConstants::mm; @@ -162,6 +175,15 @@ class PHActsSiliconSeeding : public SubsysReco float m_zMax = 300. * Acts::UnitConstants::mm; float m_zMin = -300. * Acts::UnitConstants::mm; + /// misalignment parameters + float m_helixcut = 1; + float m_tolerance = 1.1 * Acts::UnitConstants::mm; + float m_ralign = 0; + float m_zalign = 0; + float m_maxPtScattering = 10; + float m_sigmaScattering = 5.; + float m_sigmaError = 5; + /// Value tuned to provide as large of phi bins as possible. /// Increases the secondary finding efficiency float m_gridFactor = 2.3809; From dbcb5f91974f6f85dda0ff0f1e6a56edfbf7ef27 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 12 Apr 2023 16:09:12 -0400 Subject: [PATCH 211/468] Cleaned the memory leak --- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index c3e974baf8..bda336a1bb 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -72,6 +72,8 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) PHG4TpcPadPlaneReadout::~PHG4TpcPadPlaneReadout() { gsl_rng_free(RandomGenerator); + delete h_gain[0]; + delete h_gain[1]; } int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, PHG4TpcCylinderGeomContainer *seggeo) @@ -749,13 +751,17 @@ void PHG4TpcPadPlaneReadout::ReadGain() { // Reading TPC Gain Maps from the file if(m_flagToUseGain==1){ - std::string gain_maps_filename = std::string(getenv("CALIBRATIONROOT"))+std::string("/TPC/GainMaps/TPCGainMaps.root"); - TFile *fileGain = TFile::Open(gain_maps_filename.c_str(), "READ"); - h_gain[0] = (TH2F*)fileGain->Get("RadPhiPlot0")->Clone(); - h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); - h_gain[0]->SetDirectory(0); - h_gain[1]->SetDirectory(0); - fileGain->Close(); + char *calibrationsroot = getenv("CALIBRATIONROOT"); + if (calibrationsroot != nullptr) + { + std::string gain_maps_filename = std::string(calibrationsroot)+std::string("/TPC/GainMaps/TPCGainMaps.root"); + TFile *fileGain = TFile::Open(gain_maps_filename.c_str(), "READ"); + h_gain[0] = (TH2F*)fileGain->Get("RadPhiPlot0")->Clone(); + h_gain[1] = (TH2F*)fileGain->Get("RadPhiPlot1")->Clone(); + h_gain[0]->SetDirectory(nullptr); + h_gain[1]->SetDirectory(nullptr); + fileGain->Close(); + } } } void PHG4TpcPadPlaneReadout::SetDefaultParameters() From 6e09a59f8ad3357da50f5597fb8f210ff7da63ec Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 12 Apr 2023 19:29:10 -0400 Subject: [PATCH 212/468] compiling and working version of sphenixnpc --- offline/database/sphenixnpc/sphenixnpc.cc | 44 +++++++++++------------ offline/database/sphenixnpc/sphenixnpc.h | 23 ++++++------ 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index cdee4e2111..f057c19b23 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -8,7 +8,7 @@ sphenixnpc *sphenixnpc::instance(const std::string &globaltag) { __instance = new sphenixnpc(); } - __instance->setGlobalTag(globaltag); + __instance->cache_set_GlobalTag(globaltag); return __instance; } @@ -17,16 +17,26 @@ sphenixnpc::~sphenixnpc() __instance = nullptr; } -nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) +int sphenixnpc::createGlobalTag(const std::string &tagname) { setGlobalTag(tagname); - return nopayloadclient::Client::createGlobalTag(); + nlohmann::json result = nopayloadclient::Client::createGlobalTag(); + if (Verbosity()) + { + std::cout << result << std::endl; + } + return 0; } -nlohmann::json sphenixnpc::deleteGlobalTag(const std::string &tagname) +int sphenixnpc::deleteGlobalTag(const std::string &tagname) { setGlobalTag(tagname); - return nopayloadclient::Client::deleteGlobalTag(); + nlohmann::json result = nopayloadclient::Client::deleteGlobalTag(); + if (Verbosity()) + { + std::cout << result << std::endl; + } + return 0; } nlohmann::json sphenixnpc::getUrlDict(long long iov) @@ -44,24 +54,12 @@ nlohmann::json sphenixnpc::get(std::string pl_type, long long iov) } if (not url_dict_.contains(pl_type)) { - return DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); + return nopayloadclient::DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); } return makeResp(url_dict_[pl_type]); } -nlohmann::json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, - long long iov_start) -{ - return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); -} - -nlohmann::json sphenixnpc::insertPayload(std::string pl_type, std::string file_url, - long long iov_start, long long iov_end) -{ - return nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); -} - -nlohmann::json sphenixnpc::setGlobalTag(std::string name) +nlohmann::json sphenixnpc::cache_set_GlobalTag(std::string name) { if (name != m_CachedGlobalTag) { @@ -83,9 +81,9 @@ std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov return result.at("msg"); } -int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start) +int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) { - nlohmann::json ret = insertPayload(payloadtype, fname, iov_start); + nlohmann::json ret = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); if (Verbosity()) { std::cout << ret << std::endl; @@ -93,9 +91,9 @@ int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &f return 0; } -int sphenixnpc::insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start, uint64_t iov_end) +int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) { - nlohmann::json ret = insertPayload(payloadtype, fname, iov_start, iov_end); + nlohmann::json ret = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); if (Verbosity()) { std::cout << ret << std::endl; diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 225ebc6425..27967ca93e 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -1,10 +1,7 @@ #ifndef SPHENIXNPC_SPHENIXNPC_H #define SPHENIXNPC_SPHENIXNPC_H -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include -#pragma GCC diagnostic pop #include @@ -13,22 +10,24 @@ class sphenixnpc : public nopayloadclient::Client { public: + using nopayloadclient::Client::getUrlDict; + using nopayloadclient::Client::createGlobalTag; + using nopayloadclient::Client::deleteGlobalTag; + using nopayloadclient::Client::setGlobalTag; + static sphenixnpc *instance(const std::string &globaltag = "NONE"); ~sphenixnpc(); nlohmann::json getUrlDict(long long iov); - nlohmann::json createGlobalTag(const std::string &tagname); + int createGlobalTag(const std::string &tagname); - nlohmann::json deleteGlobalTag(const std::string &); nlohmann::json get(std::string pl_type, long long iov); - nlohmann::json insertPayload(std::string pl_type, std::string file_url, - long long iov_start); - nlohmann::json insertPayload(std::string pl_type, std::string file_url, - long long iov_start, long long iov_end) override; - nlohmann::json setGlobalTag(std::string name) override; + nlohmann::json cache_set_GlobalTag(std::string name); nlohmann::json clearCache() override; std::string getCalibrationFile(const std::string &type, uint64_t iov); - int insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start); - int insertcalib(const std::string &payloadtype, const std::string &fname, uint64_t iov_start, uint64_t iov_end); + int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); + int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); + int deleteGlobalTag(const std::string &); + void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } From 5ab19732837b8a3dce8b91664badc7cb46d35a32 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 12 Apr 2023 19:45:06 -0400 Subject: [PATCH 213/468] clang-tidy, clang-format to trigger jenkins --- offline/database/sphenixnpc/sphenixnpc.cc | 9 ++++++--- offline/database/sphenixnpc/sphenixnpc.h | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index f057c19b23..a6572e66a2 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -44,12 +44,15 @@ nlohmann::json sphenixnpc::getUrlDict(long long iov) return nopayloadclient::Client::getUrlDict(0, iov); } -nlohmann::json sphenixnpc::get(std::string pl_type, long long iov) +nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) { if (url_dict_.is_null()) { nlohmann::json resp = getUrlDict(iov); - if (resp["code"] != 0) return resp; + if (resp["code"] != 0) + { + return resp; + } url_dict_ = resp["msg"]; } if (not url_dict_.contains(pl_type)) @@ -59,7 +62,7 @@ nlohmann::json sphenixnpc::get(std::string pl_type, long long iov) return makeResp(url_dict_[pl_type]); } -nlohmann::json sphenixnpc::cache_set_GlobalTag(std::string name) +nlohmann::json sphenixnpc::cache_set_GlobalTag(const std::string &name) { if (name != m_CachedGlobalTag) { diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 27967ca93e..557c5240d2 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -10,9 +10,9 @@ class sphenixnpc : public nopayloadclient::Client { public: - using nopayloadclient::Client::getUrlDict; using nopayloadclient::Client::createGlobalTag; using nopayloadclient::Client::deleteGlobalTag; + using nopayloadclient::Client::getUrlDict; using nopayloadclient::Client::setGlobalTag; static sphenixnpc *instance(const std::string &globaltag = "NONE"); @@ -20,8 +20,8 @@ class sphenixnpc : public nopayloadclient::Client nlohmann::json getUrlDict(long long iov); int createGlobalTag(const std::string &tagname); - nlohmann::json get(std::string pl_type, long long iov); - nlohmann::json cache_set_GlobalTag(std::string name); + nlohmann::json get(const std::string &pl_type, long long iov); + nlohmann::json cache_set_GlobalTag(const std::string &name); nlohmann::json clearCache() override; std::string getCalibrationFile(const std::string &type, uint64_t iov); int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); From 3d7f1d8712f846ff16177e759ecdb84758e2f5c5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 13 Apr 2023 14:23:22 -0400 Subject: [PATCH 214/468] use standard propagator machinery --- offline/packages/tpccalib/Makefile.am | 1 + offline/packages/tpccalib/PHTpcResiduals.cc | 59 +++++---------------- offline/packages/tpccalib/PHTpcResiduals.h | 8 --- 3 files changed, 15 insertions(+), 53 deletions(-) diff --git a/offline/packages/tpccalib/Makefile.am b/offline/packages/tpccalib/Makefile.am index 14485cca1b..34d3fc4182 100644 --- a/offline/packages/tpccalib/Makefile.am +++ b/offline/packages/tpccalib/Makefile.am @@ -30,6 +30,7 @@ libtpccalib_la_LIBADD = \ -lg4detectors_io \ -ltrack_io \ -ltrackbase_historic_io \ + -ltrack_reco \ -ltpc_io pkginclude_HEADERS = \ diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 776fa7c416..66d4fdd308 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -223,8 +225,8 @@ bool PHTpcResiduals::checkTrack(SvtxTrack* track) const Acts::BoundTrackParameters PHTpcResiduals::makeTrackParams(SvtxTrack* track) const { Acts::Vector3 momentum(track->get_px(), - track->get_py(), - track->get_pz()); + track->get_py(), + track->get_pz()); double trackQ = track->get_charge() * Acts::UnitConstants::e; double p = track->get_p(); @@ -255,17 +257,17 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << " position: (" << track->get_x() << ", " << track->get_y() << ", " << track->get_z() << ")" << std::endl; } - + ActsPropagator propagator; + // create ACTS parameters from track parameters at origin auto trackParams = makeTrackParams(track); // store crossing. It is used in calculating cluster's global position m_crossing = track->get_crossing(); assert( m_crossing != SHRT_MAX ); - + for( const auto& cluskey:get_cluster_keys( track ) ) { - // increment counter ++m_total_clusters; @@ -275,10 +277,10 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) const auto cluster = m_clusterContainer->findCluster(cluskey); const auto surface = m_tGeometry->maps().getSurface( cluskey, cluster ); - const auto result = propagateTrackState(trackParams, surface); + auto result = propagator.propagateTrack(trackParams, surface); // skip if propagation failed - if(!result) + if(!result.ok()) { if( Verbosity() > 1 ) { @@ -298,7 +300,9 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) } // get extrapolated track state, convert to sPHENIX and add to track - const auto& [pathLength, trackStateParams] = *result; + auto& [pathLength, trackStateParams] = result.value(); + pathLength /= Acts::UnitConstants::cm; + if(Verbosity() > 1) { std::cout << "PHTpcResiduals::processTrack -" @@ -309,7 +313,8 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << trackStateParams.momentum() << std::endl; } - + + addTrackState( track, cluskey, pathLength, trackStateParams ); // calculate residuals with respect to cluster @@ -486,42 +491,6 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) } -//__________________________________________________________________________________________________________________________________________ -std::optional PHTpcResiduals::propagateTrackState( const Acts::BoundTrackParameters& params, const Surface& surface) const -{ - - - using Stepper = Acts::EigenStepper<>; - using Propagator = Acts::Propagator; - - Stepper stepper(m_tGeometry->geometry().magField); - Acts::Navigator::Config cfg{m_tGeometry->geometry().tGeometry}; - Acts::Navigator navigator(cfg); - Propagator propagator(stepper, navigator); - - Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if(Verbosity() > 10) - logLevel = Acts::Logging::VERBOSE; - - auto logger = Acts::getDefaultLogger("PHTpcResiduals", logLevel); - - Acts::PropagatorOptions<> options(m_tGeometry->geometry().getGeoContext(), - m_tGeometry->geometry().magFieldContext, - Acts::LoggerWrapper{*logger}); - - auto result = propagator.propagate(params, *surface, options); - - if(result.ok()) - { - const Acts::BoundTrackParameters params = *result.value().endParameters; - double pathlength = result.value().pathLength / Acts::UnitConstants::cm; - // return both path length and extrapolated parameters - return std::make_pair( pathlength, params ); - } else { - return std::nullopt; - } -} - //_______________________________________________________________________________________________________ void PHTpcResiduals::addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, float pathlength, const Acts::BoundTrackParameters& params ) { diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 2c5ff6513d..76de6976d8 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -112,14 +112,6 @@ class PHTpcResiduals : public SubsysReco /// fill track state from bound track parameters void addTrackState( SvtxTrack* track, TrkrDefs::cluskey key, float pathlength, const Acts::BoundTrackParameters& params ); - /** \brief - * Propagates the silicon+MM track fit to the surface on which - * an available source link in the TPC exists, added from the stub - * matching propagation - * returns the path lenght and the resulting parameters - */ - std::optional propagateTrackState( const Acts::BoundTrackParameters& params, const Surface& surf ) const; - /// Gets distortion cell for identifying bins in TPC int getCell(const Acts::Vector3& loc); From 00200c2113886cf99e0eadbfcff0e0402fd48236 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 13 Apr 2023 15:11:37 -0400 Subject: [PATCH 215/468] remove verbosity --- offline/packages/trackreco/ActsPropagator.cc | 6 +++--- offline/packages/trackreco/PHActsVertexPropagator.cc | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 1ad42c4c73..d04c13ed34 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -79,7 +79,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - Acts::Logging::Level logLevel = Acts::Logging::INFO; + Acts::Logging::Level logLevel = Acts::Logging::FATAL; if (m_verbosity > 3) { logLevel = Acts::Logging::VERBOSE; @@ -123,7 +123,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - Acts::Logging::Level logLevel = Acts::Logging::INFO; + Acts::Logging::Level logLevel = Acts::Logging::FATAL; if (m_verbosity > 3) { logLevel = Acts::Logging::VERBOSE; @@ -162,7 +162,7 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, auto propagator = makeFastPropagator(); - Acts::Logging::Level logLevel = Acts::Logging::INFO; + Acts::Logging::Level logLevel = Acts::Logging::FATAL; if (m_verbosity > 3) { logLevel = Acts::Logging::VERBOSE; diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index a1d30e073f..cab45e31ce 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -81,7 +81,10 @@ int PHActsVertexPropagator::process_event(PHCompositeNode*) } else { - svtxTrack->identify(); + if(Verbosity()>1) + { + svtxTrack->identify(); + } } } } From f28c8ac6ab1a954d31d3be1c361c9fb7d0d3b284 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 13 Apr 2023 17:46:23 -0400 Subject: [PATCH 216/468] new cdb client interface (still rough) --- offline/packages/CaloReco/CaloTowerCalib.cc | 18 +++++++++--------- offline/packages/CaloReco/Makefile.am | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerCalib.cc b/offline/packages/CaloReco/CaloTowerCalib.cc index 1fb87aa684..19c190827c 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.cc +++ b/offline/packages/CaloReco/CaloTowerCalib.cc @@ -19,7 +19,7 @@ #include #include -#include +#include #include //____________________________________________________________________________.. @@ -61,8 +61,8 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) recoConsts *rc = recoConsts::instance(); // place holder rc->set_StringFlag("CDB_GLOBALTAG", "CEMCCalibTest"); - ReadCalib *rb = new ReadCalib(); - std::string calibdir = rb->getCalibrationFile("TestBeginValidity", m_runNumber); + sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); m_detector = "CEMC"; m_DETECTOR = TowerInfoContainer::EMCAL; m_fieldname = "cemc_abscalib_mip"; @@ -80,8 +80,8 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) { recoConsts *rc = recoConsts::instance(); rc->set_StringFlag("CDB_GLOBALTAG", "HCalCalibTest"); - ReadCalib *rb = new ReadCalib(); - std::string calibdir = rb->getCalibrationFile("TestBeginValidity", m_runNumber); + sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); m_detector = "HCALIN"; m_DETECTOR = TowerInfoContainer::HCAL; m_fieldname = "ihcal_abscalib_mip"; @@ -99,8 +99,8 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) { recoConsts *rc = recoConsts::instance(); rc->set_StringFlag("CDB_GLOBALTAG", "HCalCalibTest"); - ReadCalib *rb = new ReadCalib(); - std::string calibdir = rb->getCalibrationFile("TestBeginValidity", m_runNumber); + sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); m_detector = "HCALOUT"; m_DETECTOR = TowerInfoContainer::HCAL; m_fieldname = "ohcal_abscalib_mip"; @@ -119,8 +119,8 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) recoConsts *rc = recoConsts::instance(); // place holder rc->set_StringFlag("CDB_GLOBALTAG", "EPDCalibTest"); - ReadCalib *rb = new ReadCalib(); - std::string calibdir = rb->getCalibrationFile("TestBeginValidity", m_runNumber); + sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); m_detector = "EPD"; m_DETECTOR = TowerInfoContainer::SEPD; m_fieldname = "EPD_abscalib_mip"; diff --git a/offline/packages/CaloReco/Makefile.am b/offline/packages/CaloReco/Makefile.am index 0b7ff200c7..c071c4afc9 100644 --- a/offline/packages/CaloReco/Makefile.am +++ b/offline/packages/CaloReco/Makefile.am @@ -26,6 +26,7 @@ libcalo_reco_la_LIBADD = \ -lg4vertex_io \ -lcalo_io \ -lsph_onnx \ + -lsphenixnpc \ -lcaloCalibDBFile \ -lcdbobjects \ -lphparameter @@ -69,6 +70,7 @@ libcalo_reco_la_SOURCES = \ CaloWaveformFitting.cc \ CaloWaveformProcessing.cc \ CaloTowerBuilder.cc \ + CaloTowerCalib.cc \ RawClusterBuilderGraph.cc \ RawClusterBuilderTopo.cc \ RawClusterBuilderTemplate.cc \ From e518492b7296f8a8e4c94ba46f21f86774034ff1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 13 Apr 2023 21:38:34 -0400 Subject: [PATCH 217/468] trigger jenkins From 8bff3b722f906921cfd3f9315b63031a8f244511 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 13 Apr 2023 21:43:08 -0400 Subject: [PATCH 218/468] trigger jenkins From 64be19cb324ffab09b94ec53613c0fcbec1d05b9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 14 Apr 2023 07:54:29 -0400 Subject: [PATCH 219/468] trigger jenkins From 58706167a49ff7952776808924719d431dd4749f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 14 Apr 2023 09:55:08 -0400 Subject: [PATCH 220/468] trigger jenkins From fad818bbc103d50478e87539f46c2e31c0f3aabe Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 14 Apr 2023 11:00:21 -0400 Subject: [PATCH 221/468] added utility functions to get detector names from hitsetkey --- .../packages/micromegas/MicromegasMapping.cc | 21 +++++++++++++++++++ .../packages/micromegas/MicromegasMapping.h | 8 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index cd46c23727..3e2f1c4787 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -92,3 +92,24 @@ int MicromegasMapping::get_physical_strip( int /*fee_id*/, int channel_id) const return channel_id; } +//____________________________________________________________________________________________________ +std::string MicromegasMapping::get_detname_saclay_from_hitsetkey( TrkrDefs::hitsetkey key ) const +{ + const auto iter = std::find_if( m_detectors.begin(), m_detectors.end(), [key](const DetectorId& detector ) { return detector.m_hitsetkey == key; } ); + if( iter == m_detectors.end() ) + { + std::cout << "MicromegasMapping::get_detname_saclay_from_hitsetkey - invalid key: " << key << std::endl; + return std::string(); + } else return iter->m_detname_saclay; +} + +//____________________________________________________________________________________________________ +std::string MicromegasMapping::get_detname_sphenix_from_hitsetkey( TrkrDefs::hitsetkey key ) const +{ + const auto iter = std::find_if( m_detectors.begin(), m_detectors.end(), [key](const DetectorId& detector ) { return detector.m_hitsetkey == key; } ); + if( iter == m_detectors.end() ) + { + std::cout << "MicromegasMapping::get_detname_sphenix_from_hitsetkey - invalid key: " << key << std::endl; + return std::string(); + } else return iter->m_detname_sphenix; +} diff --git a/offline/packages/micromegas/MicromegasMapping.h b/offline/packages/micromegas/MicromegasMapping.h index 53c007ddbf..21845f0fce 100644 --- a/offline/packages/micromegas/MicromegasMapping.h +++ b/offline/packages/micromegas/MicromegasMapping.h @@ -30,7 +30,7 @@ class MicromegasMapping /** saclay detector name are of type MxxP and MxxZ, with xx the module number */ std::string get_detname_saclay( int /*fee_id*/) const; - /// get detector name (saclay) from fiber_id (fee_id) + /// get detector name (sphenix) from fiber_id (fee_id) /** sphenix detector name are of type SWP, SWZ, etc. */ std::string get_detname_sphenix( int /*fee_id*/) const; @@ -42,6 +42,12 @@ class MicromegasMapping */ int get_physical_strip( int /*fee_id*/, int /*channel_id*/) const; + /// get detector name (sphenix) from hitset key + std::string get_detname_saclay_from_hitsetkey( TrkrDefs::hitsetkey ) const; + + /// get detector name (saclay) from hitset key + std::string get_detname_sphenix_from_hitsetkey( TrkrDefs::hitsetkey ) const; + private: /// contains all relevant detector information From c42bebacf5f18f33aa04585047b0b653fc10dcbc Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 14 Apr 2023 23:36:33 -0400 Subject: [PATCH 222/468] moved max_adc, number of channels per fee and total number of channels to MicromegasDefs --- offline/packages/micromegas/MicromegasDefs.h | 12 ++++++++++++ .../micromegas/MicromegasRawDataCalibration.cc | 13 +++++++------ .../micromegas/MicromegasRawDataCalibration.h | 5 ----- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index 6a903080d1..65f76d6a9f 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -91,6 +91,18 @@ namespace MicromegasDefs s*/ uint8_t getTileId(TrkrDefs::cluskey); + //! number of channels per fee board + static constexpr int m_nchannels_fee = 256; + + //! number of fee boards + static constexpr int m_nfee = 16; + + //! total number of channels + static constexpr int m_nchannels_total = m_nfee*m_nchannels_fee; + + //! max adc value per readout sample + static constexpr int m_max_adc = 1024; + } #endif diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index acb73f95cb..90dcb787b1 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -5,6 +5,7 @@ #include "MicromegasRawDataCalibration.h" #include "MicromegasCalibrationData.h" +#include "MicromegasDefs.h" #include #include @@ -109,7 +110,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) if( piter == m_profile_map.end() || fee < piter->first ) { // create and insert - profile = new TProfile( Form( "h_adc_channel_%i", fee ), "ADC vs channel;channel;adc", m_nchannels_fee, 0, m_nchannels_fee ); + profile = new TProfile( Form( "h_adc_channel_%i", fee ), "ADC vs channel;channel;adc", MicromegasDefs::m_nchannels_fee, 0, MicromegasDefs::m_nchannels_fee ); profile->SetErrorOption( "s" ); m_profile_map.insert( piter, std::make_pair( fee, profile ) ); } else profile = piter->second; @@ -131,7 +132,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) } else { const auto fee_index = iter->second; - const auto channel_index = fee_index*m_nchannels_fee + channel; + const auto channel_index = fee_index*MicromegasDefs::m_nchannels_fee + channel; // loop over samples if( m_h_adc_channel ) @@ -176,9 +177,9 @@ int MicromegasRawDataCalibration::End(PHCompositeNode* /*topNode*/ ) { // create mean and rms histograms auto profile = m_h_adc_channel->ProfileX("h_adc_channel_profx", 1, -1, "s" ); - auto h_pedestal = new TH1F( "h_pedestal", "pedestal vs channel;channel;pedestal (adc)", m_nchannels_total, 0, m_nchannels_total ); - auto h_rms = new TH1F( "h_rms", "rms vs channel;channel;RMS (adc)", m_nchannels_total, 0, m_nchannels_total ); - for( int i =0; iSetBinContent( i+1, profile->GetBinContent(i+1) ); h_rms->SetBinContent(i+1, profile->GetBinError(i+1) ); @@ -202,5 +203,5 @@ void MicromegasRawDataCalibration::create_histograms() m_histogramfile->cd(); m_h_fee_id = new TH1I( "h_fee_id", "FEE id;Fee id;entries", 10, 0, 10 ); - m_h_adc_channel = new TH2I( "h_adc_channel", "ADC vs channel;channel;adc", m_nchannels_total, 0, m_nchannels_total, m_max_adc, 0, m_max_adc ); + m_h_adc_channel = new TH2I( "h_adc_channel", "ADC vs channel;channel;adc", MicromegasDefs::m_nchannels_total, 0, MicromegasDefs::m_nchannels_total, MicromegasDefs::m_max_adc, 0, MicromegasDefs::m_max_adc ); } diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.h b/offline/packages/micromegas/MicromegasRawDataCalibration.h index 1120747ce1..46b620d6ef 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.h +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.h @@ -57,11 +57,6 @@ class MicromegasRawDataCalibration : public SubsysReco /// create evaluation histograms void create_histograms(); - - static constexpr int m_nchannels_fee = 256; - static constexpr int m_nfee = 16; - static constexpr int m_nchannels_total = m_nfee*m_nchannels_fee; - static constexpr int m_max_adc = 1024; /// min sample for noise estimation int m_sample_min = 0; From d7272f25a384fa961cfad45d3766a262e141c706 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 14 Apr 2023 23:37:00 -0400 Subject: [PATCH 223/468] added mapping from channel id to physical strip id. How the mapping is constructed from various sources is documented in the code --- .../packages/micromegas/MicromegasMapping.cc | 364 +++++++++++++++++- .../packages/micromegas/MicromegasMapping.h | 12 + 2 files changed, 369 insertions(+), 7 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index 3e2f1c4787..99ede735d7 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -7,6 +7,64 @@ #include "MicromegasDefs.h" #include +#include + +namespace +{ + + class mec8_channel_id + { + public: + + /* + * 0 or 1, corresponding to cable1 and cable 2 as defined by Takao in + * https://indico.bnl.gov/event/18458/contributions/73400/attachments/46043/77969/FEE_to_MEC_map_Feb17_2023.xlsx + */ + int m_cable_id = 0; + + /* + * 0 or 1, corresponding to j2 or j3 in transition board drawing in + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png + * and as defined by Takao in + * https://indico.bnl.gov/event/18458/contributions/73400/attachments/46043/77969/FEE_to_MEC_map_Feb17_2023.xlsx + */ + int m_connector_id = 0; + + /* + * 1 to 70 as defined in + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png + */ + int m_channel_id = 0; + + // constructor + mec8_channel_id( int cable_id, int connector_id, int channel_id ): + m_cable_id( cable_id ), + m_connector_id( connector_id ), + m_channel_id( channel_id ) + {} + + }; + + // equal to operator + inline bool operator == (const mec8_channel_id& lhs, const mec8_channel_id& rhs ) + { + return + lhs.m_cable_id == rhs.m_cable_id && + lhs.m_connector_id == rhs.m_connector_id && + lhs.m_channel_id == rhs.m_channel_id; + } + + // less than operator + inline bool operator < (const mec8_channel_id& lhs, const mec8_channel_id& rhs ) + { + if( lhs.m_cable_id != rhs.m_cable_id ) return lhs.m_cable_id < rhs.m_cable_id; + if( lhs.m_connector_id != rhs.m_connector_id ) return lhs.m_connector_id < rhs.m_connector_id; + return lhs.m_channel_id < rhs.m_channel_id; + } + +} //____________________________________________________________________________________________________ MicromegasMapping::MicromegasMapping(): @@ -36,9 +94,13 @@ m_detectors( { { std::cout << "MicromegasMapping::MicromegasMapping." << std::endl; - /// fill detector map from vector + // fill detector map from vector for( const auto& detector_id:m_detectors ) { m_detector_map.emplace( detector_id.m_fee_id, detector_id ); } + + // construct channel mapping + construct_channel_mapping(); + } //____________________________________________________________________________________________________ @@ -83,13 +145,29 @@ std::string MicromegasMapping::get_detname_sphenix( int fee_id ) const } //____________________________________________________________________________________________________ -int MicromegasMapping::get_physical_strip( int /*fee_id*/, int channel_id) const +int MicromegasMapping::get_physical_strip( int fee_id, int channel_id) const { - /* - * this maps channel id (0-255) on a given FEE board, to physical strip number in the detector - * Just a placeholder for now. We just return the same index. - */ - return channel_id; + // bound check + if( channel_id < 0 || channel_id >= MicromegasDefs::m_nchannels_fee ) + { + std::cout << "MicromegasMapping::get_physical_strip - invalid channel: " << channel_id << std::endl; + return -1; + } + + // get hitsetkey and orientation + const auto hitsetkey = get_hitsetkey(fee_id); + const auto segmentation_type = MicromegasDefs::getSegmentationType(hitsetkey); + switch (segmentation_type) + { + case MicromegasDefs::SegmentationType::SEGMENTATION_Z: + return m_fee_to_strip_mapping_z[channel_id]; + + case MicromegasDefs::SegmentationType::SEGMENTATION_PHI: + return m_fee_to_strip_mapping_phi[channel_id]; + } + + // never reached + return -1; } //____________________________________________________________________________________________________ @@ -113,3 +191,275 @@ std::string MicromegasMapping::get_detname_sphenix_from_hitsetkey( TrkrDefs::hit return std::string(); } else return iter->m_detname_sphenix; } + +//____________________________________________________________________________________________________ +void MicromegasMapping::construct_channel_mapping() +{ + + /* + * map channel id on FEE board (0-255) to mec8 connector and channel + * there are 2 cables (left and right) per FEE board + * each cable has two MEC8 connector + * on each MEC8 connector, channel 1,2, 35, 36, 69 and 70 are connected to the ground + * the other 64 channels are signals + */ + // source: https://indico.bnl.gov/event/18458/contributions/73400/attachments/46043/77969/FEE_to_MEC_map_Feb17_2023.xlsx + std::array fee_to_mec8_mapping = + {{ + {0,0,34}, {0,0,33}, {0,0,32}, {0,0,31}, {0,0,30}, {0,0,29}, {0,0,28}, {0,0,27}, + {0,0,26}, {0,0,25}, {0,0,24}, {0,0,23}, {0,0,22}, {0,0,21}, {0,0,20}, {0,0,19}, + {0,0,18}, {0,0,17}, {0,0,16}, {0,0,15}, {0,0,14}, {0,0,13}, {0,0,12}, {0,0,11}, + {0,0,10}, {0,0,9}, {0,0,8}, {0,0,7}, {0,0,6}, {0,0,5}, {0,0,4}, {0,0,3}, + + {0,0,68}, {0,0,67}, {0,0,66}, {0,0,65}, {0,0,64}, {0,0,63}, {0,0,62}, {0,0,61}, + {0,0,60}, {0,0,59}, {0,0,58}, {0,0,57}, {0,0,56}, {0,0,55}, {0,0,54}, {0,0,53}, + {0,0,52}, {0,0,51}, {0,0,50}, {0,0,49}, {0,0,48}, {0,0,47}, {0,0,46}, {0,0,45}, + {0,0,44}, {0,0,43}, {0,0,42}, {0,0,41}, {0,0,40}, {0,0,39}, {0,0,38}, {0,0,37}, + + {0,1,34}, {0,1,33}, {0,1,32}, {0,1,31}, {0,1,30}, {0,1,29}, {0,1,28}, {0,1,27}, + {0,1,26}, {0,1,25}, {0,1,24}, {0,1,23}, {0,1,22}, {0,1,21}, {0,1,20}, {0,1,19}, + {0,1,18}, {0,1,17}, {0,1,16}, {0,1,15}, {0,1,14}, {0,1,13}, {0,1,12}, {0,1,11}, + {0,1,10}, {0,1,9}, {0,1,8}, {0,1,7}, {0,1,6}, {0,1,5}, {0,1,4}, {0,1,3}, + + {0,1,68}, {0,1,67}, {0,1,66}, {0,1,65}, {0,1,64}, {0,1,63}, {0,1,62}, {0,1,61}, + {0,1,60}, {0,1,59}, {0,1,58}, {0,1,57}, {0,1,56}, {0,1,55}, {0,1,54}, {0,1,53}, + {0,1,52}, {0,1,51}, {0,1,50}, {0,1,49}, {0,1,48}, {0,1,47}, {0,1,46}, {0,1,45}, + {0,1,44}, {0,1,43}, {0,1,42}, {0,1,41}, {0,1,40}, {0,1,39}, {0,1,38}, {0,1,37}, + + {1,0,34}, {1,0,33}, {1,0,32}, {1,0,31}, {1,0,30}, {1,0,29}, {1,0,28}, {1,0,27}, + {1,0,26}, {1,0,25}, {1,0,24}, {1,0,23}, {1,0,22}, {1,0,21}, {1,0,20}, {1,0,19}, + {1,0,18}, {1,0,17}, {1,0,16}, {1,0,15}, {1,0,14}, {1,0,13}, {1,0,12}, {1,0,11}, + {1,0,10}, {1,0,9}, {1,0,8}, {1,0,7}, {1,0,6}, {1,0,5}, {1,0,4}, {1,0,3}, + + {1,0,68}, {1,0,67}, {1,0,66}, {1,0,65}, {1,0,64}, {1,0,63}, {1,0,62}, {1,0,61}, + {1,0,60}, {1,0,59}, {1,0,58}, {1,0,57}, {1,0,56}, {1,0,55}, {1,0,54}, {1,0,53}, + {1,0,52}, {1,0,51}, {1,0,50}, {1,0,49}, {1,0,48}, {1,0,47}, {1,0,46}, {1,0,45}, + {1,0,44}, {1,0,43}, {1,0,42}, {1,0,41}, {1,0,40}, {1,0,39}, {1,0,38}, {1,0,37}, + + {1,1,34}, {1,1,33}, {1,1,32}, {1,1,31}, {1,1,30}, {1,1,29}, {1,1,28}, {1,1,27}, + {1,1,26}, {1,1,25}, {1,1,24}, {1,1,23}, {1,1,22}, {1,1,21}, {1,1,20}, {1,1,19}, + {1,1,18}, {1,1,17}, {1,1,16}, {1,1,15}, {1,1,14}, {1,1,13}, {1,1,12}, {1,1,11}, + {1,1,10}, {1,1,9}, {1,1,8}, {1,1,7}, {1,1,6}, {1,1,5}, {1,1,4}, {1,1,3}, + + {1,1,68}, {1,1,67}, {1,1,66}, {1,1,65}, {1,1,64}, {1,1,63}, {1,1,62}, {1,1,61}, + {1,1,60}, {1,1,59}, {1,1,58}, {1,1,57}, {1,1,56}, {1,1,55}, {1,1,54}, {1,1,53}, + {1,1,52}, {1,1,51}, {1,1,50}, {1,1,49}, {1,1,48}, {1,1,47}, {1,1,46}, {1,1,45}, + {1,1,44}, {1,1,43}, {1,1,42}, {1,1,41}, {1,1,40}, {1,1,39}, {1,1,38}, {1,1,37} + }}; + + // map mec8 channel id (1-70) to mec8 signal id on detector as defined by audrey in z views + /* sources: + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 + */ + std::map mec8_to_signal_mapping_z = { + /* bottom row on mec8 (female) connector corresponds to bottom row on detector as defined by Audrey */ + {1,-1}, + {3,1}, {5,2}, {7,3}, {9,4}, {11,5}, {13,6}, {15,7}, {17,8}, + {19,9}, {21,10}, {23,11}, {25,12}, {27,13}, {29,14}, {31,15}, {33,16}, + {35,-1}, + {37,17}, {39,18}, {41,19}, {43,20}, {45,21}, {47,22}, {49,23}, {51,24}, + {53,25}, {55,26}, {57,27}, {59,28}, {61,29}, {63,30}, {65,31}, {67,32}, + {69,-1}, + /* top row on mec8 (female) connector corresponds to top row on detector as defined by Audrey */ + {2,-1}, + {4,33}, {6,34}, {8,35}, {10,36}, {12,37}, {14,38}, {16,39}, {18,40}, + {20,41}, {22,42}, {24,43}, {26,44}, {28,45}, {30,46}, {32,47}, {34,48}, + {36,-1}, + {38,49}, {40,50}, {42,51}, {44,52}, {46,53}, {48,54}, {50,55}, {52,56}, + {54,57}, {56,58}, {58,59}, {60,60}, {62,61}, {64,62}, {66,63}, {68,64}, + {70,-1} + }; + + // map all mec8 channel id to signal id on detector as defined by audrey in z views + /* sources: + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 + */ + std::map mec8_to_signal_mapping_z_all; + for( const auto& [mec8_channel,signal_id]:mec8_to_signal_mapping_z ) + { + + // ignore ground channels + if( signal_id == -1 ) continue; + + // cable 0, connector 0 corresponds to signal ids 1 to 64 + mec8_to_signal_mapping_z_all.insert(std::pair({0,0,mec8_channel}, signal_id)); + + // cable 0, connector 1 corresponds to signal ids 65 to 128 + mec8_to_signal_mapping_z_all.insert(std::pair({0,1,mec8_channel}, signal_id+64)); + + // cable 1, connector 0 corresponds to signal ids 129 to 192 + mec8_to_signal_mapping_z_all.insert(std::pair({1,0,mec8_channel}, signal_id+128)); + + // cable 1, connector 1 corresponds to signal ids 193 to 256 + mec8_to_signal_mapping_z_all.insert(std::pair({1,1,mec8_channel}, signal_id+192)); + } + + // map phisical strips in the detector to MEC8 signal id on detector as defined by Audrey + // source: https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79751/MappingTPOT.xlsx + std::map strip_to_signal_id_mapping_all = + { + {1,1}, {2,33}, {3,2}, {4,34}, {5,3}, {6,35}, {7,4}, {8,36}, + {9,5}, {10,37}, {11,6}, {12,38}, {13,7}, {14,39}, {15,8}, {16,40}, + {17,9}, {18,41}, {19,10}, {20,42}, {21,11}, {22,43}, {23,12}, {24,44}, + {25,13}, {26,45}, {27,14}, {28,46}, {29,15}, {30,47}, {31,16}, {32,48}, + {33,17}, {34,49}, {35,18}, {36,50}, {37,19}, {38,51}, {39,20}, {40,52}, + {41,21}, {42,53}, {43,22}, {44,54}, {45,23}, {46,55}, {47,24}, {48,56}, + {49,25}, {50,57}, {51,26}, {52,58}, {53,27}, {54,59}, {55,28}, {56,60}, + {57,29}, {58,61}, {59,30}, {60,62}, {61,31}, {62,63}, {63,32}, {64,64}, + + {65,65}, {66,97}, {67,66}, {68,98}, {69,67}, {70,99}, {71,68}, {72,100}, + {73,69}, {74,101}, {75,70}, {76,102}, {77,71}, {78,103}, {79,72}, {80,104}, + {81,73}, {82,105}, {83,74}, {84,106}, {85,75}, {86,107}, {87,76}, {88,108}, + {89,77}, {90,109}, {91,78}, {92,110}, {93,79}, {94,111}, {95,80}, {96,112}, + {97,81}, {98,113}, {99,82}, {100,114}, {101,83}, {102,115}, {103,84}, {104,116}, + {105,85}, {106,117}, {107,86}, {108,118}, {109,87}, {110,119}, {111,88}, {112,120}, + {113,89}, {114,121}, {115,90}, {116,122}, {117,91}, {118,123}, {119,92}, {120,124}, + {121,93}, {122,125}, {123,94}, {124,126}, {125,95}, {126,127}, {127,96}, {128,128}, + + {129,129}, {130,161}, {131,130}, {132,162}, {133,131}, {134,163}, {135,132}, {136,164}, + {137,133}, {138,165}, {139,134}, {140,166}, {141,135}, {142,167}, {143,136}, {144,168}, + {145,137}, {146,169}, {147,138}, {148,170}, {149,139}, {150,171}, {151,140}, {152,172}, + {153,141}, {154,173}, {155,142}, {156,174}, {157,143}, {158,175}, {159,144}, {160,176}, + {161,145}, {162,177}, {163,146}, {164,178}, {165,147}, {166,179}, {167,148}, {168,180}, + {169,149}, {170,181}, {171,150}, {172,182}, {173,151}, {174,183}, {175,152}, {176,184}, + {177,153}, {178,185}, {179,154}, {180,186}, {181,155}, {182,187}, {183,156}, {184,188}, + {185,157}, {186,189}, {187,158}, {188,190}, {189,159}, {190,191}, {191,160}, {192,192}, + + {193,193}, {194,225}, {195,194}, {196,226}, {197,195}, {198,227}, {199,196}, {200,228}, + {201,197}, {202,229}, {203,198}, {204,230}, {205,199}, {206,231}, {207,200}, {208,232}, + {209,201}, {210,233}, {211,202}, {212,234}, {213,203}, {214,235}, {215,204}, {216,236}, + {217,205}, {218,237}, {219,206}, {220,238}, {221,207}, {222,239}, {223,208}, {224,240}, + {225,209}, {226,241}, {227,210}, {228,242}, {229,211}, {230,243}, {231,212}, {232,244}, + {233,213}, {234,245}, {235,214}, {236,246}, {237,215}, {238,247}, {239,216}, {240,248}, + {241,217}, {242,249}, {243,218}, {244,250}, {245,219}, {246,251}, {247,220}, {248,252}, + {249,221}, {250,253}, {251,222}, {252,254}, {253,223}, {254,255}, {255,224}, {256,256} + }; + + // add mapping from strip number as defined by Audrey and geant convention + auto get_strip_geant_z = []( int strip_audrey ) + { + /* + * for z views, audrey and geant strips are numbered in the same direction + * geant strips start from zero + */ + return strip_audrey-1; + }; + + // construct fee channel id to strip + /* + * fee channel id is from 0 to 255 + * strip id from 0 to 255 (-1 with respect to Audrey's convention + */ + for( int channel_id = 0; channel_id < MicromegasDefs::m_nchannels_fee; ++channel_id ) + { + + // mec8 channel id + auto mec8_channel_id = fee_to_mec8_mapping[channel_id]; + + // mec8 signal id as defined by Audrey + int mec8_signal_id = mec8_to_signal_mapping_z_all.at(mec8_channel_id); + + // find mec8_signal_id in detector mapping + const auto iter = std::find_if( strip_to_signal_id_mapping_all.begin(), strip_to_signal_id_mapping_all.end(), [mec8_signal_id]( const std::pair& pair ) { return pair.second == mec8_signal_id; } ); + assert( iter != strip_to_signal_id_mapping_all.end() ); + const int strip_audrey = iter->first; + + // convert to geant convention + const int strip_geant = get_strip_geant_z( strip_audrey ); + + // store in array + m_fee_to_strip_mapping_z[channel_id] = strip_geant; + } + + // map mec8 channel id (1-70) to mec8 signal id on detector as defined by audrey in phi views + /* sources: + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png + * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 + */ + std::map mec8_to_signal_mapping_phi = { + /* bottom row on mec8 (female) connector corresponds to top row on detector as defined by Audrey */ + {1,-1}, + {3,33}, {5,34}, {7,35}, {9,36}, {11,37}, {13,38}, {15,39}, {17,40}, + {19,41}, {21,42}, {23,43}, {25,44}, {27,45}, {29,46}, {31,47}, {33,48}, + {35,-1}, + {37,49}, {39,50}, {41,51}, {43,52}, {45,53}, {47,54}, {49,55}, {51,56}, + {53,57}, {55,58}, {57,59}, {59,60}, {61,61}, {63,62}, {65,63}, {67,64}, + {69,-1}, + /* top row on mec8 (female) connector corresponds to bottom row on detector as defined by Audrey */ + {2,-1}, + {4,1}, {6,2}, {8,3}, {10,4}, {12,5}, {14,6}, {16,7}, {18,8}, + {20,9}, {22,10}, {24,11}, {26,12}, {28,13}, {30,14}, {32,15}, {34,16}, + {36,-1}, + {38,17}, {40,18}, {42,19}, {44,20}, {46,21}, {48,22}, {50,23}, {52,24}, + {54,25}, {56,26}, {58,27}, {60,28}, {62,29}, {64,30}, {66,31}, {68,32}, + {70,-1} + }; + + // map all mec8 channel id to signal id on detector as defined by audrey in phi views + /* sources: + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 + */ + std::map mec8_to_signal_mapping_phi_all; + for( const auto& [mec8_channel,signal_id]:mec8_to_signal_mapping_phi ) + { + + // ignore ground channels + if( signal_id == -1 ) continue; + + // cable 0, connector 0 corresponds to signal ids 193 to 256 + mec8_to_signal_mapping_phi_all.insert(std::pair({0,0,mec8_channel}, signal_id+192)); + + // cable 0, connector 1 corresponds to signal ids 129 to 160 + mec8_to_signal_mapping_phi_all.insert(std::pair({0,1,mec8_channel}, signal_id+128)); + + // cable 1, connector 0 corresponds to signal ids 65 to 128 + mec8_to_signal_mapping_phi_all.insert(std::pair({1,0,mec8_channel}, signal_id+64)); + + // cable 1, connector 1 corresponds to signal ids 1 to 64 + mec8_to_signal_mapping_phi_all.insert(std::pair({1,1,mec8_channel}, signal_id)); + } + + // add mapping from strip number as defined by Audrey and geant convention + auto get_strip_geant_phi = []( int strip_audrey ) + { + /* + * for phi views, audrey and geant strips are numbered in oposite directions + * geant strips start from zero + */ + return MicromegasDefs::m_nchannels_fee-strip_audrey; + }; + + // construct fee channel id to strip + /* + * fee channel id is from 0 to 255 + * strip id from 0 to 255 (-1 with respect to Audrey's convention + */ + for( int channel_id = 0; channel_id < MicromegasDefs::m_nchannels_fee; ++channel_id ) + { + + // mec8 channel id + auto mec8_channel_id = fee_to_mec8_mapping[channel_id]; + + // mec8 signal id as defined by Audrey + int mec8_signal_id = mec8_to_signal_mapping_phi_all.at(mec8_channel_id); + + // find mec8_signal_id in detector mapping + const auto iter = std::find_if( strip_to_signal_id_mapping_all.begin(), strip_to_signal_id_mapping_all.end(), [mec8_signal_id]( const std::pair& pair ) { return pair.second == mec8_signal_id; } ); + assert( iter != strip_to_signal_id_mapping_all.end() ); + const int strip_audrey = iter->first; + + // convert to geant convention + const int strip_geant = get_strip_geant_phi( strip_audrey ); + + // store in array + m_fee_to_strip_mapping_phi[channel_id] = strip_geant; + } + +} diff --git a/offline/packages/micromegas/MicromegasMapping.h b/offline/packages/micromegas/MicromegasMapping.h index 21845f0fce..88e30ff692 100644 --- a/offline/packages/micromegas/MicromegasMapping.h +++ b/offline/packages/micromegas/MicromegasMapping.h @@ -6,8 +6,11 @@ * \author Hugo Pereira Da Costa */ +#include "MicromegasDefs.h" + #include +#include #include #include #include @@ -50,6 +53,9 @@ class MicromegasMapping private: + /// construct fee channel id to physical strip mapping + void construct_channel_mapping(); + /// contains all relevant detector information /** this effectively implements mapping between fee_id as defined in EDBC,
 * detector names (in both Saclay and sPHENIX convention), * and hitsetkey which is the detector unique identifier @@ -95,6 +101,12 @@ class MicromegasMapping /// map detector_id to fee_id std::map m_detector_map; + + /// map FEE channel id to physical strip id (z view) + std::array m_fee_to_strip_mapping_z = {{0}}; + + /// map FEE channel id to physical strip id (phi view) + std::array m_fee_to_strip_mapping_phi = {{0}}; }; From d578c70a783edb789c39acf2ebd8de77fc7a4d41 Mon Sep 17 00:00:00 2001 From: Ejiro Umaka Date: Sat, 15 Apr 2023 01:47:51 -0400 Subject: [PATCH 224/468] remove duplicate include file --- simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc index 7023279f00..95d0691c2c 100644 --- a/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc +++ b/simulation/g4simulation/g4epd/PHG4EPDModuleReco.cc @@ -5,8 +5,6 @@ #include #include -#include - #include #include @@ -154,11 +152,12 @@ int PHG4EPDModuleReco::process_event(PHCompositeNode *topNode) { unsigned int globalphi = Getphimap(j) + 2 * i; unsigned int r = Getrmap(j); + if (r == 0) { globalphi = i; } - + unsigned int key = TowerInfoDefs::encode_epd(k, r, globalphi); unsigned int ch = m_TowerInfoContainer->decode_key(key); m_TowerInfoContainer->get_tower_at_channel(ch)->set_energy(m_EpdTile_e[k][i][j]); From aabfa91b8e90f8e00215e0063e57bbcfcdeda234 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Sat, 15 Apr 2023 09:27:07 -0400 Subject: [PATCH 225/468] fixed clang --- offline/packages/micromegas/MicromegasMapping.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index 99ede735d7..2d56a2cfe9 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -46,16 +46,7 @@ namespace {} }; - - // equal to operator - inline bool operator == (const mec8_channel_id& lhs, const mec8_channel_id& rhs ) - { - return - lhs.m_cable_id == rhs.m_cable_id && - lhs.m_connector_id == rhs.m_connector_id && - lhs.m_channel_id == rhs.m_channel_id; - } - + // less than operator inline bool operator < (const mec8_channel_id& lhs, const mec8_channel_id& rhs ) { From 98cf500380c1671bf48b22f14334e38ca8e3be39 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 10:13:34 -0400 Subject: [PATCH 226/468] Add DumpEpdGeom for new Epd geometry --- offline/packages/NodeDump/DumpEpdGeom.cc | 50 ++++++++++++++++++++++++ offline/packages/NodeDump/DumpEpdGeom.h | 20 ++++++++++ offline/packages/NodeDump/Makefile.am | 2 + offline/packages/NodeDump/PHNodeDump.cc | 5 +++ 4 files changed, 77 insertions(+) create mode 100644 offline/packages/NodeDump/DumpEpdGeom.cc create mode 100644 offline/packages/NodeDump/DumpEpdGeom.h diff --git a/offline/packages/NodeDump/DumpEpdGeom.cc b/offline/packages/NodeDump/DumpEpdGeom.cc new file mode 100644 index 0000000000..645d7e5d15 --- /dev/null +++ b/offline/packages/NodeDump/DumpEpdGeom.cc @@ -0,0 +1,50 @@ +#include "DumpEpdGeom.h" + +#include + +#include +#include + +#include +#include +#include + +using MyNode_t = PHIODataNode; + +DumpEpdGeom::DumpEpdGeom(const std::string &NodeName) + : DumpObject(NodeName) +{ + return; +} + +int DumpEpdGeom::process_Node(PHNode *myNode) +{ + EpdGeom *epdgeom = nullptr; + MyNode_t *thisNode = static_cast(myNode); + if (thisNode) + { + epdgeom = thisNode->getData(); + } + if (epdgeom) + { + for (int iarm = 0; iarm<2; iarm++) + { + for (int irad = 0; irad < 16; irad++) + { + for (int iphi = 0; iphi<24; iphi++) + { + if (irad == 0 && iphi > 11) + { + continue; + } + unsigned int key = TowerInfoDefs::encode_epd(iarm, irad, iphi); + *fout << "tile key: 0x" << std::hex << key << std::dec << std::endl; + *fout << "get_r: " << epdgeom->get_r(key) << std::endl; + *fout << "get_phi: " << epdgeom->get_phi(key) << std::endl; + *fout << "get_z: " << epdgeom->get_z(key) << std::endl; + } + } + } + } + return 0; +} diff --git a/offline/packages/NodeDump/DumpEpdGeom.h b/offline/packages/NodeDump/DumpEpdGeom.h new file mode 100644 index 0000000000..9ae3e8af77 --- /dev/null +++ b/offline/packages/NodeDump/DumpEpdGeom.h @@ -0,0 +1,20 @@ +#ifndef NODEDUMP_DUMPEPDGEOM_H +#define NODEDUMP_DUMPEPDGEOM_H + +#include "DumpObject.h" + +#include + +class PHNode; + +class DumpEpdGeom : public DumpObject +{ + public: + explicit DumpEpdGeom(const std::string &NodeName); + ~DumpEpdGeom() override {} + + protected: + int process_Node(PHNode *mynode) override; +}; + +#endif diff --git a/offline/packages/NodeDump/Makefile.am b/offline/packages/NodeDump/Makefile.am index f78f16f053..23c8ba264e 100644 --- a/offline/packages/NodeDump/Makefile.am +++ b/offline/packages/NodeDump/Makefile.am @@ -20,6 +20,7 @@ libphnodedump_la_SOURCES = \ DumpCaloTriggerInfo.cc \ DumpCdbUrlSave.cc \ DumpCentralityInfo.cc \ + DumpEpdGeom.cc \ DumpEpInfo.cc \ DumpEventHeader.cc \ DumpFlagSave.cc \ @@ -70,6 +71,7 @@ libphnodedump_la_LIBADD = \ -lbbc_io \ -lcalo_io \ -lcalotrigger_io \ + -lepd_io \ -leventplane_io \ -lffaobjects \ -lg4detectors_io \ diff --git a/offline/packages/NodeDump/PHNodeDump.cc b/offline/packages/NodeDump/PHNodeDump.cc index b67b6f8dd8..db990c7048 100644 --- a/offline/packages/NodeDump/PHNodeDump.cc +++ b/offline/packages/NodeDump/PHNodeDump.cc @@ -7,6 +7,7 @@ #include "DumpCaloTriggerInfo.h" #include "DumpCdbUrlSave.h" #include "DumpCentralityInfo.h" +#include "DumpEpdGeom.h" #include "DumpEpInfo.h" #include "DumpEventHeader.h" #include "DumpFlagSave.h" @@ -206,6 +207,10 @@ int PHNodeDump::AddDumpObject(const std::string &NodeName, PHNode *node) { newdump = new DumpCentralityInfo(NodeName); } + else if (tmp->InheritsFrom("EpdGeom")) + { + newdump = new DumpEpdGeom(NodeName); + } else if (tmp->InheritsFrom("EpInfo")) { newdump = new DumpEpInfo(NodeName); From 6bce5f700c90011e65c9741b59afd74acbc5bfe0 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 10:16:31 -0400 Subject: [PATCH 227/468] put back default ctors so root can read the files back --- offline/packages/bbc/BbcNorthSouth.h | 8 +++++--- offline/packages/bbc/BbcNorthSouthV1.h | 9 +++++---- offline/packages/bbc/BbcOutV1.cc | 10 +++++----- offline/packages/bbc/BbcPmtHit.h | 12 +++++++----- offline/packages/bbc/BbcPmtHitV1.h | 11 ++++++----- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/offline/packages/bbc/BbcNorthSouth.h b/offline/packages/bbc/BbcNorthSouth.h index a2ea742e1d..76427c4233 100644 --- a/offline/packages/bbc/BbcNorthSouth.h +++ b/offline/packages/bbc/BbcNorthSouth.h @@ -3,6 +3,8 @@ #ifndef BBC_BBCNORTHSOUTH_H #define BBC_BBCNORTHSOUTH_H +#include "BbcReturnCodes.h" + #include #include @@ -19,17 +21,17 @@ class BbcNorthSouth : public PHObject virtual short get_nPMT() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_SHORT; } virtual float get_nCharge() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_FLOAT; } virtual float get_MeanTime() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_FLOAT; } private: diff --git a/offline/packages/bbc/BbcNorthSouthV1.h b/offline/packages/bbc/BbcNorthSouthV1.h index 98a3fa4a06..c812e80225 100644 --- a/offline/packages/bbc/BbcNorthSouthV1.h +++ b/offline/packages/bbc/BbcNorthSouthV1.h @@ -6,11 +6,12 @@ #include "BbcNorthSouth.h" #include +#include class BbcNorthSouthV1 : public BbcNorthSouth { public: - BbcNorthSouthV1() = delete; + BbcNorthSouthV1() = default; BbcNorthSouthV1(const short npmt, const float chargesum, const float timing); virtual ~BbcNorthSouthV1() {} void identify(std::ostream& os = std::cout) const override; @@ -22,9 +23,9 @@ class BbcNorthSouthV1 : public BbcNorthSouth protected: virtual void Clear(Option_t* /*option*/ = "") override {} - short nPmt; - float nCharge; - float MeanTime; + short nPmt = 0; + float nCharge = std::numeric_limits::quiet_NaN(); + float MeanTime = std::numeric_limits::quiet_NaN(); private: ClassDefOverride(BbcNorthSouth, 1) diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index d64a745508..94bd067820 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -18,10 +18,10 @@ BbcOutV1::BbcOutV1() //______________________________________ void BbcOutV1::Init() { - Bbc_ZVertex = -99999.9; - Bbc_dZVertex = -99999.9; - Bbc_TimeZero = -99999.9; - Bbc_dTimeZero = -99999.9; + Bbc_ZVertex = std::numeric_limits::quiet_NaN(); + Bbc_dZVertex = std::numeric_limits::quiet_NaN(); + Bbc_TimeZero = std::numeric_limits::quiet_NaN(); + Bbc_dTimeZero = std::numeric_limits::quiet_NaN(); } //______________________________________ @@ -33,7 +33,7 @@ BbcOutV1::~BbcOutV1() //______________________________________ int BbcOutV1::isValid() const { - return ((Bbc_TimeZero > -9999.) ? 1 : 0); + return ((std::isfinite(Bbc_TimeZero)) ? 1 : 0); } //______________________________________ diff --git a/offline/packages/bbc/BbcPmtHit.h b/offline/packages/bbc/BbcPmtHit.h index 3e7d08672d..6d79c9328c 100644 --- a/offline/packages/bbc/BbcPmtHit.h +++ b/offline/packages/bbc/BbcPmtHit.h @@ -3,11 +3,13 @@ #ifndef BBC_BBCPMTHIT_H #define BBC_BBCPMTHIT_H -#include +#include "BbcReturnCodes.h" #include #include +#include + class BbcPmtHit : public PHObject { public: @@ -18,22 +20,22 @@ class BbcPmtHit : public PHObject virtual short get_pmt() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_SHORT; } virtual float get_adc() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_FLOAT; } virtual float get_tdc0() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_FLOAT; } virtual float get_tdc1() const { PHOOL_VIRTUAL_WARNING; - return -9999; + return BbcReturnCodes::BBC_INVALID_FLOAT; } void identify(std::ostream& os = std::cout) const override; diff --git a/offline/packages/bbc/BbcPmtHitV1.h b/offline/packages/bbc/BbcPmtHitV1.h index 013833a853..4fa30c44ae 100644 --- a/offline/packages/bbc/BbcPmtHitV1.h +++ b/offline/packages/bbc/BbcPmtHitV1.h @@ -6,11 +6,12 @@ #include "BbcPmtHit.h" #include +#include class BbcPmtHitV1 : public BbcPmtHit { public: - BbcPmtHitV1() = delete; + BbcPmtHitV1() = default; BbcPmtHitV1(const short pmt, const float adc, const float tdc0, const float tdc1); ~BbcPmtHitV1() override = default; @@ -22,10 +23,10 @@ class BbcPmtHitV1 : public BbcPmtHit void identify(std::ostream& os = std::cout) const override; private: - short pmt; - float adc; - float tdc0; - float tdc1; + short pmt = 0; + float adc = std::numeric_limits::quiet_NaN(); + float tdc0 = std::numeric_limits::quiet_NaN(); + float tdc1 = std::numeric_limits::quiet_NaN(); ClassDefOverride(BbcPmtHitV1, 1) }; From 528e820e30a00d349df02bed3bc60c3ca0e7a93c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 10:22:10 -0400 Subject: [PATCH 228/468] cmpatible with old invalid value of -9999.9 --- offline/packages/bbc/BbcOutV1.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/bbc/BbcOutV1.cc b/offline/packages/bbc/BbcOutV1.cc index 94bd067820..eb400b25ba 100644 --- a/offline/packages/bbc/BbcOutV1.cc +++ b/offline/packages/bbc/BbcOutV1.cc @@ -33,7 +33,8 @@ BbcOutV1::~BbcOutV1() //______________________________________ int BbcOutV1::isValid() const { - return ((std::isfinite(Bbc_TimeZero)) ? 1 : 0); +// compatible with old invalid setting of -9999.9 + return ((std::isfinite(Bbc_TimeZero) && (Bbc_TimeZero > -9999.)) ? 1 : 0); } //______________________________________ From 9c1f918d3a62235a8ed741179cf6ce01eb1d7267 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 13:52:38 -0400 Subject: [PATCH 229/468] Add CDBInterface for new cdb client --- offline/framework/ffamodules/CDBInterface.cc | 134 +++++++++++++++++++ offline/framework/ffamodules/CDBInterface.h | 37 +++++ offline/framework/ffamodules/Makefile.am | 3 + 3 files changed, 174 insertions(+) create mode 100644 offline/framework/ffamodules/CDBInterface.cc create mode 100644 offline/framework/ffamodules/CDBInterface.h diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc new file mode 100644 index 0000000000..ffae6c06be --- /dev/null +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -0,0 +1,134 @@ +#include "CDBInterface.h" + +#include +#include + +#include +#include +#include // for SubsysReco + +#include +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include + +#include + +#include // for uint64_t +#include // for operator<<, basic_ostream, endl +#include // for pair +#include // for vector + +CDBInterface *CDBInterface::__instance = nullptr; + +CDBInterface *CDBInterface::instance() +{ + if (__instance) + { + return __instance; + } + __instance = new CDBInterface(); + return __instance; +} + +//____________________________________________________________________________.. +CDBInterface::CDBInterface(const std::string &name) + : SubsysReco(name) +{ + Fun4AllServer *se = Fun4AllServer::instance(); + se->addNewSubsystem(this); +} + +//____________________________________________________________________________.. +int CDBInterface::End(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + CdbUrlSave *cdburls = findNode::getClass(runNode, "CdbUrl"); + if (!cdburls) + { + cdburls = new CdbUrlSavev1(); + PHIODataNode *newNode = new PHIODataNode(cdburls, "CdbUrl", "PHObject"); + runNode->addNode(newNode); + } + else + { + std::set> tmp_set; + for (const auto & cdburl : *cdburls) + { + tmp_set.insert(cdburl); + } + // remove duplicates in our set + // not possible using for range loops, iterator gets invalidated + for (auto itr = m_UrlVector.cbegin(); itr != m_UrlVector.cend();) + { + if (tmp_set.find(*itr) != tmp_set.end()) + { + if (Verbosity()) + { + std::cout << "removing already saved: domain " << std::get<0>(*itr) + << ", url: " << std::get<1>(*itr) + << ", timestamp: " << std::get<2>(*itr) << std::endl; + } + itr = m_UrlVector.erase(itr); + } + else + { + ++itr; + } + } + } + for (auto &tuple : m_UrlVector) + { + cdburls->AddUrl(tuple); + } + if (Verbosity() > 0) + { + cdburls->identify(); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +void CDBInterface::Print(const std::string & /* what */) const +{ + for (auto &iter : m_UrlVector) + { + std::cout << "domain: " << std::get<0>(iter) + << ", url: " << std::get<1>(iter) + << ", timestamp: " << std::get<2>(iter) << std::endl; + } +} + +std::string CDBInterface::getUrl(const std::string &domain, const std::string &filename) +{ + recoConsts *rc = recoConsts::instance(); + if (! rc->FlagExist("CDB_GLOBALTAG")) + { + std::cout << "CDB_GLOBALTAG flag needs to be set via" << std::endl; + std::cout << "rc->set_StringFlag(\"CDB_GLOBALTAG\",)" << std::endl; + gSystem->Exit(1); + } + if (! rc->FlagExist("TIMESTAMP")) + { + std::cout << "TIMESTAMP flag needs to be set via" << std::endl; + std::cout << "rc->set_uint64Flag(\"TIMESTAMP\",<64 bit timestamp>)" << std::endl; + gSystem->Exit(1); + } + sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + std::string return_url = cdb->getCalibrationFile(domain,rc->get_uint64Flag("TIMESTAMP")); + if (return_url.empty()) + { + return_url = filename; + } + auto pret = m_UrlVector.insert(make_tuple(domain, return_url, timestamp)); + if (!pret.second && Verbosity() > 1) + { + std::cout << "duplicate entry " << domain << ", url: " << return_url + << ", time stamp: " << timestamp << std::endl; + } + return return_url; +} diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h new file mode 100644 index 0000000000..b150b34616 --- /dev/null +++ b/offline/framework/ffamodules/CDBInterface.h @@ -0,0 +1,37 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef FFAMODULES_CDBINTERFACE_H +#define FFAMODULES_CDBINTERFACE_H + +#include + +#include // for uint64_t +#include +#include +#include // for tuple + +class PHCompositeNode; + +class CDBInterface : public SubsysReco +{ + public: + static CDBInterface *instance(); + + ~CDBInterface() override {} + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void Print(const std::string &what = "ALL") const override; + + std::string getUrl(const std::string &domain, const std::string &filename = ""); + + private: + CDBInterface(const std::string &name = "CDBInterface"); + + static CDBInterface *__instance; + + std::set> m_UrlVector; +}; + +#endif // FFAMODULES_CDBINTERFACE_H diff --git a/offline/framework/ffamodules/Makefile.am b/offline/framework/ffamodules/Makefile.am index 2716fbe047..7809f2b7d2 100644 --- a/offline/framework/ffamodules/Makefile.am +++ b/offline/framework/ffamodules/Makefile.am @@ -17,17 +17,20 @@ libffamodules_la_LIBADD = \ -lfun4all \ -lffaobjects \ -lphhepmc_io \ + -lsphenixnpc \ -lSubsysReco \ -lxpload \ -lstdc++fs pkginclude_HEADERS = \ + CDBInterface.h \ FlagHandler.h \ HeadReco.h \ SyncReco.h \ XploadInterface.h libffamodules_la_SOURCES = \ + CDBInterface.cc \ FlagHandler.cc \ HeadReco.cc \ SyncReco.cc \ From bc98d56d901d201a9cbf8cfaad22d641e080df79 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 13:53:40 -0400 Subject: [PATCH 230/468] return empty string as url on DB failure --- offline/database/sphenixnpc/sphenixnpc.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index a6572e66a2..7b37755bfa 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -81,7 +81,16 @@ nlohmann::json sphenixnpc::clearCache() std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov) { nlohmann::json result = get(type, iov); - return result.at("msg"); + std::string fullUrl = result.at("msg"); + if (fullUrl.find("Exception") != std::string::npos) + { + if (Verbosity()) + { + std::cout << fullUrl << std::endl; + } + return std::string(""); + } + return fullUrl; } int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) From 6ba0f24972cda858d3bc5605c99571ee2d5486f5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 14:45:17 -0400 Subject: [PATCH 231/468] fix build crash --- offline/framework/ffamodules/CDBInterface.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index ffae6c06be..a3c38cf933 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -17,6 +17,8 @@ #include +#include + #include // for uint64_t #include // for operator<<, basic_ostream, endl #include // for pair @@ -119,7 +121,8 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f gSystem->Exit(1); } sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); - std::string return_url = cdb->getCalibrationFile(domain,rc->get_uint64Flag("TIMESTAMP")); + uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); + std::string return_url = cdb->getCalibrationFile(domain,timestamp); if (return_url.empty()) { return_url = filename; From e26a2dd7f1d36f7b93c11371742f044c2a28853d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 16:55:14 -0400 Subject: [PATCH 232/468] iwyu to trigger jenkins --- .../calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc b/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc index b1c6105afe..67ff72257a 100644 --- a/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc +++ b/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc @@ -5,11 +5,10 @@ #include #include #include +#include #include -#include - -#include -#include +#include +#include #include From 7ccd6fda7b915cd4176a9de80a2962774082ffcf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 19:14:37 -0400 Subject: [PATCH 233/468] use -isystem for root includes --- offline/framework/ffamodules/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/ffamodules/Makefile.am b/offline/framework/ffamodules/Makefile.am index 7809f2b7d2..12f0a809a5 100644 --- a/offline/framework/ffamodules/Makefile.am +++ b/offline/framework/ffamodules/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = \ AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include + -isystem$(ROOTSYS)/include AM_LDFLAGS = \ -L$(libdir) \ From 51f29d0aeafd67a8c974b26f968bd46ddba40f3c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 15 Apr 2023 19:18:34 -0400 Subject: [PATCH 234/468] use -isystem for root includes --- generators/FermiMotionAfterburner/Makefile.am | 2 +- offline/framework/ffaobjects/Makefile.am | 2 +- offline/packages/tpc/Makefile.am | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/generators/FermiMotionAfterburner/Makefile.am b/generators/FermiMotionAfterburner/Makefile.am index 10d15395ea..f2683ce1ac 100644 --- a/generators/FermiMotionAfterburner/Makefile.am +++ b/generators/FermiMotionAfterburner/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include + -isystem$(ROOTSYS)/include AM_LDFLAGS = \ -L$(libdir) \ diff --git a/offline/framework/ffaobjects/Makefile.am b/offline/framework/ffaobjects/Makefile.am index bc0c547333..1c569ef9b0 100644 --- a/offline/framework/ffaobjects/Makefile.am +++ b/offline/framework/ffaobjects/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = \ AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include + -isystem$(ROOTSYS)/include AM_LDFLAGS = \ -L$(libdir) \ diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index d44c81b744..8dcc7a04b3 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -10,7 +10,7 @@ lib_LTLIBRARIES = \ AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include + -isystem$(ROOTSYS)/include AM_LDFLAGS = \ -L$(libdir) \ From 9bbb19e9e346bb4ff1d69df4dc151c18c64a103a Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 15 Apr 2023 23:32:56 -0400 Subject: [PATCH 235/468] handle zero-sized array --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index d4cb388975..d98e6d28ef 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -64,6 +64,12 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const for (uint16_t i = 0; i < m_nPads; ++i) { + if (m_timeFrameADCData[i].size() == 0) + { + os << "Pad " << i << " is empty" << std::endl; + continue; + } + // skip empty pads if (*std::max_element(m_timeFrameADCData[i].begin(), m_timeFrameADCData[i].end()) == 0) continue; From a83e246a867d902b364732e622db2744e38ee11d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 15 Apr 2023 23:35:11 -0400 Subject: [PATCH 236/468] avoid calling reset in resize --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index d98e6d28ef..746f74ead5 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -33,10 +33,8 @@ void TrkrHitSetTpcv1::Resize() for (auto& pad : m_timeFrameADCData) { if (n_tbin != pad.size()) - pad.resize(n_tbin); + pad.resize(n_tbin, 0); } - - Reset(); } void TrkrHitSetTpcv1::identify(std::ostream& os) const From a378562cbbd8399cc183f99abe21b1ac3c4ed997 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 16 Apr 2023 16:30:55 -0400 Subject: [PATCH 237/468] enable ROOT readback --- offline/packages/trackbase/TrkrHitSetContainerv2.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.h b/offline/packages/trackbase/TrkrHitSetContainerv2.h index 28ff3892cc..e2f31594a4 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.h +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.h @@ -18,11 +18,10 @@ class TrkrHitSet; */ class TrkrHitSetContainerv2 final : public TrkrHitSetContainer { - private: - //! only used in ROOT IO +public: + //! only used in ROOT IO. Do NOT use this constructor in user code TrkrHitSetContainerv2() = default; - public: TrkrHitSetContainerv2(const std::string& hitsetclass, const size_t estimated_size); ~TrkrHitSetContainerv2() override From b6673da3a102af67c4959300c704bb986dce5f28 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 16 Apr 2023 16:31:21 -0400 Subject: [PATCH 238/468] deal with the annoying fact that TPC pad size varies --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 3 + .../g4tpc/PHG4TpcElectronDrift.cc | 100 ++++++++++-------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 746f74ead5..3efc777931 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -33,7 +33,10 @@ void TrkrHitSetTpcv1::Resize() for (auto& pad : m_timeFrameADCData) { if (n_tbin != pad.size()) + { + pad.reserve(n_tbin); pad.resize(n_tbin, 0); + } } } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index a3146d7ca2..9cb9afdcfa 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -631,11 +631,18 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) assert(hitset->getHitSetKey() == node_hitsetkey); if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " filling hitset from node_hitsetkey = "<identify(); } + assert(seggeo); + PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); + assert(layer_geometry); + + const int npad = layer_geometry->get_phibins() / TpcDefs::NRSectors; + const int start_pad = sector * npad; + // ensure the hitset is prepared and consistent { if (Verbosity() > 100) @@ -645,64 +652,63 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) << " with sector " << sector << " side " << side << std::endl; } - assert(seggeo); - PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); - assert(layer_geometry); - - const int npad = layer_geometry->get_phibins() / TpcDefs::NRSectors; - const int start_pad = sector * npad; - if (hitset->getNPads()) + // phi setup if needed + if (hitset->getNPads() == npad) { - assert(hitset->getNPads() == npad); + if (Verbosity() > 2) + std::cout << __PRETTY_FUNCTION__ << " npad is consistent, no need to resize for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " hitset->getNPads() = " << hitset->getNPads() + << " : setNPads " << npad + << std::endl; } else { if (Verbosity()) { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + std::cout << __PRETTY_FUNCTION__ << " npad is inconsistent, need to resize for temp_hitset with key: " << node_hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << " : setNPads " << npad + << " This is necissary as TPC has various sizes of pad rows, which unfortunately leads to this extra memory allocation/delocation from event to event" << std::endl; } hitset->setNPads(npad); } if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done npad hitset from node_hitsetkey = "<identify(); } - if (hitset->getPadIndexStart()) - { - assert(hitset->getPadIndexStart() == start_pad); - } - else + + // start_pad setup if needed + if (Verbosity() > 100) { - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setPadIndexStart " << start_pad - << std::endl; - } - hitset->setPadIndexStart(start_pad); + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setPadIndexStart " << start_pad + << std::endl; } + hitset->setPadIndexStart(start_pad); if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done start_pad hitset from node_hitsetkey = "<identify(); } + + // ntbin setup if needed // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. const int ntbin = layer_geometry->get_zbins(); const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); if (hitset->getNTBins()) { - assert(hitset->getNTBins() == ntbin); + assert(hitset->getNTBins() == ntbin); // we do not expect ntbin to change, othertwise it is a consistency error } else { @@ -718,37 +724,31 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done ntbin hitset from node_hitsetkey = "<identify(); } - if (hitset->getTBinIndexStart()) - { - assert(hitset->getTBinIndexStart() == start_tbin); - } - else + // ntbin start_tbin if needed + if (Verbosity() > 100) { - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setTBinIndexStart " << start_tbin - << std::endl; - } - hitset->setTBinIndexStart(start_tbin); + std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setTBinIndexStart " << start_tbin + << std::endl; } + hitset->setTBinIndexStart(start_tbin); if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done start_tbin hitset from node_hitsetkey = "<identify(); } } // ensure the hitset is prepared and consistent if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done initializing hitset from node_hitsetkey = "<identify(); } @@ -772,6 +772,18 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) ncollectedhits++; } + if (TpcDefs::getPad(temp_hitkey) < start_pad or TpcDefs::getPad(temp_hitkey) >= start_pad + npad) + { + std::cout << __PRETTY_FUNCTION__ + << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) + << " z bin " << TpcDefs::getTBin(temp_hitkey) + << "which is outside the hitset " + << " in layer " << layer + << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad + << std::endl; + continue; + } + hitset->getTpcADC(temp_hitkey) += temp_tpchit->getEnergy(); } // end loop over temp hits From 8aab3589bbb8cd91ef2b2f230a27fe01dcf6dd24 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 16 Apr 2023 16:52:26 -0400 Subject: [PATCH 239/468] add more variables in clear to ensure proper intra-event reset --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 3efc777931..8af1d84c12 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -16,7 +16,12 @@ void TrkrHitSetTpcv1::Reset() { m_hitSetKey = TrkrDefs::HITSETKEYMAX; + m_StartingBCO = 0; + m_padIndexStart = 0; + m_tBinIndexStart = 0; + //ADC 2D array is zeroed but intentionally NOT deleted, + //which potentially save memory allocation-deallocation ops in the next event for (auto& pad : m_timeFrameADCData) { std::fill(pad.begin(), pad.end(), 0); From 616297c0a135da5c76dcd61d0a9e8315e8ac2c90 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 16 Apr 2023 21:19:06 -0400 Subject: [PATCH 240/468] deal with rarer abnormal data in TPC digitization --- .../g4tpc/PHG4TpcElectronDrift.cc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 9cb9afdcfa..c60e742b8e 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -683,7 +683,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) hitset->identify(); } - // start_pad setup if needed if (Verbosity() > 100) { @@ -701,10 +700,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) hitset->identify(); } - // ntbin setup if needed // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. - const int ntbin = layer_geometry->get_zbins(); + const int ntbin = layer_geometry->get_zbins() + 1; const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); if (hitset->getNTBins()) { @@ -774,13 +772,14 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (TpcDefs::getPad(temp_hitkey) < start_pad or TpcDefs::getPad(temp_hitkey) >= start_pad + npad) { - std::cout << __PRETTY_FUNCTION__ - << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) - << " z bin " << TpcDefs::getTBin(temp_hitkey) - << "which is outside the hitset " - << " in layer " << layer - << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad - << std::endl; + if (Verbosity()) + std::cout << __PRETTY_FUNCTION__ + << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) + << " z bin " << TpcDefs::getTBin(temp_hitkey) + << "which is outside the hitset " + << " in layer " << layer + << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad + << std::endl; continue; } From 29d414de73a952c001f55b48c456f353406e59cf Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 17 Apr 2023 00:59:05 -0400 Subject: [PATCH 241/468] add debug info --- .../trackbase/TrkrHitSetContainerv2.cc | 2 ++ offline/packages/trackbase/TrkrHitSetTpcv1.cc | 13 ++++--- .../g4simulation/g4tpc/PHG4TpcDigitizer.cc | 34 +++++++++++++++---- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 17 ++++++++++ 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc index bef971220e..ecbeeab29e 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.cc +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -22,7 +22,9 @@ TrkrHitSetContainerv2:: void TrkrHitSetContainerv2::Reset() { + // force rebuild of indexing map m_hitmap.clear(); + //! fast clear without calling destructor m_hitArray.Clear("C"); } diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index 8af1d84c12..c9ac2b2d3f 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -20,8 +20,8 @@ void TrkrHitSetTpcv1::Reset() m_padIndexStart = 0; m_tBinIndexStart = 0; - //ADC 2D array is zeroed but intentionally NOT deleted, - //which potentially save memory allocation-deallocation ops in the next event + // ADC 2D array is zeroed but intentionally NOT deleted, + // which potentially save memory allocation-deallocation ops in the next event for (auto& pad : m_timeFrameADCData) { std::fill(pad.begin(), pad.end(), 0); @@ -72,7 +72,7 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const { if (m_timeFrameADCData[i].size() == 0) { - os << "Pad " << i << " is empty" << std::endl; + os << "Pad " << i << " ADC vector is zero-sized" << std::endl; continue; } @@ -81,9 +81,14 @@ void TrkrHitSetTpcv1::identify(std::ostream& os) const os << "Pad " << i << ":"; + int j = 0; for (const auto& adc : m_timeFrameADCData[i]) { - os << "\t" << adc; + if (adc) + { + os << "\t[" << j << "]:" << adc; + } + ++j; } os << std::endl; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index 38b6f38631..d9305da6c1 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -152,7 +152,6 @@ void PHG4TpcDigitizer::CalculateCylinderCellADCScale(PHCompositeNode *topNode) void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) { - // Digitizes the Tpc cells that were created in PHG4CylinderCellTpcReco // These contain as edep the number of electrons out of the GEM stack, distributed between Z bins by shaper response and ADC clock window // - i.e. all of the phi and Z bins in a cluster have edep values that add up to the primary charge in the layer times 2000 @@ -257,12 +256,23 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } assert(hitset); + if (Verbosity() > 2) + { + const unsigned int layer = TrkrDefs::getLayer(hitsetkey); + const int sector = TpcDefs::getSectorId(hitsetkey); + const int side = TpcDefs::getSide(hitsetkey); + + std::cout << __PRETTY_FUNCTION__ << " Start processing hitsetkey " + << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; + hitset->identify(std::cout); + } + std::vector pass_zero_suppression; - for (auto & t_sorted_hits : hitset->getTimeFrameAdcData()) + for (auto &t_sorted_hits : hitset->getTimeFrameAdcData()) { // add noise - for (auto & adc_bin : t_sorted_hits) + for (auto &adc_bin : t_sorted_hits) { adc_bin = static_cast(add_noise_to_bin((float) adc_bin)); } @@ -274,10 +284,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) { if (t_sorted_hits[i] > ADCThreshold_mV) { - for (int j = i - m_nPreSample; j < i + (int)m_nPostSample; ++j) + for (int j = i - m_nPreSample; j < i + (int) m_nPostSample; ++j) { if (j < 0) continue; - if (j >= (int)pass_zero_suppression.size()) continue; + if (j >= (int) pass_zero_suppression.size()) continue; pass_zero_suppression[j] = true; } @@ -301,6 +311,16 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // for (auto & t_sorted_hits : hitset->getTimeFrameAdcData()) + if (Verbosity() > 2) + { + const unsigned int layer = TrkrDefs::getLayer(hitsetkey); + const int sector = TpcDefs::getSectorId(hitsetkey); + const int side = TpcDefs::getSide(hitsetkey); + + std::cout << __PRETTY_FUNCTION__ << " Finished processing hitsetkey " + << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl; + hitset->identify(std::cout); + } } // for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; return; @@ -324,7 +344,7 @@ float PHG4TpcDigitizer::added_noise() } void PHG4TpcDigitizer:: -SetTpcMinLayer(const int ) + SetTpcMinLayer(const int) { - std::cout <<__PRETTY_FUNCTION__<<" is deprecated. Ignore this call"<addEnergy(neffelectrons); + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " adding hit: hitkey = " + << hitkey << " pad " << TpcDefs::getPad(hitkey) + << " z bin " << TpcDefs::getTBin(hitkey) + << "which comes from input hit in hitsetkey "<get_phibins() " << LayerGeom->get_phibins() + << " LayerGeom->get_layer() " << LayerGeom->get_layer() + << std::endl; + hit->identify(); + } + tpc_truth_clusterer->addhitset(hitsetkey, hitkey, neffelectrons); // repeat for the single_hitsetcontainer From 80c9af71e342173957c473215ec68a244ef186bc Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 17 Apr 2023 00:59:33 -0400 Subject: [PATCH 242/468] fix n_sector reference --- .../g4tpc/PHG4TpcElectronDrift.cc | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index c60e742b8e..6a87d10f07 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -640,7 +640,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); assert(layer_geometry); - const int npad = layer_geometry->get_phibins() / TpcDefs::NRSectors; + const int npad = layer_geometry->get_phibins() / TpcDefs::NSectors; const int start_pad = sector * npad; // ensure the hitset is prepared and consistent @@ -680,7 +680,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { std::cout << __PRETTY_FUNCTION__ << " done npad hitset from node_hitsetkey = " << node_hitsetkey << ": "; - hitset->identify(); +// hitset->identify(); } // start_pad setup if needed @@ -697,7 +697,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { std::cout << __PRETTY_FUNCTION__ << " done start_pad hitset from node_hitsetkey = " << node_hitsetkey << ": "; - hitset->identify(); +// hitset->identify(); } // ntbin setup if needed @@ -724,7 +724,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { std::cout << __PRETTY_FUNCTION__ << " done ntbin hitset from node_hitsetkey = " << node_hitsetkey << ": "; - hitset->identify(); +// hitset->identify(); } // ntbin start_tbin if needed @@ -741,7 +741,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { std::cout << __PRETTY_FUNCTION__ << " done start_tbin hitset from node_hitsetkey = " << node_hitsetkey << ": "; - hitset->identify(); +// hitset->identify(); } } // ensure the hitset is prepared and consistent if (Verbosity() > 100) @@ -761,7 +761,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) TrkrHit *temp_tpchit = temp_hit_iter->second; if ((Verbosity() > 10 && layer == print_layer) or Verbosity() > 100) { - std::cout << " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) + std::cout << __PRETTY_FUNCTION__<< " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) << " z bin " << TpcDefs::getTBin(temp_hitkey) << " energy " << temp_tpchit->getEnergy() << " eg4hit " << eg4hit << std::endl; @@ -779,6 +779,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) << "which is outside the hitset " << " in layer " << layer << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad + << " layer_geometry->get_phibins() " << layer_geometry->get_phibins() + << " layer_geometry->get_layer() " << layer_geometry->get_layer() << std::endl; continue; } @@ -790,6 +792,16 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (Verbosity() > 100 && layer == print_layer) std::cout << " ihit " << ihit << " collected energy = " << eg4hit << std::endl; + + if (Verbosity() > 100 ) + { + + std::cout << __PRETTY_FUNCTION__ << " Done with filling from temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side <<"Print content:" + << std::endl; + hitset->identify(); + } } // end loop over temp hitsets // erase all entries in the temp hitsetcontainer From 20cd914082fe0c5a605d5b25213a9d26e842cd01 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 17 Apr 2023 09:21:46 -0400 Subject: [PATCH 243/468] Set gain maps reading to OFF --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 3 ++- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index bda336a1bb..2790e82600 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -62,7 +62,8 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) : PHG4TpcPadPlane(name) { InitializeParameters(); - if(m_flagToUseGain==1)ReadGain(); + //if(m_flagToUseGain==1) + ReadGain(); RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index 36e1383c8d..5c90189f58 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -92,8 +92,8 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::array NTpcLayers; std::array SectorPhi; int m_NHits = 0; - // Using Gain maps is turned on by default - int m_flagToUseGain = 1; + // Using Gain maps is turned off by default + int m_flagToUseGain = 0; // gaussian sampling static constexpr double _nsigmas = 5; From 4a775e30f315127afad736b78ecb3594656b15a8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 17 Apr 2023 11:13:49 -0400 Subject: [PATCH 244/468] setter --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index b2921d8287..6af3745e70 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -737,6 +737,7 @@ Acts::SeedFinderConfig PHActsSiliconSeeding::configureSeeder() config.toleranceParam = m_tolerance; config.maxPtScattering = m_maxPtScattering; config.sigmaError = m_sigmaError; + config.helixcut = m_helixcut; return config; } From 07170034850c3ea44c45d03051946bf40a5d23f3 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 17 Apr 2023 11:47:31 -0400 Subject: [PATCH 245/468] prevent silent crash --- offline/packages/trackbase/ClusterErrorPara.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index cac17d5774..676d472d75 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -514,7 +514,8 @@ double ClusterErrorPara::tpc_phi_error(int layer, double alpha, TrkrCluster* clu double phierror = 0; TrkrClusterv4 *clusterv4 = dynamic_cast(cluster); - + assert( clusterv4 ); + int sector = -1; if(layer >=7 && layer < 23){ sector = 0; @@ -617,6 +618,7 @@ double ClusterErrorPara::tpc_phi_error(int layer, double alpha, TrkrCluster* clu double ClusterErrorPara::tpc_z_error(int layer, double beta, TrkrCluster* cluster){ double zerror = 0.05; TrkrClusterv4 *clusterv4 = dynamic_cast(cluster); + assert( clusterv4 ); int sector = -1; if(layer >=7 && layer < 23){ From 007a8786432c297df1a576f35a91f826a6d0f6dd Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 17 Apr 2023 14:54:43 -0400 Subject: [PATCH 246/468] speed up matcher --- .../trackbase_historic/TrackSeed_v1.cc | 1 - .../trackreco/PHSiliconTpcTrackMatching.cc | 48 +++++++++---------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed_v1.cc b/offline/packages/trackbase_historic/TrackSeed_v1.cc index 371276531d..41cf08997a 100644 --- a/offline/packages/trackbase_historic/TrackSeed_v1.cc +++ b/offline/packages/trackbase_historic/TrackSeed_v1.cc @@ -101,7 +101,6 @@ void TrackSeed_v1::circleFitByTaubin(TrkrClusterContainer *clusters, } if(positions.size() < 3) { - std::cout << "Can't circle fit less than 3 points " << std::endl; return; } diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc index dfec97b23b..b6daf183bd 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc @@ -305,7 +305,7 @@ void PHSiliconTpcTrackMatching::findEtaPhiMatches( bool eta_match = false; double si_eta = _tracklet_si->get_eta(); if( fabs(tpc_eta - si_eta) < _eta_search_win * mag) eta_match = true; -// if(!eta_match) continue; + if(!eta_match) continue; unsigned int siid = phtrk_iter_si; double si_x = _tracklet_si->get_x(); double si_y = _tracklet_si->get_y(); @@ -329,14 +329,14 @@ void PHSiliconTpcTrackMatching::findEtaPhiMatches( position_match = true; } -// if(!position_match) -// { continue; } + if(!position_match) + { continue; } bool phi_match = false; double si_phi = _tracklet_si->get_phi(_cluster_map,_tGeometry); if( fabs(tpc_phi - si_phi) < _phi_search_win * mag) phi_match = true; if( fabs( fabs(tpc_phi - si_phi) - 2.0 * M_PI) < _phi_search_win * mag ) phi_match = true; -// if(!phi_match) continue; + if(!phi_match) continue; if(Verbosity() > 3) { cout << " testing for a match for TPC track " << tpcid << " with pT " << _tracklet_tpc->get_pt() @@ -347,29 +347,27 @@ void PHSiliconTpcTrackMatching::findEtaPhiMatches( std::cout << " x search " << _x_search_win*mag << " y search " << _y_search_win*mag << " z search " << _z_search_win*mag << std::endl; } - if(eta_match && phi_match && position_match) + // got a match, add to the list + // These stubs are matched in eta, phi, x and y already + matched = true; + tpc_matches.insert(std::make_pair(tpcid, siid)); + tpc_matched_set.insert(tpcid); + + if(Verbosity() > 1) { - // got a match, add to the list - // These stubs are matched in eta, phi, x and y already - matched = true; - tpc_matches.insert(std::make_pair(tpcid, siid)); - tpc_matched_set.insert(tpcid); - - if(Verbosity() > 1) - { - cout << " found a match for TPC track " << tpcid << " with Si track " << siid << endl; - cout << " tpc_phi " << tpc_phi << " si_phi " << si_phi << " phi_match " << phi_match - << " tpc_eta " << tpc_eta << " si_eta " << si_eta << " eta_match " << eta_match << endl; - std::cout << " tpc x " << tpc_x << " si x " << si_x << " tpc y " << tpc_y << " si y " << si_y << " tpc_z " << tpc_z << " si z " << si_z << std::endl; - } - - // temporary! - if(_test_windows) - cout << " Try_silicon: pt " << tpc_pt << " tpc_phi " << tpc_phi << " si_phi " << si_phi << " dphi " << tpc_phi-si_phi - << " tpc_eta " << tpc_eta << " si_eta " << si_eta << " deta " << tpc_eta-si_eta << " tpc_x " << tpc_x << " tpc_y " << tpc_y << " tpc_z " << tpc_z - << " dx " << tpc_x - si_x << " dy " << tpc_y - si_y << " dz " << tpc_z - si_z - << endl; + cout << " found a match for TPC track " << tpcid << " with Si track " << siid << endl; + cout << " tpc_phi " << tpc_phi << " si_phi " << si_phi << " phi_match " << phi_match + << " tpc_eta " << tpc_eta << " si_eta " << si_eta << " eta_match " << eta_match << endl; + std::cout << " tpc x " << tpc_x << " si x " << si_x << " tpc y " << tpc_y << " si y " << si_y << " tpc_z " << tpc_z << " si z " << si_z << std::endl; } + + // temporary! + if(_test_windows) + cout << " Try_silicon: pt " << tpc_pt << " tpc_phi " << tpc_phi << " si_phi " << si_phi << " dphi " << tpc_phi-si_phi + << " tpc_eta " << tpc_eta << " si_eta " << si_eta << " deta " << tpc_eta-si_eta << " tpc_x " << tpc_x << " tpc_y " << tpc_y << " tpc_z " << tpc_z + << " dx " << tpc_x - si_x << " dy " << tpc_y - si_y << " dz " << tpc_z - si_z + << endl; + } // if no match found, keep tpc seed for fitting if(!matched) From e589f9f895db57ea5f627a0d5ad306f46afd1014 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 17 Apr 2023 23:43:39 -0400 Subject: [PATCH 247/468] initialize TPC hitset for all channels at InitRun and keep the memory throughout the run --- .../trackbase/TrkrHitSetContainerv2.cc | 18 +- .../g4tpc/PHG4TpcElectronDrift.cc | 233 +++++++++--------- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 2 + .../g4simulation/g4tpc/PHG4TpcPadPlane.h | 3 + .../g4tpc/PHG4TpcPadPlaneReadout.h | 28 +-- 5 files changed, 151 insertions(+), 133 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetContainerv2.cc b/offline/packages/trackbase/TrkrHitSetContainerv2.cc index ecbeeab29e..92d788f5dd 100644 --- a/offline/packages/trackbase/TrkrHitSetContainerv2.cc +++ b/offline/packages/trackbase/TrkrHitSetContainerv2.cc @@ -25,8 +25,22 @@ void TrkrHitSetContainerv2::Reset() // force rebuild of indexing map m_hitmap.clear(); - //! fast clear without calling destructor - m_hitArray.Clear("C"); + //! fast clear without calling destructor and without marking hitsets removed. + //! This is inspired by but even faster than TClonesArray::Clear() + //! We just reset hitset values and reuse the hitset objects + Int_t n = m_hitArray.GetEntriesFast(); + for (Int_t i = 0; i < n; i++) { + TObject *obj = m_hitArray.UncheckedAt(i); + if (obj) { + obj->Clear(); + obj->ResetBit( kHasUUID ); + obj->ResetBit( kIsReferenced ); + obj->SetUniqueID( 0 ); + } + } + + // alternative is to also marking hitset removed, which is not used here but optional for a v3 container + // m_hitArray.Clear("C"); } void TrkrHitSetContainerv2::identify(std::ostream& os) const diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 6a87d10f07..77a9df1416 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -303,6 +303,7 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) padplane->InitRun(topNode); padplane->CreateReadoutGeometry(topNode, seggeo); + InitTrkrHitSets(); // print all layers radii if (Verbosity()) @@ -326,6 +327,108 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +void PHG4TpcElectronDrift::InitTrkrHitSets() +{ + assert(seggeo); + assert(padplane); + assert(hitsetcontainer); + + const int min_layer = padplane->get_minLayer(); + const int n_layer = padplane->get_nLayer(); + + for (int layer = min_layer; layer < min_layer + n_layer; ++layer) + { + assert(seggeo); + PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); + assert(layer_geometry); + + const int npad = layer_geometry->get_phibins() / TpcDefs::NSectors; + + for (int side = 0; side < TpcDefs::NSides; ++side) + { + for (int sector = 0; sector < TpcDefs::NSectors; ++sector) + { + TrkrDefs::hitsetkey node_hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); + + // find or add this hitset on the node tree + TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey); + TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); + assert(hitset); + assert(hitset->getHitSetKey() == node_hitsetkey); + + const int start_pad = sector * npad; + + // prepare hitset + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << "prepare hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side << std::endl; + } + + // phi setup if needed + assert(hitset->getNPads() == 0); + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " npad is inconsistent, need to resize for temp_hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setNPads " << npad + << " This is necissary as TPC has various sizes of pad rows, which unfortunately leads to this extra memory allocation/delocation from event to event" + << std::endl; + } + hitset->setNPads(npad); + + // start_pad setup if needed + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " prepare hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setPadIndexStart " << start_pad + << std::endl; + } + hitset->setPadIndexStart(start_pad); + + // ntbin setup if needed + // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. + const int ntbin = layer_geometry->get_zbins() + 1; + const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); + assert(hitset->getNTBins() == 0); + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " prepare hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setTBins " << ntbin + << std::endl; + } + hitset->setNTBins(ntbin); + + // ntbin start_tbin if needed + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " prepare hitset with key: " + << node_hitsetkey << " in layer " << layer + << " with sector " << sector << " side " << side + << " : setTBinIndexStart " << start_tbin + << std::endl; + } + hitset->setTBinIndexStart(start_tbin); + if (Verbosity() > 100) + { + std::cout << __PRETTY_FUNCTION__ << " done start_tbin hitset from node_hitsetkey = " << node_hitsetkey << ": "; + + hitset->identify(); + } + + } // for (int sector = 0; sector< TpcDefs::NSectors; ++sector) + + } // for (int side = 0; side < TpcDefs::NSides; ++side) + + } // for(int layer = min_layer; layer < min_layer + n_layer; ++layer) +} + int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); @@ -643,110 +746,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) const int npad = layer_geometry->get_phibins() / TpcDefs::NSectors; const int start_pad = sector * npad; - // ensure the hitset is prepared and consistent - { - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side << std::endl; - } - - // phi setup if needed - if (hitset->getNPads() == npad) - { - if (Verbosity() > 2) - std::cout << __PRETTY_FUNCTION__ << " npad is consistent, no need to resize for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " hitset->getNPads() = " << hitset->getNPads() - << " : setNPads " << npad - << std::endl; - } - else - { - if (Verbosity()) - { - std::cout << __PRETTY_FUNCTION__ << " npad is inconsistent, need to resize for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setNPads " << npad - << " This is necissary as TPC has various sizes of pad rows, which unfortunately leads to this extra memory allocation/delocation from event to event" - << std::endl; - } - hitset->setNPads(npad); - } - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " done npad hitset from node_hitsetkey = " << node_hitsetkey << ": "; - -// hitset->identify(); - } - - // start_pad setup if needed - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setPadIndexStart " << start_pad - << std::endl; - } - hitset->setPadIndexStart(start_pad); - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " done start_pad hitset from node_hitsetkey = " << node_hitsetkey << ": "; - -// hitset->identify(); - } - - // ntbin setup if needed - // TODO: using a x2 larger zbins to ensure fitting extended readout time. Reduce down when needed. - const int ntbin = layer_geometry->get_zbins() + 1; - const int start_tbin = side == 0 ? 0 : layer_geometry->get_zbins(); - if (hitset->getNTBins()) - { - assert(hitset->getNTBins() == ntbin); // we do not expect ntbin to change, othertwise it is a consistency error - } - else - { - if (Verbosity()) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setTBins " << ntbin - << std::endl; - } - hitset->setNTBins(ntbin); - } - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " done ntbin hitset from node_hitsetkey = " << node_hitsetkey << ": "; - -// hitset->identify(); - } - - // ntbin start_tbin if needed - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << "ensure the hitset is prepared and consistent for temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side - << " : setTBinIndexStart " << start_tbin - << std::endl; - } - hitset->setTBinIndexStart(start_tbin); - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " done start_tbin hitset from node_hitsetkey = " << node_hitsetkey << ": "; - -// hitset->identify(); - } - } // ensure the hitset is prepared and consistent if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " done initializing hitset from node_hitsetkey = " << node_hitsetkey << ": "; + std::cout << __PRETTY_FUNCTION__ << " start with filling hitset from node_hitsetkey = " << node_hitsetkey << ": "; hitset->identify(); } @@ -761,7 +763,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) TrkrHit *temp_tpchit = temp_hit_iter->second; if ((Verbosity() > 10 && layer == print_layer) or Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__<< " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) + std::cout << __PRETTY_FUNCTION__ << " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) << " z bin " << TpcDefs::getTBin(temp_hitkey) << " energy " << temp_tpchit->getEnergy() << " eg4hit " << eg4hit << std::endl; @@ -772,16 +774,15 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (TpcDefs::getPad(temp_hitkey) < start_pad or TpcDefs::getPad(temp_hitkey) >= start_pad + npad) { - if (Verbosity()) - std::cout << __PRETTY_FUNCTION__ - << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) - << " z bin " << TpcDefs::getTBin(temp_hitkey) - << "which is outside the hitset " - << " in layer " << layer - << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad - << " layer_geometry->get_phibins() " << layer_geometry->get_phibins() - << " layer_geometry->get_layer() " << layer_geometry->get_layer() - << std::endl; + std::cout << __PRETTY_FUNCTION__ + << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) + << " z bin " << TpcDefs::getTBin(temp_hitkey) + << "which is outside the hitset " + << " in layer " << layer + << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad + << " layer_geometry->get_phibins() " << layer_geometry->get_phibins() + << " layer_geometry->get_layer() " << layer_geometry->get_layer() + << std::endl; continue; } @@ -792,13 +793,11 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (Verbosity() > 100 && layer == print_layer) std::cout << " ihit " << ihit << " collected energy = " << eg4hit << std::endl; - - if (Verbosity() > 100 ) + if (Verbosity() > 100) { - std::cout << __PRETTY_FUNCTION__ << " Done with filling from temp_hitset with key: " << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side <<"Print content:" + << " with sector " << sector << " side " << side << "Print content:" << std::endl; hitset->identify(); } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 4d3f6ff183..7f71702d15 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -41,6 +41,8 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface int process_event(PHCompositeNode *) override; int End(PHCompositeNode *) override; + void InitTrkrHitSets(); + void SetDefaultParameters() override; //! detector name diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h index ac8b7ccda3..deeb082bc0 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h @@ -36,6 +36,9 @@ class PHG4TpcPadPlane : public SubsysReco, public PHParameterInterface virtual void MapToPadPlane(TpcClusterBuilder* /*builder*/, TrkrHitSetContainer * /*single_hitsetcontainer*/, TrkrHitSetContainer * /*hitsetcontainer*/, TrkrHitTruthAssoc * /*hittruthassoc*/, const double /*x_gem*/, const double /*y_gem*/, const double /*t_gem*/, const unsigned int /*side*/, PHG4HitContainer::ConstIterator /*hiter*/, TNtuple * /*ntpad*/, TNtuple * /*nthit*/)=0;// { return {}; } void Detector(const std::string &name) { detector = name; } + virtual int get_minLayer() {return 0;} + virtual int get_nLayer() {return 0;} + protected: std::string detector; }; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index 04e926aaed..59c3aafd3d 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -4,8 +4,8 @@ #include "PHG4TpcPadPlane.h" #include "TpcClusterBuilder.h" -#include #include +#include #include #include @@ -15,7 +15,7 @@ #include class PHCompositeNode; -//class PHG4CellContainer; +// class PHG4CellContainer; class PHG4TpcCylinderGeomContainer; class PHG4TpcCylinderGeom; class TNtuple; @@ -31,17 +31,18 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane void SetDriftVelocity(double vd) override { drift_velocity = vd; } - int CreateReadoutGeometry(PHCompositeNode *topNode, PHG4TpcCylinderGeomContainer *seggeo) override; // otherwise warning of inconsistent overload since only one MapToPadPlane methow is overridden using PHG4TpcPadPlane::MapToPadPlane; - - void MapToPadPlane(TpcClusterBuilder* tpc_clustbuilder, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, const double x_gem, const double y_gem, const double t_gem, const unsigned int side, PHG4HitContainer::ConstIterator hiter, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) override; + void MapToPadPlane(TpcClusterBuilder *tpc_clustbuilder, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, const double x_gem, const double y_gem, const double t_gem, const unsigned int side, PHG4HitContainer::ConstIterator hiter, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) override; void SetDefaultParameters() override; void UpdateInternalParameters() override; + int get_minLayer() override { return MinLayer[0]; } + int get_nLayer() override { return NTpcLayers[0] + NTpcLayers[1] + NTpcLayers[2]; } + private: // void populate_rectangular_phibins(const unsigned int layernum, const double phi, const double cloud_sig_rp, std::vector &pad_phibin, std::vector &pad_phibin_share); void populate_zigzag_phibins(const unsigned int side, const unsigned int layernum, const double phi, const double cloud_sig_rp, std::vector &pad_phibin, std::vector &pad_phibin_share); @@ -70,8 +71,8 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane static const int NSectors = TpcDefs::NSectors; static const int NRSectors = TpcDefs::NRSectors; - std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dR; - std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dPhi; + std::array, NSectors>, NSides> dR; + std::array, NSectors>, NSides> dPhi; double MaxZ = NAN; double MinT = NAN; @@ -99,17 +100,16 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane std::vector pad_phibin; std::vector pad_phibin_share; std::vector adc_tbin_share; - std::array, NSides > sector_R_bias; - std::array, NSides > sector_Phi_bias; - std::array, NSides > sector_min_Phi; - std::array, NSides > sector_max_Phi; - std::array< std::array< std::vector, NRSectors >, NSides > sector_min_Phi_sectors; - std::array< std::array< std::vector, NRSectors >, NSides > sector_max_Phi_sectors; + std::array, NSides> sector_R_bias; + std::array, NSides> sector_Phi_bias; + std::array, NSides> sector_min_Phi; + std::array, NSides> sector_max_Phi; + std::array, NRSectors>, NSides> sector_min_Phi_sectors; + std::array, NRSectors>, NSides> sector_max_Phi_sectors; // return random distribution of number of electrons after amplification of GEM for each initial ionizing electron double getSingleEGEMAmplification(); gsl_rng *RandomGenerator; - }; #endif From 88ef1571ac020802fc223c1262eb3208119f1240 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 18 Apr 2023 00:54:30 -0400 Subject: [PATCH 248/468] simplify workflow for digitization --- offline/packages/trackbase/TrkrHitSetTpcv1.cc | 9 +- .../g4tpc/PHG4TpcElectronDrift.cc | 122 +---- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 1 - .../g4tpc/PHG4TpcPadPlaneReadout.cc | 472 +++++++++--------- 4 files changed, 258 insertions(+), 346 deletions(-) diff --git a/offline/packages/trackbase/TrkrHitSetTpcv1.cc b/offline/packages/trackbase/TrkrHitSetTpcv1.cc index c9ac2b2d3f..e4faa7a50f 100644 --- a/offline/packages/trackbase/TrkrHitSetTpcv1.cc +++ b/offline/packages/trackbase/TrkrHitSetTpcv1.cc @@ -15,10 +15,11 @@ void TrkrHitSetTpcv1::Reset() { - m_hitSetKey = TrkrDefs::HITSETKEYMAX; - m_StartingBCO = 0; - m_padIndexStart = 0; - m_tBinIndexStart = 0; + // not resetting properties as the hitset are used in the next events + // m_hitSetKey = TrkrDefs::HITSETKEYMAX; + // m_StartingBCO = 0; + // m_padIndexStart = 0; + // m_tBinIndexStart = 0; // ADC 2D array is zeroed but intentionally NOT deleted, // which potentially save memory allocation-deallocation ops in the next event diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 77a9df1416..83e6f15574 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -86,7 +86,6 @@ namespace PHG4TpcElectronDrift::PHG4TpcElectronDrift(const std::string &name) : SubsysReco(name) , PHParameterInterface(name) - , temp_hitsetcontainer(new TrkrHitSetContainerv1) , single_hitsetcontainer(new TrkrHitSetContainerv1) { InitializeParameters(); @@ -374,7 +373,6 @@ void PHG4TpcElectronDrift::InitTrkrHitSets() << node_hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << " : setNPads " << npad - << " This is necissary as TPC has various sizes of pad rows, which unfortunately leads to this extra memory allocation/delocation from event to event" << std::endl; } hitset->setNPads(npad); @@ -448,6 +446,12 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if (Verbosity()) std::cout << " truth clusterer was NOT a null pointer " << std::endl; } + if (Verbosity()>100) + { + std::cout << __PRETTY_FUNCTION__<< " entry. Current hitsetcontainer: " << std::endl; + hitsetcontainer->identify(); + } + static constexpr unsigned int print_layer = 18; truth_clusterer->is_embedded_track = false; std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer @@ -480,20 +484,13 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits(); unsigned int count_g4hits = 0; - // int count_electrons = 0; - - // double ecollectedhits = 0.0; - int ncollectedhits = 0; double ihit = 0; - unsigned int dump_interval = 5000; // dump temp_hitsetcontainer to the node tree after this many g4hits - unsigned int dump_counter = 0; int trkid = -1; for (auto hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter) { count_g4hits++; - dump_counter++; const double t0 = fmax(hiter->second->get_t(0), hiter->second->get_t(1)); if (t0 > max_time) @@ -672,7 +669,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } // this fills the cells and updates the hits in temp_hitsetcontainer for this drifted electron hitting the GEM stack padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(), - temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, + hitsetcontainer, hittruthassoc, x_final, y_final, t_final, side, hiter, ntpad, nthit); } // end loop over electrons for this g4hit @@ -705,111 +702,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } } - // Dump the temp_hitsetcontainer to the node tree and reset it - // - after every "dump_interval" g4hits - // - if this is the last g4hit - if (dump_counter >= dump_interval || count_g4hits == g4hit->size()) - { - // std::cout << " dump_counter " << dump_counter << " count_g4hits " << count_g4hits << std::endl; - - double eg4hit = 0.0; - TrkrHitSetContainer::ConstRange temp_hitset_range = temp_hitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); - for (TrkrHitSetContainer::ConstIterator temp_hitset_iter = temp_hitset_range.first; - temp_hitset_iter != temp_hitset_range.second; - ++temp_hitset_iter) - { - // we have an itrator to one TrkrHitSet for the Tpc from the temp_hitsetcontainer - TrkrDefs::hitsetkey node_hitsetkey = temp_hitset_iter->first; - const unsigned int layer = TrkrDefs::getLayer(node_hitsetkey); - const int sector = TpcDefs::getSectorId(node_hitsetkey); - const int side = TpcDefs::getSide(node_hitsetkey); - if (Verbosity() > 100) - std::cout << "PHG4TpcElectronDrift: temp_hitset with key: " << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side << std::endl; - - // find or add this hitset on the node tree - TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey); - TrkrHitSetTpc *hitset = dynamic_cast(node_hitsetit->second); - assert(hitset); - assert(hitset->getHitSetKey() == node_hitsetkey); - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " filling hitset from node_hitsetkey = " << node_hitsetkey << ": "; - - hitset->identify(); - } - - assert(seggeo); - PHG4TpcCylinderGeom *layer_geometry = seggeo->GetLayerCellGeom(layer); - assert(layer_geometry); - - const int npad = layer_geometry->get_phibins() / TpcDefs::NSectors; - const int start_pad = sector * npad; - - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " start with filling hitset from node_hitsetkey = " << node_hitsetkey << ": "; - - hitset->identify(); - } - - // get all of the hits from the temporary hitset - TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits(); - for (TrkrHitSet::ConstIterator temp_hit_iter = temp_hit_range.first; - temp_hit_iter != temp_hit_range.second; - ++temp_hit_iter) - { - TrkrDefs::hitkey temp_hitkey = temp_hit_iter->first; - TrkrHit *temp_tpchit = temp_hit_iter->second; - if ((Verbosity() > 10 && layer == print_layer) or Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) - << " z bin " << TpcDefs::getTBin(temp_hitkey) - << " energy " << temp_tpchit->getEnergy() << " eg4hit " << eg4hit << std::endl; - - eg4hit += temp_tpchit->getEnergy(); - // ecollectedhits += temp_tpchit->getEnergy(); - ncollectedhits++; - } - - if (TpcDefs::getPad(temp_hitkey) < start_pad or TpcDefs::getPad(temp_hitkey) >= start_pad + npad) - { - std::cout << __PRETTY_FUNCTION__ - << " WARNING: ignore an invalid hit temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey) - << " z bin " << TpcDefs::getTBin(temp_hitkey) - << "which is outside the hitset " - << " in layer " << layer - << " with sector " << sector << " side " << side << " start_pad " << start_pad << " npad " << npad - << " layer_geometry->get_phibins() " << layer_geometry->get_phibins() - << " layer_geometry->get_layer() " << layer_geometry->get_layer() - << std::endl; - continue; - } - - hitset->getTpcADC(temp_hitkey) += temp_tpchit->getEnergy(); - - } // end loop over temp hits - - if (Verbosity() > 100 && layer == print_layer) - std::cout << " ihit " << ihit << " collected energy = " << eg4hit << std::endl; - - if (Verbosity() > 100) - { - std::cout << __PRETTY_FUNCTION__ << " Done with filling from temp_hitset with key: " - << node_hitsetkey << " in layer " << layer - << " with sector " << sector << " side " << side << "Print content:" - << std::endl; - hitset->identify(); - } - } // end loop over temp hitsets - - // erase all entries in the temp hitsetcontainer - temp_hitsetcontainer->Reset(); - - // reset the dump counter - dump_counter = 0; - } // end copy of temp hitsetcontainer to node tree hitsetcontainer - ++ihit; single_hitsetcontainer->Reset(); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 7f71702d15..b8caca29c9 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -79,7 +79,6 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface TrkrTruthTrackContainer *truthtracks = nullptr; TrkrTruthTrack *current_track = nullptr; TrkrClusterContainer *truthclustercontainer = nullptr; // the TrkrClusterContainer for truth clusters - std::unique_ptr temp_hitsetcontainer; std::unique_ptr single_hitsetcontainer; std::unique_ptr padplane; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 7d789e5deb..d155dd5324 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -7,7 +7,6 @@ #include // for PHG4Hit #include - #include // Move to new storage containers @@ -16,12 +15,13 @@ #include // for TrkrHit #include #include +#include #include // for TrkrHit #include -#include #include #include +#include #include // for PHWHERE @@ -30,6 +30,7 @@ #include #include // for gsl_rng_alloc +#include #include #include #include // for _Rb_tree_cons... @@ -78,42 +79,46 @@ int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, for (int iregion = 0; iregion < 3; ++iregion) { - //int zside = 0; - for (int zside = 0; zside < 2;zside++){ + // int zside = 0; + for (int zside = 0; zside < 2; zside++) + { sector_R_bias[zside].clear(); sector_Phi_bias[zside].clear(); sector_min_Phi[zside].clear(); sector_max_Phi[zside].clear(); sector_min_Phi_sectors[zside][iregion].clear(); sector_max_Phi_sectors[zside][iregion].clear(); - //int eff_layer = 0; - for (int isector = 0; isector < NSectors; ++isector)//12 sectors + // int eff_layer = 0; + for (int isector = 0; isector < NSectors; ++isector) // 12 sectors { sector_R_bias[zside].push_back(dR[zside][isector][iregion]); sector_Phi_bias[zside].push_back(dPhi[zside][isector][iregion]); - - double sec_gap = (2*M_PI - SectorPhi[iregion]*12)/12; - double sec_max_phi = M_PI - SectorPhi[iregion]/2 - sec_gap - 2 * M_PI / 12 * isector;// * (isector+1) ; + + double sec_gap = (2 * M_PI - SectorPhi[iregion] * 12) / 12; + double sec_max_phi = M_PI - SectorPhi[iregion] / 2 - sec_gap - 2 * M_PI / 12 * isector; // * (isector+1) ; double sec_min_phi = sec_max_phi - SectorPhi[iregion]; sector_min_Phi[zside].push_back(sec_min_phi); sector_max_Phi[zside].push_back(sec_max_phi); sector_min_Phi_sectors[zside][iregion].push_back(sec_min_phi); sector_max_Phi_sectors[zside][iregion].push_back(sec_max_phi); - - }// isector + + } // isector } double sum_r = 0; for (int layer = MinLayer[iregion]; layer < MinLayer[iregion] + NTpcLayers[iregion]; ++layer) - { + { double r_length = Thickness[iregion]; - if(iregion == 0 && layer>0){ - if(layer%2==0) r_length = Thickness[4]; - else r_length = Thickness[3]; + if (iregion == 0 && layer > 0) + { + if (layer % 2 == 0) + r_length = Thickness[4]; + else + r_length = Thickness[3]; } sum_r += r_length; - } - double pad_space = (MaxRadius[iregion] - MinRadius[iregion] - sum_r)/(NTpcLayers[iregion]-1); + } + double pad_space = (MaxRadius[iregion] - MinRadius[iregion] - sum_r) / (NTpcLayers[iregion] - 1); double current_r = MinRadius[iregion]; for (int layer = MinLayer[iregion]; layer < MinLayer[iregion] + NTpcLayers[iregion]; ++layer) @@ -130,16 +135,19 @@ int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, PHG4TpcCylinderGeom *layerseggeo = new PHG4TpcCylinderGeom(); layerseggeo->set_layer(layer); - //layerseggeo->set_radius(MinRadius[iregion] + ((double) (layer - MinLayer[iregion]) + 0.5) * Thickness[iregion]); - //layerseggeo->set_thickness(Thickness[iregion]); + // layerseggeo->set_radius(MinRadius[iregion] + ((double) (layer - MinLayer[iregion]) + 0.5) * Thickness[iregion]); + // layerseggeo->set_thickness(Thickness[iregion]); double r_length = Thickness[iregion]; - if(iregion == 0 && layer>0){ - if(layer%2==0) r_length = Thickness[4]; - else r_length = Thickness[3]; + if (iregion == 0 && layer > 0) + { + if (layer % 2 == 0) + r_length = Thickness[4]; + else + r_length = Thickness[3]; } layerseggeo->set_thickness(r_length); - layerseggeo->set_radius(current_r+r_length/2); + layerseggeo->set_radius(current_r + r_length / 2); layerseggeo->set_binning(PHG4CellDefs::sizebinning); layerseggeo->set_zbins(NTBins); layerseggeo->set_zmin(MinT); @@ -171,7 +179,6 @@ int PHG4TpcPadPlaneReadout::CreateReadoutGeometry(PHCompositeNode * /*topNode*/, return 0; } - double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() { // Jin H.: For the GEM gain in sPHENIX TPC, @@ -183,18 +190,17 @@ double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() // for the single electron gain distribution - // and yes, the parameter you're looking for is of course the slope, which is the inverse gain. double nelec = gsl_ran_exponential(RandomGenerator, averageGEMGain); - //Put gain reading here + // Put gain reading here return nelec; } - void PHG4TpcPadPlaneReadout::MapToPadPlane( - TpcClusterBuilder *tpc_truth_clusterer, - TrkrHitSetContainer *single_hitsetcontainer, - TrkrHitSetContainer *hitsetcontainer, - TrkrHitTruthAssoc * /*hittruthassoc*/, - const double x_gem, const double y_gem, const double t_gem, const unsigned int side, + TpcClusterBuilder *tpc_truth_clusterer, + TrkrHitSetContainer *single_hitsetcontainer, + TrkrHitSetContainer *hitsetcontainer, + TrkrHitTruthAssoc * /*hittruthassoc*/, + const double x_gem, const double y_gem, const double t_gem, const unsigned int side, PHG4HitContainer::ConstIterator hiter, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) { // One electron per call of this method @@ -207,24 +213,29 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( rad_gem = sqrt(x_gem * x_gem + y_gem * y_gem); - // Moving electrons from dead area to a closest pad + // Moving electrons from dead area to a closest pad for (int iregion = 0; iregion < 3; ++iregion) { - double daR = 0; - if(iregion==0 || iregion==2){ - daR=1.0;//1.0cm edge to collect electrons from - }else{ - daR = MinRadius[iregion]-MaxRadius[iregion-1]; + double daR = 0; + if (iregion == 0 || iregion == 2) + { + daR = 1.0; // 1.0cm edge to collect electrons from } - if ( rad_gem <= MinRadius[iregion] && rad_gem >= MinRadius[iregion]-daR){ - if( rad_gem <= MinRadius[iregion]-daR/2){ - rad_gem = MinRadius[iregion] - (1.1*daR) ; - }else{ - rad_gem = MinRadius[iregion] + 0.1*daR; + else + { + daR = MinRadius[iregion] - MaxRadius[iregion - 1]; + } + if (rad_gem <= MinRadius[iregion] && rad_gem >= MinRadius[iregion] - daR) + { + if (rad_gem <= MinRadius[iregion] - daR / 2) + { + rad_gem = MinRadius[iregion] - (1.1 * daR); + } + else + { + rad_gem = MinRadius[iregion] + 0.1 * daR; } - } - } phi = check_phi(side, phi, rad_gem); @@ -238,7 +249,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( layeriter != layerrange.second; ++layeriter) { - double rad_low = layeriter->second->get_radius() - layeriter->second->get_thickness() / 2.0; + double rad_low = layeriter->second->get_radius() - layeriter->second->get_thickness() / 2.0; double rad_high = layeriter->second->get_radius() + layeriter->second->get_thickness() / 2.0; if (rad_gem > rad_low && rad_gem < rad_high) @@ -253,7 +264,6 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( << " layer " << hiter->second->get_layer() << " want to change to " << layernum << std::endl; hiter->second->set_layer(layernum); // have to set here, since the stepping action knows nothing about layers } - } if (layernum == 0) @@ -265,7 +275,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( const auto phibins = LayerGeom->get_phibins(); /* pass_data.nphibins = phibins; */ - const auto tbins = LayerGeom->get_zbins(); + const auto tbins = LayerGeom->get_zbins(); // Create the distribution function of charge on the pad plane around the electron position @@ -296,9 +306,9 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( populate_zigzag_phibins(side, layernum, phi, sigmaT, pad_phibin, pad_phibin_share); /* if (pad_phibin.size() == 0) { */ - /* pass_data.neff_electrons = 0; */ + /* pass_data.neff_electrons = 0; */ /* } else { */ - /* pass_data.fillPhiBins(pad_phibin); */ + /* pass_data.fillPhiBins(pad_phibin); */ /* } */ // Normalize the shares so they add up to 1 @@ -321,9 +331,9 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( adc_tbin_share.clear(); populate_tbins(t_gem, sigmaL, adc_tbin, adc_tbin_share); /* if (adc_tbin.size() == 0) { */ - /* pass_data.neff_electrons = 0; */ + /* pass_data.neff_electrons = 0; */ /* } else { */ - /* pass_data.fillTimeBins(adc_tbin); */ + /* pass_data.fillTimeBins(adc_tbin); */ /* } */ // Normalize the shares so that they add up to 1 @@ -345,7 +355,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( for (unsigned int ipad = 0; ipad < pad_phibin.size(); ++ipad) { - int pad_num = pad_phibin[ipad]; + int pad_num = pad_phibin[ipad]; double pad_share = pad_phibin_share[ipad]; for (unsigned int it = 0; it < adc_tbin.size(); ++it) @@ -357,16 +367,16 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( float neffelectrons = nelec * (pad_share) * (adc_bin_share); if (neffelectrons < neffelectrons_threshold) continue; // skip signals that will be below the noise suppression threshold - if (tbin_num >= tbins) std::cout << " Error making key: adc_tbin " << tbin_num << " ntbins " << tbins << std::endl; + if (tbin_num >= tbins) std::cout << " Error making key: adc_tbin " << tbin_num << " ntbins " << tbins << std::endl; if (pad_num >= phibins) std::cout << " Error making key: pad_phibin " << pad_num << " nphibins " << phibins << std::endl; // collect information to do simple clustering. Checks operation of PHG4CylinderCellTpcReco, and // is also useful for comparison with PHG4TpcClusterizer result when running single track events. // The only information written to the cell other than neffelectrons is tbin and pad number, so get those from geometry - double tcenter = LayerGeom->get_zcenter(tbin_num); + double tcenter = LayerGeom->get_zcenter(tbin_num); double phicenter = LayerGeom->get_phicenter(pad_num); phi_integral += phicenter * neffelectrons; - t_integral += tcenter * neffelectrons; + t_integral += tcenter * neffelectrons; weight += neffelectrons; if (Verbosity() > 1 && layernum == print_layer) std::cout << " tbin_num " << tbin_num << " tcenter " << tcenter << " pad_num " << pad_num << " phicenter " << phicenter @@ -384,39 +394,53 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( unsigned int pads_per_sector = phibins / 12; unsigned int sector = pad_num / pads_per_sector; TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layernum, sector, side); + + assert(hitsetcontainer->findHitSet(hitsetkey)); // expect all TPC hitset are pre-allocated and initialized + // Use existing hitset or add new one if needed TrkrHitSetContainer::Iterator hitsetit = hitsetcontainer->findOrAddHitSet(hitsetkey); TrkrHitSetContainer::Iterator single_hitsetit = single_hitsetcontainer->findOrAddHitSet(hitsetkey); - // generate the key for this hit, requires tbin and phibin - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad_num, (unsigned int) tbin_num); - // See if this hit already exists - TrkrHit *hit = nullptr; - hit = hitsetit->second->getHit(hitkey); - if (!hit) + // TrkrHitSetTpc hit update + TrkrHitSetTpc *hitset = dynamic_cast(hitsetit->second); + assert(hitset); + assert(hitset->getHitSetKey() == hitsetkey); + + if (Verbosity() > 1000) { - // create a new one - hit = new TrkrHitv2(); - hitsetit->second->addHitSpecificKey(hitkey, hit); + std::cout << __PRETTY_FUNCTION__ << " prepare hitset with hitsetkey " << hitsetkey + << " layer " << layernum << "|" << (int) TrkrDefs::getLayer(hitsetkey) + << " with sector " << sector << "|" << (int) TpcDefs::getSectorId(hitsetkey) + << " side " << side << "|" << (int) TpcDefs::getSide(hitsetkey) + << " pads_per_sector " << pads_per_sector + << " pad_num " << pad_num + << " LayerGeom->get_phibins() " << LayerGeom->get_phibins() + << " LayerGeom->get_layer() " << LayerGeom->get_layer() + << std::endl; + hitset->identify(); } - // Either way, add the energy to it -- adc values will be added at digitization - hit->addEnergy(neffelectrons); + assert(hitset->getNPads() == pads_per_sector); + + // generate the key for this hit, requires tbin and phibin + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad_num, (unsigned int) tbin_num); + hitset->getTpcADC(hitkey) += neffelectrons; - if (Verbosity() > 100) + if (Verbosity() > 1000) { - std::cout << __PRETTY_FUNCTION__ << " adding hit: hitkey = " - << hitkey << " pad " << TpcDefs::getPad(hitkey) - << " z bin " << TpcDefs::getTBin(hitkey) - << "which comes from input hit in hitsetkey "<get_phibins() " << LayerGeom->get_phibins() - << " LayerGeom->get_layer() " << LayerGeom->get_layer() - << std::endl; - hit->identify(); + std::cout << __PRETTY_FUNCTION__ << " done adding hit: hitkey = " + << hitkey << " pad " << TpcDefs::getPad(hitkey) + << " z bin " << TpcDefs::getTBin(hitkey) + << " neffelectrons " << neffelectrons + << "which comes from input hit in hitsetkey " << hitsetkey + << " layer " << layernum << "|" << (int) TrkrDefs::getLayer(hitsetkey) + << " with sector " << sector << "|" << (int) TpcDefs::getSectorId(hitsetkey) + << " side " << side << "|" << (int) TpcDefs::getSide(hitsetkey) + << " pads_per_sector " << pads_per_sector + << " pad_num " << pad_num + << " LayerGeom->get_phibins() " << LayerGeom->get_phibins() + << " LayerGeom->get_layer() " << LayerGeom->get_layer() + << std::endl; + hitset->identify(); } tpc_truth_clusterer->addhitset(hitsetkey, hitkey, neffelectrons); @@ -475,45 +499,53 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( m_NHits++; /* return pass_data; */ } -double PHG4TpcPadPlaneReadout::check_phi(const unsigned int side, const double phi, const double radius){ +double PHG4TpcPadPlaneReadout::check_phi(const unsigned int side, const double phi, const double radius) +{ double new_phi = phi; - int p_region=-1; + int p_region = -1; for (int iregion = 0; iregion < 3; ++iregion) - { + { if (radius < MaxRadius[iregion] && radius > MinRadius[iregion]) p_region = iregion; } - if(p_region>0){ - for(int s=0; s<12;s++){ - double daPhi = 0; - if (s==0){ - daPhi = fabs(sector_min_Phi_sectors[side][p_region][11] + 2*M_PI - sector_max_Phi_sectors[side][p_region][s]); - }else{ - daPhi = fabs(sector_min_Phi_sectors[side][p_region][s-1] - sector_max_Phi_sectors[side][p_region][s]); - } + if (p_region > 0) + { + for (int s = 0; s < 12; s++) + { + double daPhi = 0; + if (s == 0) + { + daPhi = fabs(sector_min_Phi_sectors[side][p_region][11] + 2 * M_PI - sector_max_Phi_sectors[side][p_region][s]); + } + else + { + daPhi = fabs(sector_min_Phi_sectors[side][p_region][s - 1] - sector_max_Phi_sectors[side][p_region][s]); + } double min_phi = sector_max_Phi_sectors[side][p_region][s]; - double max_phi = sector_max_Phi_sectors[side][p_region][s]+daPhi; - if (new_phi<=max_phi && new_phi>=min_phi){ - if(fabs(max_phi - new_phi) > fabs(new_phi - min_phi)){ - new_phi = min_phi-PhiBinWidth[p_region]/5;//to be changed - }else{ - new_phi = max_phi+PhiBinWidth[p_region]/5; - } - - - } - + double max_phi = sector_max_Phi_sectors[side][p_region][s] + daPhi; + if (new_phi <= max_phi && new_phi >= min_phi) + { + if (fabs(max_phi - new_phi) > fabs(new_phi - min_phi)) + { + new_phi = min_phi - PhiBinWidth[p_region] / 5; // to be changed + } + else + { + new_phi = max_phi + PhiBinWidth[p_region] / 5; + } } } - if(new_phi=-M_PI){ - new_phi += 2*M_PI; - } + } + if (new_phi < sector_min_Phi_sectors[side][p_region][11] && new_phi >= -M_PI) + { + new_phi += 2 * M_PI; + } return new_phi; } void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, const unsigned int layernum, const double phi, const double cloud_sig_rp, std::vector &phibin_pad, std::vector &phibin_pad_share) { - const double radius = LayerGeom->get_radius(); + const double radius = LayerGeom->get_radius(); const double phistepsize = LayerGeom->get_phistep(); - const auto phibins = LayerGeom->get_phibins(); + const auto phibins = LayerGeom->get_phibins(); // make the charge distribution gaussian double rphi = phi * radius; @@ -526,17 +558,16 @@ void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, co } // Get the range of phi values that completely contains all pads that touch the charge distribution - (nsigmas + 1/2 pad width) in each direction - const double philim_low_calc = phi - (_nsigmas * cloud_sig_rp / radius) - phistepsize; + const double philim_low_calc = phi - (_nsigmas * cloud_sig_rp / radius) - phistepsize; const double philim_high_calc = phi + (_nsigmas * cloud_sig_rp / radius) + phistepsize; // Find the pad range that covers this phi range const double philim_low = check_phi(side, philim_low_calc, radius); const double philim_high = check_phi(side, philim_high_calc, radius); - int phibin_low = LayerGeom->get_phibin(philim_high); + int phibin_low = LayerGeom->get_phibin(philim_high); int phibin_high = LayerGeom->get_phibin(philim_low); - int npads = phibin_high - phibin_low; - + int npads = phibin_high - phibin_low; if (Verbosity() > 1000) if (layernum == print_layer) @@ -553,7 +584,6 @@ void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, co std::array pad_parameters; std::array pad_keep; - // Now make a loop that steps through the charge distribution and evaluates the response at that point on each pad std::array overlap = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; double pads_phi[10] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}; @@ -571,8 +601,8 @@ void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, co for (int ipad = 0; ipad <= npads; ipad++) { int pad_now = phibin_low + ipad; - //if(phibin_low<0 && phibin_high<0) pad_now = phibin_high + ipad; - // check that we do not exceed the maximum number of pads, wrap if necessary + // if(phibin_low<0 && phibin_high<0) pad_now = phibin_high + ipad; + // check that we do not exceed the maximum number of pads, wrap if necessary if (pad_now >= phibins) pad_now -= phibins; pad_keep[ipad] = pad_now; @@ -584,44 +614,48 @@ void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, co if (layernum == print_layer) std::cout << " zigzags: make fpad for ipad " << ipad << " pad_now " << pad_now << " pad_rphi/2 " << pad_rphi / 2.0 << " rphi_pad_now " << rphi_pad_now << std::endl; - //} - - // use analytic integral - //for (int ipad = 0; ipad <= npads; ipad++) - //{ - //const double pitch = pad_parameters[ipad][0]; - //const double x_loc = pad_parameters[ipad][1] - rphi; - //const double sigma = cloud_sig_rp; - - const double pitch = pad_rphi / 2.0;//eshulga - double x_loc_tmp = rphi_pad_now - rphi;//eshulga - const double sigma = cloud_sig_rp;//eshulga - - // Checking if the pads are on the same side of the TPC in phi - if(fabs(sum_of_pads_phi)!= sum_of_pads_absphi){ - if(phi<-M_PI/2 && phi_now>0){ - x_loc_tmp = (phi_now - 2*M_PI) * radius - rphi; + //} + + // use analytic integral + // for (int ipad = 0; ipad <= npads; ipad++) + //{ + // const double pitch = pad_parameters[ipad][0]; + // const double x_loc = pad_parameters[ipad][1] - rphi; + // const double sigma = cloud_sig_rp; + + const double pitch = pad_rphi / 2.0; // eshulga + double x_loc_tmp = rphi_pad_now - rphi; // eshulga + const double sigma = cloud_sig_rp; // eshulga + + // Checking if the pads are on the same side of the TPC in phi + if (fabs(sum_of_pads_phi) != sum_of_pads_absphi) + { + if (phi < -M_PI / 2 && phi_now > 0) + { + x_loc_tmp = (phi_now - 2 * M_PI) * radius - rphi; } - if(phi>M_PI/2 && phi_now<0){ - x_loc_tmp = (phi_now + 2*M_PI) * radius - rphi; + if (phi > M_PI / 2 && phi_now < 0) + { + x_loc_tmp = (phi_now + 2 * M_PI) * radius - rphi; } - if(phi<0 && phi_now>0){ - x_loc_tmp = (phi_now+fabs(phi)) * radius; + if (phi < 0 && phi_now > 0) + { + x_loc_tmp = (phi_now + fabs(phi)) * radius; } - if(phi>0 && phi_now<0){ - x_loc_tmp = (2*M_PI - phi_now + phi) * radius; + if (phi > 0 && phi_now < 0) + { + x_loc_tmp = (2 * M_PI - phi_now + phi) * radius; } } const double x_loc = x_loc_tmp; // calculate fraction of the total charge on this strip - /* - this corresponds to integrating the charge distribution Gaussian function (centered on rphi and of width cloud_sig_rp), + /* + this corresponds to integrating the charge distribution Gaussian function (centered on rphi and of width cloud_sig_rp), convoluted with a strip response function, which is triangular from -pitch to +pitch, with a maximum of 1. at stript center */ overlap[ipad] = (pitch - x_loc) * (std::erf(x_loc / (M_SQRT2 * sigma)) - std::erf((x_loc - pitch) / (M_SQRT2 * sigma))) / (pitch * 2) + (pitch + x_loc) * (std::erf((x_loc + pitch) / (M_SQRT2 * sigma)) - std::erf(x_loc / (M_SQRT2 * sigma))) / (pitch * 2) + (gaus(x_loc - pitch, sigma) - gaus(x_loc, sigma)) * square(sigma) / pitch + (gaus(x_loc + pitch, sigma) - gaus(x_loc, sigma)) * square(sigma) / pitch; - } // now we have the overlap for each pad @@ -630,7 +664,7 @@ void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, co phibin_pad.push_back(pad_keep[ipad]); phibin_pad_share.push_back(overlap[ipad]); if (rad_gem < output_radius) std::cout << " zigzags: for pad " << ipad << " integral is " << overlap[ipad] << std::endl; - } + } return; } @@ -640,7 +674,7 @@ void PHG4TpcPadPlaneReadout::populate_tbins(const double t, const std::arrayget_zbin(t); if (tbin < 0 || tbin > LayerGeom->get_zbins()) { - //std::cout << " t bin is outside range, return" << std::endl; + // std::cout << " t bin is outside range, return" << std::endl; return; } @@ -756,23 +790,21 @@ void PHG4TpcPadPlaneReadout::SetDefaultParameters() set_default_int_param("tpc_minlayer_inner", 7); - //set_default_double_param("tpc_minradius_inner", 30.0); // cm - //set_default_double_param("tpc_minradius_mid", 40.0); - //set_default_double_param("tpc_minradius_outer", 60.0); -// - //set_default_double_param("tpc_maxradius_inner", 40.0); // cm - //set_default_double_param("tpc_maxradius_mid", 60.0); - //set_default_double_param("tpc_maxradius_outer", 77.0); // from Tom - - set_default_double_param("tpc_minradius_inner", 31.105);//30.0); // cm - set_default_double_param("tpc_minradius_mid", 41.153);//40.0); - set_default_double_param("tpc_minradius_outer", 58.367);//60.0); - + // set_default_double_param("tpc_minradius_inner", 30.0); // cm + // set_default_double_param("tpc_minradius_mid", 40.0); + // set_default_double_param("tpc_minradius_outer", 60.0); + // + // set_default_double_param("tpc_maxradius_inner", 40.0); // cm + // set_default_double_param("tpc_maxradius_mid", 60.0); + // set_default_double_param("tpc_maxradius_outer", 77.0); // from Tom - set_default_double_param("tpc_maxradius_inner", 40.249);//40.0); // cm - set_default_double_param("tpc_maxradius_mid", 57.475);//60.0); - set_default_double_param("tpc_maxradius_outer", 75.911);//77.0); // from Tom + set_default_double_param("tpc_minradius_inner", 31.105); // 30.0); // cm + set_default_double_param("tpc_minradius_mid", 41.153); // 40.0); + set_default_double_param("tpc_minradius_outer", 58.367); // 60.0); + set_default_double_param("tpc_maxradius_inner", 40.249); // 40.0); // cm + set_default_double_param("tpc_maxradius_mid", 57.475); // 60.0); + set_default_double_param("tpc_maxradius_outer", 75.911); // 77.0); // from Tom set_default_double_param("neffelectrons_threshold", 1.0); set_default_double_param("maxdriftlength", 105.5); // cm @@ -781,9 +813,9 @@ void PHG4TpcPadPlaneReadout::SetDefaultParameters() set_default_double_param("sampa_shaping_lead", 32.0); // ns, for 80 ns SAMPA set_default_double_param("sampa_shaping_tail", 48.0); // ns, for 80 ns SAMPA - set_default_double_param("tpc_sector_phi_inner", 0.5024);//2 * M_PI / 12 );//sector size in phi for R1 sector - set_default_double_param("tpc_sector_phi_mid", 0.5087);//2 * M_PI / 12 );//sector size in phi for R2 sector - set_default_double_param("tpc_sector_phi_outer", 0.5097);//2 * M_PI / 12 );//sector size in phi for R3 sector + set_default_double_param("tpc_sector_phi_inner", 0.5024); // 2 * M_PI / 12 );//sector size in phi for R1 sector + set_default_double_param("tpc_sector_phi_mid", 0.5087); // 2 * M_PI / 12 );//sector size in phi for R2 sector + set_default_double_param("tpc_sector_phi_outer", 0.5097); // 2 * M_PI / 12 );//sector size in phi for R3 sector set_default_int_param("ntpc_phibins_inner", 1152); set_default_int_param("ntpc_phibins_mid", 1536); @@ -791,7 +823,7 @@ void PHG4TpcPadPlaneReadout::SetDefaultParameters() // GEM Gain /* - hp (2020/09/04): gain changed from 2000 to 1400, to accomodate gas mixture change + hp (2020/09/04): gain changed from 2000 to 1400, to accomodate gas mixture change from Ne/CF4 90/10 to Ne/CF4 50/50, and keep the average charge per particle per pad constant */ set_default_double_param("gem_amplification", 1400); @@ -818,9 +850,9 @@ void PHG4TpcPadPlaneReadout::UpdateInternalParameters() MaxRadius[1] = get_double_param("tpc_maxradius_mid"); MaxRadius[2] = get_double_param("tpc_maxradius_outer"); - //Thickness[0] = NTpcLayers[0] <= 0 ? 0 : (MaxRadius[0] - MinRadius[0]) / NTpcLayers[0]; - //Thickness[1] = NTpcLayers[1] <= 0 ? 0 : (MaxRadius[1] - MinRadius[1]) / NTpcLayers[1]; - //Thickness[2] = NTpcLayers[2] <= 0 ? 0 : (MaxRadius[2] - MinRadius[2]) / NTpcLayers[2]; + // Thickness[0] = NTpcLayers[0] <= 0 ? 0 : (MaxRadius[0] - MinRadius[0]) / NTpcLayers[0]; + // Thickness[1] = NTpcLayers[1] <= 0 ? 0 : (MaxRadius[1] - MinRadius[1]) / NTpcLayers[1]; + // Thickness[2] = NTpcLayers[2] <= 0 ? 0 : (MaxRadius[2] - MinRadius[2]) / NTpcLayers[2]; MaxRadius[0] = get_double_param("tpc_maxradius_inner"); MaxRadius[1] = get_double_param("tpc_maxradius_mid"); @@ -861,68 +893,56 @@ void PHG4TpcPadPlaneReadout::UpdateInternalParameters() averageGEMGain = get_double_param("gem_amplification"); - //The modules are segmented in [-M_PI;M_PI] interval - std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dR_tmp = {{ - {{ - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.} - }}, - {{ - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.} - }} - }}; - - std::array< std::array< std::array< float,NRSectors >,NSectors >,NSides > dPhi_tmp = {{ - {{ - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.} - }}, - {{ - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.}, - {0.,0.,0.} - }} - }}; + // The modules are segmented in [-M_PI;M_PI] interval + std::array, NSectors>, NSides> dR_tmp = {{{{{0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}}}, + {{{0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}}}}}; + + std::array, NSectors>, NSides> dPhi_tmp = {{{{{0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}}}, + {{{0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}, + {0., 0., 0.}}}}}; dR = dR_tmp; dPhi = dPhi_tmp; From 4ffcbf2caeaa4dc5380f6be83c738e031d149c59 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 18 Apr 2023 09:52:12 -0400 Subject: [PATCH 249/468] testing --- .../trackreco/PHActsVertexPropagator.cc | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index d564d38676..8ec1fef312 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -215,11 +215,29 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) auto bbcmap = findNode::getClass(topNode, "BbcOut"); if(!bbcmap) { - std::cout << PHWHERE << "Can't propagate tracks as no vertex was found" - << std::endl; + if(Verbosity() > 1) + { + std::cout << PHWHERE << "Won't propagate tracks as no vertex was found" + << std::endl; + } + return false; } + float z = bbcmap->get_VertexPoint(); + float zerr = bbcmap->get_dVertexPoint(); + if(std::isnan(z) or std::isnan(zerr)) + { + if(Verbosity() > 1) + { + std::cout << PHWHERE + << "No vertex found in the event, track parameters are WRT (0,0,z_{trk})" + << std::endl; + } + + return false; + } + /// If we found no vertices in the event, propagate the tracks to 0,0,bbcz auto vertex = std::make_unique(); vertex->set_chisq(0.); @@ -228,17 +246,23 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) vertex->set_id(0); vertex->set_x(0); vertex->set_y(0); - vertex->set_z(bbcmap->get_VertexPoint()); + vertex->set_z(z); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - vertex->set_error(i, j, 20.); + vertex->set_error(i, j, 0.); } } - vertex->set_error(2,2, bbcmap->get_dVertexPoint() * bbcmap->get_dVertexPoint()); + vertex->set_error(2,2, zerr*zerr); m_vertexMap->insert(vertex.release()); - + if(Verbosity() > 1) + { + std::cout << "Set track vertex to propagate to BBC vertex " + << bbcmap->get_VertexPoint() << " +/- " + << bbcmap->get_dVertexPoint() << std::endl; + } + for (auto& [key, track] : *m_trackMap) { track->set_vertex_id(0); From 3a84c995fc7035ff026769c3fbab868b4b54d712 Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Tue, 18 Apr 2023 10:23:25 -0400 Subject: [PATCH 250/468] Tracking projection to outer radius of calorimeters. --- .../packages/trackbase_historic/SvtxTrack.h | 5 ++- .../trackreco/PHActsTrackProjection.cc | 34 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/SvtxTrack.h b/offline/packages/trackbase_historic/SvtxTrack.h index 5c62e7bffa..e2779b25d8 100644 --- a/offline/packages/trackbase_historic/SvtxTrack.h +++ b/offline/packages/trackbase_historic/SvtxTrack.h @@ -35,7 +35,10 @@ class SvtxTrack : public PHObject PRES = 0, CEMC = 1, HCALIN = 2, - HCALOUT = 3 + HCALOUT = 3, + OUTER_CEMC = 4, + OUTER_HCALIN = 5, + OUTER_HCALOUT = 6 }; ~SvtxTrack() override = default; diff --git a/offline/packages/trackreco/PHActsTrackProjection.cc b/offline/packages/trackreco/PHActsTrackProjection.cc index 288554242a..e404ed9652 100644 --- a/offline/packages/trackreco/PHActsTrackProjection.cc +++ b/offline/packages/trackreco/PHActsTrackProjection.cc @@ -41,10 +41,16 @@ PHActsTrackProjection::PHActsTrackProjection(const std::string& name) m_caloNames.push_back("CEMC"); m_caloNames.push_back("HCALIN"); m_caloNames.push_back("HCALOUT"); + m_caloNames.push_back("OUTER_CEMC"); + m_caloNames.push_back("OUTER_HCALIN"); + m_caloNames.push_back("OUTER_HCALOUT"); m_caloTypes.push_back(SvtxTrack::CEMC); m_caloTypes.push_back(SvtxTrack::HCALIN); m_caloTypes.push_back(SvtxTrack::HCALOUT); + m_caloTypes.push_back(SvtxTrack::OUTER_CEMC); + m_caloTypes.push_back(SvtxTrack::OUTER_HCALIN); + m_caloTypes.push_back(SvtxTrack::OUTER_HCALOUT); } int PHActsTrackProjection::InitRun(PHCompositeNode* topNode) @@ -98,6 +104,11 @@ int PHActsTrackProjection::process_event(PHCompositeNode* topNode) { return Fun4AllReturnCodes::ABORTEVENT; } + ret = projectTracks(layer+m_nCaloLayers); + if (ret != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } } if (Verbosity() > 1) @@ -306,6 +317,8 @@ int PHActsTrackProjection::makeCaloSurfacePtrs(PHCompositeNode* topNode) /// Default to using calo radius double caloRadius = m_towerGeomContainer->get_radius(); + double caloOuterRadius = m_towerGeomContainer->get_radius() + m_towerGeomContainer->get_thickness(); + if (m_caloRadii.find(m_caloTypes.at(caloLayer)) != m_caloRadii.end()) { caloRadius = m_caloRadii.find(m_caloTypes.at(caloLayer))->second; @@ -317,11 +330,23 @@ int PHActsTrackProjection::makeCaloSurfacePtrs(PHCompositeNode* topNode) caloRadius *= Acts::UnitConstants::cm; + if (m_caloRadii.find(m_caloTypes.at(caloLayer+m_nCaloLayers)) != m_caloRadii.end()) + { + caloOuterRadius = m_caloRadii.find(m_caloTypes.at(caloLayer+m_nCaloLayers))->second; + } + else + { + m_caloRadii.insert(std::make_pair(m_caloTypes.at(caloLayer+m_nCaloLayers), caloOuterRadius)); + } + + caloOuterRadius *= Acts::UnitConstants::cm; + /// Extend farther so that there is at least surface there, for high /// curling tracks. Can always reject later const auto eta = 2.5; const auto theta = 2. * atan(exp(-eta)); const auto halfZ = caloRadius / tan(theta) * Acts::UnitConstants::cm; + const auto halfZOuter = caloOuterRadius / tan(theta) * Acts::UnitConstants::cm; /// Make a cylindrical surface at (0,0,0) aligned along the z axis auto transform = Acts::Transform3::Identity(); @@ -330,12 +355,17 @@ int PHActsTrackProjection::makeCaloSurfacePtrs(PHCompositeNode* topNode) Acts::Surface::makeShared(transform, caloRadius, halfZ); + std::shared_ptr outer_surf = + Acts::Surface::makeShared(transform, + caloOuterRadius, + halfZOuter); if (Verbosity() > 1) { std::cout << "Creating cylindrical surface at " << caloRadius << std::endl; + std::cout << "Creating cylindrical surface at " << caloOuterRadius << std::endl; } - m_caloSurfaces.insert(std::make_pair(m_caloNames.at(caloLayer), - surf)); + m_caloSurfaces.insert(std::make_pair(m_caloNames.at(caloLayer),surf)); + m_caloSurfaces.insert(std::make_pair(m_caloNames.at(caloLayer+m_nCaloLayers), outer_surf)); } if (Verbosity() > 1) From ef27bc5af88d85521cbe75092cdaba1466aef2c8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 10:25:01 -0400 Subject: [PATCH 251/468] use CDBInterface for PHParameters --- offline/database/PHParameter/PHParameters.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/database/PHParameter/PHParameters.cc b/offline/database/PHParameter/PHParameters.cc index 5ea4ffc9b1..4957b0bd9d 100644 --- a/offline/database/PHParameter/PHParameters.cc +++ b/offline/database/PHParameter/PHParameters.cc @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include @@ -502,11 +502,12 @@ int PHParameters::ReadFromDB() int PHParameters::ReadFromCDB(const std::string &domain) { - std::string url = XploadInterface::instance()->getUrl(domain); + std::string url = CDBInterface::instance()->getUrl(domain); TFile *f = TFile::Open(url.c_str()); if (!f) { - std::cout << "could not open " << url << std::endl; + std::cout << "could not open " << url + << " for domain " << domain << std::endl; gSystem->Exit(1); } PdbParameterMap *myparm = static_cast(f->Get("PdbParameterMap")); From 8a79960dbb51680ab75be483fc1f7c567efb53de Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 10:26:25 -0400 Subject: [PATCH 252/468] create domain and cache existing ones --- offline/database/sphenixnpc/sphenixnpc.cc | 30 +++++++++++++++++++++++ offline/database/sphenixnpc/sphenixnpc.h | 4 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index 7b37755bfa..26a53d7f2c 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -112,3 +112,33 @@ int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_ } return 0; } + +int sphenixnpc::createDomain(const std::string &domain) +{ + int iret = -1; + nlohmann::json resp; + if (m_DomainCache.empty()) + { + resp = nopayloadclient::Client::getPayloadTypes(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string existent_domain = it.value().at("name"); + m_DomainCache.insert(existent_domain); + } + } + if (m_DomainCache.find(domain) == m_DomainCache.end()) + { + resp = nopayloadclient::Client::createPayloadType(domain); + iret = resp["code"]; + if (iret == 0) + { + m_DomainCache.insert(domain); + } + } + else + { + iret = 0; + } + return iret; +} diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 557c5240d2..35d0886fac 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -6,6 +6,7 @@ #include #include +#include class sphenixnpc : public nopayloadclient::Client { @@ -19,7 +20,7 @@ class sphenixnpc : public nopayloadclient::Client ~sphenixnpc(); nlohmann::json getUrlDict(long long iov); int createGlobalTag(const std::string &tagname); - + int createDomain(const std::string &domain); nlohmann::json get(const std::string &pl_type, long long iov); nlohmann::json cache_set_GlobalTag(const std::string &name); nlohmann::json clearCache() override; @@ -36,6 +37,7 @@ class sphenixnpc : public nopayloadclient::Client int m_Verbosity = 0; nlohmann::json url_dict_; // valid until global tag is switched std::string m_CachedGlobalTag; + std::set m_DomainCache; }; #endif // SPHENIXNPC_SPHENIXNPC_H From 2241b00b1de4fe95fd35c086f6baa2efdd7aaebd Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 10:29:06 -0400 Subject: [PATCH 253/468] use CDBInterface, remove obsolete CaloCalibSimpleCorrFile classes --- offline/packages/CaloReco/Makefile.am | 12 ++++++------ .../CaloReco/RawClusterBuilderTemplate.cc | 5 ++--- .../packages/CaloReco/RawTowerCalibration.cc | 17 ++--------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/offline/packages/CaloReco/Makefile.am b/offline/packages/CaloReco/Makefile.am index c071c4afc9..53f6136721 100644 --- a/offline/packages/CaloReco/Makefile.am +++ b/offline/packages/CaloReco/Makefile.am @@ -18,18 +18,18 @@ if USE_ONLINE else libcalo_reco_la_LIBADD = \ + -lcalo_io \ + -lcdbobjects \ -lCLHEP \ - -lphool \ - -lSubsysReco \ + -lffamodules \ -lgsl \ -lgslcblas \ -lg4vertex_io \ - -lcalo_io \ -lsph_onnx \ -lsphenixnpc \ - -lcaloCalibDBFile \ - -lcdbobjects \ - -lphparameter + -lphparameter \ + -lphool \ + -lSubsysReco endif AM_CPPFLAGS = \ diff --git a/offline/packages/CaloReco/RawClusterBuilderTemplate.cc b/offline/packages/CaloReco/RawClusterBuilderTemplate.cc index 59e2256e6e..a301574793 100644 --- a/offline/packages/CaloReco/RawClusterBuilderTemplate.cc +++ b/offline/packages/CaloReco/RawClusterBuilderTemplate.cc @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -99,8 +99,7 @@ void RawClusterBuilderTemplate::Detector(const std::string &d) void RawClusterBuilderTemplate::LoadProfile(const std::string &fname) { - std::string url = XploadInterface::instance()->getUrl("EMCPROFILE", fname); - + std::string url = CDBInterface::instance()->getUrl("EMCPROFILE", fname); bemc->LoadProfile(url); } diff --git a/offline/packages/CaloReco/RawTowerCalibration.cc b/offline/packages/CaloReco/RawTowerCalibration.cc index 093f5bc79c..1c571803e9 100644 --- a/offline/packages/CaloReco/RawTowerCalibration.cc +++ b/offline/packages/CaloReco/RawTowerCalibration.cc @@ -75,23 +75,10 @@ int RawTowerCalibration::InitRun(PHCompositeNode *topNode) if (_calib_algorithm == kDbfile_tbt_gain_corr) { - if (detector.c_str()[0] == 'H') - { - _cal_dbfile = (CaloCalibSimpleCorrFile *) new HcalCaloCalibSimpleCorrFilev1(); - } - else if (detector.c_str()[0] == 'C') - { - _cal_dbfile = (CaloCalibSimpleCorrFile *) new CEmcCaloCalibSimpleCorrFilev1(); - } - else - { std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ - << "kDbfile_tbt_gain_corr chosen but Detector Name not HCALOUT/IN or CEMC" + << "kDbfile_tbt_gain_corr chosen but not implemented" << std::endl; - return -999; - } - - _cal_dbfile->Open(m_CalibrationFileName.c_str()); + return Fun4AllReturnCodes::ABORTRUN; } return Fun4AllReturnCodes::EVENT_OK; From a67a9f3c787cea1bede4333c1c42724624f84588 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 18 Apr 2023 12:13:38 -0400 Subject: [PATCH 254/468] Propagate to 0 and then attach the bbc vertex if available to the track --- .../trackreco/PHActsVertexPropagator.cc | 45 +++++++++---------- .../trackreco/PHActsVertexPropagator.h | 2 +- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index 8ec1fef312..01225a9228 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -41,14 +41,6 @@ int PHActsVertexPropagator::InitRun(PHCompositeNode* topNode) } int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) { - if (m_vertexMap->size() == 0) - { - bool ret = setTrackVertexToBbc(topNode); - if(!ret) - { - return Fun4AllReturnCodes::EVENT_OK; - } - } std::vector deletedKeys; for (const auto& [trackKey, trajectory] : *m_trajectories) @@ -97,6 +89,11 @@ int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) setVtxChi2(); + if (m_vertexMap->size() == 0) + { + setTrackVertexToBbc(topNode); + } + /// Erase the trajectories that were removed from the track cleaner for (auto& key : deletedKeys) { @@ -187,12 +184,6 @@ PHActsVertexPropagator::propagateTrack( { /// create perigee surface auto actsVertex = getVertex(vtxid); - - /// BBC vertex wasn't found. Propagate to perigee at 0,0,0 - if(actsVertex(2) < -9999) - { - actsVertex = Acts::Vector3::Zero(); - } auto perigee = Acts::Surface::makeShared(actsVertex); ActsPropagator propagator(m_tGeometry); @@ -205,12 +196,18 @@ PHActsVertexPropagator::propagateTrack( Acts::Vector3 PHActsVertexPropagator::getVertex(const unsigned int vtxid) { auto svtxVertex = m_vertexMap->get(vtxid); - return Acts::Vector3(svtxVertex->get_x() * Acts::UnitConstants::cm, - svtxVertex->get_y() * Acts::UnitConstants::cm, - svtxVertex->get_z() * Acts::UnitConstants::cm); + /// check that a vertex exists + if(svtxVertex) + { + return Acts::Vector3(svtxVertex->get_x() * Acts::UnitConstants::cm, + svtxVertex->get_y() * Acts::UnitConstants::cm, + svtxVertex->get_z() * Acts::UnitConstants::cm); + } + + return Acts::Vector3::Zero(); } -bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) +void PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) { auto bbcmap = findNode::getClass(topNode, "BbcOut"); if(!bbcmap) @@ -220,8 +217,7 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) std::cout << PHWHERE << "Won't propagate tracks as no vertex was found" << std::endl; } - - return false; + return; } float z = bbcmap->get_VertexPoint(); @@ -231,14 +227,14 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) if(Verbosity() > 1) { std::cout << PHWHERE - << "No vertex found in the event, track parameters are WRT (0,0,z_{trk})" + << "No vertex found in the event, track parameters are WRT (0,0,0})" << std::endl; } - return false; + return; } - /// If we found no vertices in the event, propagate the tracks to 0,0,bbcz + /// If we found no vertices in the event, associate track to bbc auto vertex = std::make_unique(); vertex->set_chisq(0.); vertex->set_ndof(0); @@ -256,6 +252,7 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) } vertex->set_error(2,2, zerr*zerr); m_vertexMap->insert(vertex.release()); + if(Verbosity() > 1) { std::cout << "Set track vertex to propagate to BBC vertex " @@ -268,7 +265,7 @@ bool PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) track->set_vertex_id(0); } - return true; + return; } diff --git a/offline/packages/trackreco/PHActsVertexPropagator.h b/offline/packages/trackreco/PHActsVertexPropagator.h index 4111529e44..c583142628 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.h +++ b/offline/packages/trackreco/PHActsVertexPropagator.h @@ -36,7 +36,7 @@ class PHActsVertexPropagator : public SubsysReco private: int getNodes(PHCompositeNode *topNode); - bool setTrackVertexToBbc(PHCompositeNode *topNode); + void setTrackVertexToBbc(PHCompositeNode *topNode); ActsPropagator::BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters ¶ms, const unsigned int vtxid); From a14dee52526cc210f86c890291d4121cb2a6a03b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 18 Apr 2023 12:15:12 -0400 Subject: [PATCH 255/468] clang-format --- .../trackreco/PHActsVertexPropagator.cc | 83 +++++++++---------- .../trackreco/PHActsVertexPropagator.h | 6 +- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index 01225a9228..679bab3284 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -41,7 +41,6 @@ int PHActsVertexPropagator::InitRun(PHCompositeNode* topNode) } int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) { - std::vector deletedKeys; for (const auto& [trackKey, trajectory] : *m_trajectories) { @@ -79,10 +78,10 @@ int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) } else { - if(Verbosity()>1) - { - svtxTrack->identify(); - } + if (Verbosity() > 1) + { + svtxTrack->identify(); + } } } } @@ -188,53 +187,52 @@ PHActsVertexPropagator::propagateTrack( ActsPropagator propagator(m_tGeometry); propagator.verbosity(Verbosity()); - - return propagator.propagateTrack(params,perigee); - + + return propagator.propagateTrack(params, perigee); } Acts::Vector3 PHActsVertexPropagator::getVertex(const unsigned int vtxid) { auto svtxVertex = m_vertexMap->get(vtxid); /// check that a vertex exists - if(svtxVertex) - { - return Acts::Vector3(svtxVertex->get_x() * Acts::UnitConstants::cm, - svtxVertex->get_y() * Acts::UnitConstants::cm, - svtxVertex->get_z() * Acts::UnitConstants::cm); - } - + if (svtxVertex) + { + return Acts::Vector3(svtxVertex->get_x() * Acts::UnitConstants::cm, + svtxVertex->get_y() * Acts::UnitConstants::cm, + svtxVertex->get_z() * Acts::UnitConstants::cm); + } + return Acts::Vector3::Zero(); } -void PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) +void PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode* topNode) { auto bbcmap = findNode::getClass(topNode, "BbcOut"); - if(!bbcmap) + if (!bbcmap) + { + if (Verbosity() > 1) { - if(Verbosity() > 1) - { - std::cout << PHWHERE << "Won't propagate tracks as no vertex was found" - << std::endl; - } - return; + std::cout << PHWHERE << "Won't propagate tracks as no vertex was found" + << std::endl; } - + return; + } + float z = bbcmap->get_VertexPoint(); float zerr = bbcmap->get_dVertexPoint(); - if(std::isnan(z) or std::isnan(zerr)) + if (std::isnan(z) or std::isnan(zerr)) + { + if (Verbosity() > 1) { - if(Verbosity() > 1) - { - std::cout << PHWHERE - << "No vertex found in the event, track parameters are WRT (0,0,0})" - << std::endl; - } - - return; + std::cout << PHWHERE + << "No vertex found in the event, track parameters are WRT (0,0,0})" + << std::endl; } - /// If we found no vertices in the event, associate track to bbc + return; + } + + /// If we found no vertices in the event, associate track to bbc auto vertex = std::make_unique(); vertex->set_chisq(0.); vertex->set_ndof(0); @@ -250,25 +248,24 @@ void PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode *topNode) vertex->set_error(i, j, 0.); } } - vertex->set_error(2,2, zerr*zerr); + vertex->set_error(2, 2, zerr * zerr); m_vertexMap->insert(vertex.release()); - if(Verbosity() > 1) - { - std::cout << "Set track vertex to propagate to BBC vertex " - << bbcmap->get_VertexPoint() << " +/- " - << bbcmap->get_dVertexPoint() << std::endl; - } + if (Verbosity() > 1) + { + std::cout << "Set track vertex to propagate to BBC vertex " + << bbcmap->get_VertexPoint() << " +/- " + << bbcmap->get_dVertexPoint() << std::endl; + } for (auto& [key, track] : *m_trackMap) { track->set_vertex_id(0); } - return; + return; } - int PHActsVertexPropagator::End(PHCompositeNode*) { return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/trackreco/PHActsVertexPropagator.h b/offline/packages/trackreco/PHActsVertexPropagator.h index c583142628..3cac5853e5 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.h +++ b/offline/packages/trackreco/PHActsVertexPropagator.h @@ -37,9 +37,9 @@ class PHActsVertexPropagator : public SubsysReco private: int getNodes(PHCompositeNode *topNode); void setTrackVertexToBbc(PHCompositeNode *topNode); - ActsPropagator::BoundTrackParamResult - propagateTrack(const Acts::BoundTrackParameters ¶ms, - const unsigned int vtxid); + ActsPropagator::BoundTrackParamResult + propagateTrack(const Acts::BoundTrackParameters ¶ms, + const unsigned int vtxid); Acts::Vector3 getVertex(const unsigned int vtxid); void updateSvtxTrack(SvtxTrack *track, const Acts::BoundTrackParameters ¶ms); From 72035676e002261d6c3aecd0caaa2c5592a032eb Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 15:16:07 -0400 Subject: [PATCH 256/468] replace XploadInterface by CDBInterface --- offline/packages/CaloReco/CaloWaveformProcessing.cc | 8 ++++---- offline/packages/trackbase/AlignmentTransformation.cc | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index e8487ee035..47acbabc74 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -1,7 +1,7 @@ #include "CaloWaveformProcessing.h" #include "CaloWaveformFitting.h" -#include +#include #include @@ -18,15 +18,15 @@ void CaloWaveformProcessing::initialize_processing() if (m_processingtype == CaloWaveformProcessing::TEMPLATE) { std::string calibrations_repo_template = std::string(calibrationsroot) + "/WaveformProcessing/templates/" + m_template_input_file; - url_template = XploadInterface::instance()->getUrl(m_template_input_file, calibrations_repo_template); + url_template = CDBInterface::instance()->getUrl(m_template_input_file, calibrations_repo_template); m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); m_Fitter->set_nthreads(get_nthreads()); } - if (m_processingtype == CaloWaveformProcessing::ONNX) + else if (m_processingtype == CaloWaveformProcessing::ONNX) { std::string calibrations_repo_model = std::string(calibrationsroot) + "/WaveformProcessing/models/" + m_model_name; - url_onnx = XploadInterface::instance()->getUrl(m_model_name, calibrations_repo_model); + url_onnx = CDBInterface::instance()->getUrl(m_model_name, calibrations_repo_model); onnxmodule = onnxSession(url_onnx); } } diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index dc4f1781cc..c693009768 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -4,7 +4,7 @@ #include "TpcDefs.h" #include "TrkrDefs.h" -#include +#include #include @@ -53,7 +53,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { datafile.clear(); // load alignment constants file from database - alignmentParamsFile = XploadInterface::instance()->getUrl("TRACKINGALIGNMENT"); + alignmentParamsFile = CDBInterface::instance()->getUrl("TRACKINGALIGNMENT"); std::cout << "AlignmentTransformation: Reading alignment parameters from database file: " << alignmentParamsFile << std::endl; datafile.open(alignmentParamsFile); } From fd88a43f5d90a86a658fc3247ae2bb7552a95ac7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 17:05:17 -0400 Subject: [PATCH 257/468] move sims to new cdb --- .../g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc | 4 ++-- .../g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc | 4 ++-- simulation/g4simulation/g4main/PHG4Reco.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc index 94d7bb23b0..425af46b50 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc @@ -12,7 +12,7 @@ #include // for PHG4SteppingAction #include -#include +#include #include @@ -85,7 +85,7 @@ int PHG4InnerHcalSteppingAction::Init() { return 0; } - std::string url = XploadInterface::instance()->getUrl("OLD_INNER_HCAL_TILEMAP", ihcalmapname); + std::string url = CDBInterface::instance()->getUrl("OLD_INNER_HCAL_TILEMAP", ihcalmapname); if (!std::filesystem::exists(url)) { std::cout << PHWHERE << " Could not locate " << url << std::endl; diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc index 159d84d329..8f89c77a8a 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc @@ -9,7 +9,7 @@ #include -#include +#include #include @@ -100,7 +100,7 @@ int PHG4OuterHcalSteppingAction::Init() { return 0; } - std::string url = XploadInterface::instance()->getUrl("OLD_OUTER_HCAL_TILEMAP", mappingfilename); + std::string url = CDBInterface::instance()->getUrl("OLD_OUTER_HCAL_TILEMAP", mappingfilename); if (!std::filesystem::exists(url)) { std::cout << PHWHERE << " Could not locate " << url << std::endl; diff --git a/simulation/g4simulation/g4main/PHG4Reco.cc b/simulation/g4simulation/g4main/PHG4Reco.cc index 1d9b15758d..a0a2f6647f 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.cc +++ b/simulation/g4simulation/g4main/PHG4Reco.cc @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include @@ -290,7 +290,7 @@ int PHG4Reco::InitField(PHCompositeNode *topNode) if (m_FieldMapFile == "CDB") { // loading from database - std::string url = XploadInterface::instance()->getUrl("FIELDMAPBIG", m_FieldMapFile); + std::string url = CDBInterface::instance()->getUrl("FIELDMAPBIG", m_FieldMapFile); default_field_cfg.reset(new PHFieldConfigv1(m_FieldConfigType, url, m_MagneticFieldRescale)); } else if (m_FieldMapFile != "NONE") From 8fa5a0ed6c360c3544115a31476b38d43f7edad9 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 18 Apr 2023 19:12:49 -0400 Subject: [PATCH 258/468] clang-tidy, clang-format to trigger jenkins --- .../g4main/PHG4TruthInfoContainer.cc | 160 +++++++++++++----- .../g4main/PHG4TruthInfoContainer.h | 3 +- 2 files changed, 114 insertions(+), 49 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4TruthInfoContainer.cc b/simulation/g4simulation/g4main/PHG4TruthInfoContainer.cc index 8609f49474..64c840a806 100644 --- a/simulation/g4simulation/g4main/PHG4TruthInfoContainer.cc +++ b/simulation/g4simulation/g4main/PHG4TruthInfoContainer.cc @@ -23,21 +23,21 @@ PHG4TruthInfoContainer::~PHG4TruthInfoContainer() { Reset(); } void PHG4TruthInfoContainer::Reset() { - for (Iterator iter = particlemap.begin(); iter != particlemap.end(); ++iter) + for (auto& iter : particlemap) { - delete iter->second; + delete iter.second; } particlemap.clear(); - for (VtxIterator iter = vtxmap.begin(); iter != vtxmap.end(); ++iter) + for (auto& iter : vtxmap) { - delete iter->second; + delete iter.second; } vtxmap.clear(); - for (ShowerIterator iter = showermap.begin(); iter != showermap.end(); ++iter) + for (auto& iter : showermap) { - delete iter->second; + delete iter.second; } showermap.clear(); @@ -50,42 +50,38 @@ void PHG4TruthInfoContainer::Reset() void PHG4TruthInfoContainer::identify(ostream& os) const { os << "---particlemap--------------------------" << endl; - for (ConstIterator iter = particlemap.begin(); iter != particlemap.end(); ++iter) + for (auto iter : particlemap) { - os << "particle id " << iter->first << endl; - (iter->second)->identify(); + os << "particle id " << iter.first << endl; + (iter.second)->identify(); } os << "---vtxmap-------------------------------" << endl; - for (ConstVtxIterator vter = vtxmap.begin(); vter != vtxmap.end(); ++vter) + for (auto vter : vtxmap) { - os << "vtx id: " << vter->first << endl; - (vter->second)->identify(); + os << "vtx id: " << vter.first << endl; + (vter.second)->identify(); } os << "---showermap-------------------------------" << endl; - for (ConstShowerIterator ster = showermap.begin(); ster != showermap.end(); ++ster) + for (auto ster : showermap) { - os << "shower id: " << ster->first << endl; - (ster->second)->identify(); + os << "shower id: " << ster.first << endl; + (ster.second)->identify(); } os << "---list of embeded track flags-------------------" << endl; - for (std::map::const_iterator eter = particle_embed_flags.begin(); - eter != particle_embed_flags.end(); - ++eter) + for (auto particle_embed_flag : particle_embed_flags) { - os << "embeded track id: " << eter->first - << " flag: " << eter->second << endl; + os << "embeded track id: " << particle_embed_flag.first + << " flag: " << particle_embed_flag.second << endl; } os << "---list of embeded vtx flags-------------------" << endl; - for (std::map::const_iterator eter = vertex_embed_flags.begin(); - eter != vertex_embed_flags.end(); - ++eter) + for (auto vertex_embed_flag : vertex_embed_flags) { - os << "embeded vertex id: " << eter->first - << " flag: " << eter->second << endl; + os << "embeded vertex id: " << vertex_embed_flag.first + << " flag: " << vertex_embed_flag.second << endl; } os << "---primary vertex-------------------" << endl; @@ -101,7 +97,10 @@ PHG4TruthInfoContainer::AddParticle(const int trackid, PHG4Particle* newparticle ConstIterator it; bool added = false; boost::tie(it, added) = particlemap.insert(std::make_pair(key, newparticle)); - if (added) return it; + if (added) + { + return it; + } cerr << "PHG4TruthInfoContainer::AddParticle" << " - Attempt to add particle with existing trackid " @@ -119,15 +118,24 @@ PHG4Particle* PHG4TruthInfoContainer::GetParticle(const int trackid) { int key = trackid; Iterator it = particlemap.find(key); - if (it != particlemap.end()) return it->second; + if (it != particlemap.end()) + { + return it->second; + } return nullptr; } PHG4Particle* PHG4TruthInfoContainer::GetPrimaryParticle(const int trackid) { - if (trackid <= 0) return nullptr; + if (trackid <= 0) + { + return nullptr; + } Iterator it = particlemap.find(trackid); - if (it != particlemap.end()) return it->second; + if (it != particlemap.end()) + { + return it->second; + } return nullptr; } @@ -135,15 +143,24 @@ PHG4VtxPoint* PHG4TruthInfoContainer::GetVtx(const int vtxid) { int key = vtxid; VtxIterator it = vtxmap.find(key); - if (it != vtxmap.end()) return it->second; + if (it != vtxmap.end()) + { + return it->second; + } return nullptr; } PHG4VtxPoint* PHG4TruthInfoContainer::GetPrimaryVtx(const int vtxid) { - if (vtxid <= 0) return nullptr; + if (vtxid <= 0) + { + return nullptr; + } VtxIterator it = vtxmap.find(vtxid); - if (it != vtxmap.end()) return it->second; + if (it != vtxmap.end()) + { + return it->second; + } return nullptr; } @@ -151,15 +168,24 @@ PHG4Shower* PHG4TruthInfoContainer::GetShower(const int showerid) { int key = showerid; ShowerIterator it = showermap.find(key); - if (it != showermap.end()) return it->second; + if (it != showermap.end()) + { + return it->second; + } return nullptr; } PHG4Shower* PHG4TruthInfoContainer::GetPrimaryShower(const int showerid) { - if (showerid <= 0) return nullptr; + if (showerid <= 0) + { + return nullptr; + } ShowerIterator it = showermap.find(showerid); - if (it != showermap.end()) return it->second; + if (it != showermap.end()) + { + return it->second; + } return nullptr; } @@ -220,48 +246,84 @@ PHG4TruthInfoContainer::AddShower(const int id, PHG4Shower* newshower) int PHG4TruthInfoContainer::maxtrkindex() const { int key = 0; - if (!particlemap.empty()) key = particlemap.rbegin()->first; - if (key < 0) key = 0; + if (!particlemap.empty()) + { + key = particlemap.rbegin()->first; + } + if (key < 0) + { + key = 0; + } return key; } int PHG4TruthInfoContainer::mintrkindex() const { int key = 0; - if (!particlemap.empty()) key = particlemap.begin()->first; - if (key > 0) key = 0; + if (!particlemap.empty()) + { + key = particlemap.begin()->first; + } + if (key > 0) + { + key = 0; + } return key; } int PHG4TruthInfoContainer::maxvtxindex() const { int key = 0; - if (!vtxmap.empty()) key = vtxmap.rbegin()->first; - if (key < 0) key = 0; + if (!vtxmap.empty()) + { + key = vtxmap.rbegin()->first; + } + if (key < 0) + { + key = 0; + } return key; } int PHG4TruthInfoContainer::minvtxindex() const { int key = 0; - if (!vtxmap.empty()) key = vtxmap.begin()->first; - if (key > 0) key = 0; + if (!vtxmap.empty()) + { + key = vtxmap.begin()->first; + } + if (key > 0) + { + key = 0; + } return key; } int PHG4TruthInfoContainer::maxshowerindex() const { int key = 0; - if (!showermap.empty()) key = showermap.rbegin()->first; - if (key < 0) key = 0; + if (!showermap.empty()) + { + key = showermap.rbegin()->first; + } + if (key < 0) + { + key = 0; + } return key; } int PHG4TruthInfoContainer::minshowerindex() const { int key = 0; - if (!showermap.empty()) key = showermap.begin()->first; - if (key > 0) key = 0; + if (!showermap.empty()) + { + key = showermap.begin()->first; + } + if (key > 0) + { + key = 0; + } return key; } @@ -276,7 +338,9 @@ void PHG4TruthInfoContainer::delete_particle(int trackid) { Iterator it = particlemap.find(trackid); if (it != particlemap.end()) + { delete_particle(it); + } } void PHG4TruthInfoContainer::delete_vtx(VtxIterator viter) @@ -290,7 +354,9 @@ void PHG4TruthInfoContainer::delete_vtx(int vtxid) { VtxIterator it = vtxmap.find(vtxid); if (it != vtxmap.end()) + { delete_vtx(it); + } } void PHG4TruthInfoContainer::delete_shower(ShowerIterator siter) diff --git a/simulation/g4simulation/g4main/PHG4TruthInfoContainer.h b/simulation/g4simulation/g4main/PHG4TruthInfoContainer.h index ea067a884f..627586bd8b 100644 --- a/simulation/g4simulation/g4main/PHG4TruthInfoContainer.h +++ b/simulation/g4simulation/g4main/PHG4TruthInfoContainer.h @@ -38,7 +38,7 @@ class PHG4TruthInfoContainer : public PHObject PHG4TruthInfoContainer(); ~PHG4TruthInfoContainer() override; -// from PHObject + // from PHObject void Reset() override; void identify(std::ostream& os = std::cout) const override; @@ -232,7 +232,6 @@ class PHG4TruthInfoContainer : public PHObject ClassDefOverride(PHG4TruthInfoContainer, 1) }; - /** * Equality operators for the types used in the publicly accessible internal * containers of PHG4TruthInfoContainer. From a28e6ac2599be4222c9f10bd874d63194229b357 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Tue, 18 Apr 2023 22:23:43 -0400 Subject: [PATCH 259/468] Work in progress. Fixed bug in helix-surface intersection calculation. --- .../HelicalFitter.cc | 256 +++++++++++++----- .../TrackerMillepedeAlignment/HelicalFitter.h | 8 +- .../trackbase/AlignmentTransformation.cc | 122 +++++++-- .../trackbase/AlignmentTransformation.h | 3 + 4 files changed, 293 insertions(+), 96 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 1fab941148..f128fd7bfd 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -130,7 +131,6 @@ int HelicalFitter::process_event(PHCompositeNode*) correctTpcGlobalPositions( global_vec, cluskey_vec); - ////std::vector fitpars = fitClusters(global_vec, cluskey_vec); // do helical fit std::vector fitpars = TrackFitUtils::fitClusters(global_vec, cluskey_vec); // do helical fit` if(fitpars.size() == 0) continue; // discard this track, not enough clusters to fit @@ -143,13 +143,11 @@ int HelicalFitter::process_event(PHCompositeNode*) if(fittpc && fitfulltrack) { // this associates silicon clusters and adds them to the vectors - //unsigned int nsilicon = addSiliconClusters(fitpars, global_vec, cluskey_vec); unsigned int nsilicon = TrackFitUtils::addSiliconClusters(fitpars, dca_cut, _tGeometry, _cluster_map, global_vec, cluskey_vec); if(nsilicon < 3) continue; // discard this TPC seed, did not get a good match to silicon // fit the full track now fitpars.clear(); - ////fitpars = fitClusters(global_vec, cluskey_vec); // do helical fit fitpars = TrackFitUtils::fitClusters(global_vec, cluskey_vec); // do helical fit if(fitpars.size() == 0) continue; // discard this track, fit failed @@ -159,46 +157,55 @@ int HelicalFitter::process_event(PHCompositeNode*) } // get the residuals and derivatives for all clusters + for(unsigned int ivec=0;ivecfindCluster(cluskey); if(!cluster) { continue;} + unsigned int trkrid = TrkrDefs::getTrkrId(cluskey); + // What we need now is to find the point on the surface at which the helix would intersect // If we have that point, we can transform the fit back to local coords // we have fitpars for the helix and the cluster key, from which we get the surface Surface surf = _tGeometry->maps().getSurface(cluskey, cluster); Acts::Vector3 fitpoint = get_helix_surface_intersection(surf, fitpars, global); - //std::cout << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl; // fitpoint is the point where the helical fit intersects the plane of the surface - // this is what we need to get the residuals - // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; - Acts::Vector2 residual(cluster->getLocalX() - fitpoint_local(0), cluster->getLocalY() - fitpoint_local(1)); - - if(Verbosity() > 1) {std::cout << " cluster position " << global(0) << " " << global(1) << " " << global(2) << std::endl - << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl - << " fitpoint_local " << fitpoint_local(0) << " " << fitpoint_local(1) << " " << fitpoint_local(2) << std::endl - << " cluster local x " << cluster->getLocalX() << " cluster local y " << cluster->getLocalY() << std::endl - << " cluster local residual x " << residual(0) << " cluster local residual y " <transform(_tGeometry->geometry().getGeoContext()).inverse().matrix() << std::endl; + std::cout << "local-global transform " << std::endl << surf->transform(_tGeometry->geometry().getGeoContext()).matrix() << std::endl; + + auto xloc = cluster->getLocalX(); // in cm + auto zloc = cluster->getLocalY(); + if(trkrid == TrkrDefs::tpcId) { zloc = convertTimeToZ(cluskey, cluster); } + //float y = 0.0; // Because the fitpoint is on the surface, y will always be zero in local coordinates + + Acts::Vector2 residual(xloc - fitpoint_local(0), zloc - fitpoint_local(1)); + unsigned int layer = TrkrDefs::getLayer(cluskey_vec[ivec]); float phi = atan2(global(1), global(0)); - - - if(Verbosity() > 1) - { - if(layer < 7) - { - std::cout << "Local residuals: layer " << layer << " phi " << phi << " dx " << residual(0) << " dy " << residual(1) << std::endl; - } - } + float beta = atan2(global(2), sqrt(pow(global(0),2) + pow(global(1),2))); + + if(Verbosity() > 1) { + Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); + loc_check /= Acts::UnitConstants::cm; + std::cout << " layer " << layer << std::endl + << " cluster global " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl + << " fitpoint_local " << fitpoint_local(0) << " " << fitpoint_local(1) << " " << fitpoint_local(2) << std::endl + << " cluster local x " << cluster->getLocalX() << " cluster local y " << cluster->getLocalY() << std::endl + << " cluster global to local x " << loc_check(0) << " local y " << loc_check(1) << " local z " << loc_check(2) << std::endl + << " cluster local residual x " << residual(0) << " cluster local residual y " < 1) { std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } + + // provides output that can be grep'ed to make plots of input to mille + if(Verbosity() > 1) + { + if(layer < 7) + { + std::cout << "Local residualsX: layer " << layer << " phi " << phi * 180 / M_PI << " beta " << beta * 180.90 / M_PI + << " dxloc " << residual(0) << " error " << clus_sigma(0) + << " xloc " << xloc << " fitxloc " << fitpoint_local(0) + << " zglob " << global(2) << " fitzglob " << fitpoint(2) + << " xglob " << global(0) << " fitxglob " << fitpoint(0) + << " yglob " << global(1) << " fityglob " << fitpoint(1) + << " dzloc " << residual(1) + << " dxx0 " << lcl_derivative[0] << " label " << 1 << " dxy0 " << lcl_derivative[1] << " label " << 2 + << " glbl_derivative " << glbl_derivative[3] << " label " << glbl_label[3] + << std::endl; + } + } + if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} + + + getLocalDerivativesZ(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); + //getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); + getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); // in local coords alpha and dx are applied to x axis, beta and "dz" to y axis + + // provides output that can be grep'ed to make plots of input to mille + if(Verbosity() > 1) + { + if(layer < 7) + { + std::cout << "Local residualsY: layer " << layer << " phi " << phi * 180 / M_PI << " beta " << beta * 180.90 / M_PI + << " dzloc " << residual(1) << " error " << clus_sigma(1) + << " zloc " << zloc << " fitzloc " << fitpoint_local(1) + << " zglob " << global(2) << " fitzglob " << fitpoint(2) + << " xglob " << global(0) << " fitxglob " << fitpoint(0) + << " yglob " << global(1) << " fityglob " << fitpoint(1) + << " dxloc " << residual(0) + << " dzz0 " << lcl_derivative[2] << " label " << 3 << " dzzslope " << lcl_derivative[4] << " label " << 5 + << " glbl_derivative " << glbl_derivative[5] << " label " << glbl_label[5] + // << " glbl_derivative " << glbl_derivative[4] << " label " << glbl_label[4] + << std::endl; + } + } - unsigned int trkrid = TrkrDefs::getTrkrId(cluskey); - getLocalDerivativesZ(fitpoint, fitpars, lcl_derivative); - getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); if(Verbosity() > 1) { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} - } // close out this track @@ -275,12 +321,12 @@ Acts::Vector3 HelicalFitter::get_line_plane_intersection(Acts::Vector3 PCA, Acts // for a point on the plane // (p - sensor_center).sensor_normal = 0 - // The solution is: + // The solution is: float d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal); Acts::Vector3 intersection = PCA + d * tangent; - //std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; - //std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; - //std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; + std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; + std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; + std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; return intersection; } @@ -300,17 +346,19 @@ std::pair HelicalFitter::get_helix_tangent(std::ve Acts::Vector2 pca_circle = get_circle_point_pca(radius, x0, y0, global); // The radius of the PCA determines the z position: - float pca_circle_radius = pca_circle.norm(); + float pca_circle_radius = pca_circle.norm(); // radius of the PCA of the circle to the point float pca_z = pca_circle_radius * zslope + z0; Acts::Vector3 pca(pca_circle(0), pca_circle(1), pca_z); // now we want a second point on the helix so we can get a local straight line approximation to the track - // project the circle PCA vector an additional small amount and find the helix PCA to that point - float projection = 0.25; // cm - Acts::Vector3 second_point = pca + projection * pca/pca.norm(); - Acts::Vector2 second_point_pca_circle = get_circle_point_pca(radius, x0, y0, second_point); - float second_point_pca_z = pca_circle_radius * zslope + z0; - Acts::Vector3 second_point_pca(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z); + // Get the angle of the PCA relative to the fitted circle center + float angle_pca = atan2(pca_circle(1) - y0, pca_circle(0) - x0); + // calculate coords of a point at a slightly larger angle + float d_angle = 0.005; + float newx = radius * cos(angle_pca + d_angle) + x0; + float newy = radius * sin(angle_pca + d_angle) + y0; + float newz = sqrt(newx*newx+newy*newy) * zslope + z0; + Acts::Vector3 second_point_pca(newx, newy, newz); // pca and second_point_pca define a straight line approximation to the track Acts::Vector3 tangent = (second_point_pca - pca) / (second_point_pca - pca).norm(); @@ -318,6 +366,30 @@ std::pair HelicalFitter::get_helix_tangent(std::ve // get the PCA of the cluster to that line Acts::Vector3 final_pca = getPCALinePoint(global, tangent, pca); + if(Verbosity() > 2) + { + // different method for checking: + // project the circle PCA vector an additional small amount and find the helix PCA to that point + float projection = 0.25; // cm + Acts::Vector3 second_point = pca + projection * pca/pca.norm(); + Acts::Vector2 second_point_pca_circle = get_circle_point_pca(radius, x0, y0, second_point); + float second_point_pca_z = second_point_pca_circle.norm() * zslope + z0; + Acts::Vector3 second_point_pca2(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z); + Acts::Vector3 tangent2 = (second_point_pca2 - pca) / (second_point_pca2 - pca).norm(); + Acts::Vector3 final_pca2 = getPCALinePoint(global, tangent2, pca); + + std::cout << " getting tangent at angle_pca: " << angle_pca * 180.0 / M_PI << std::endl + << " pca " << pca(0) << " " << pca(1) << " " << pca(2) << std::endl + << " second_point " << second_point_pca(0) << " " << second_point_pca(1) << " " << second_point_pca(2) << std::endl + << " tangent " << tangent(0) << " " << tangent(1) << " " << tangent(2) << std::endl + << " final_pca " << final_pca(0) << " " << final_pca(1) << " " << final_pca(2) << std::endl + << " second_point2 " << second_point_pca2(0) << " " << second_point_pca2(1) << " " << second_point_pca2(2) << std::endl + << " tangent2 " << tangent2(0) << " " << tangent2(1) << " " << tangent2(2) << std::endl + << " final_pca2 " << final_pca2(0) << " " << final_pca2(1) << " " << final_pca2(2) + << std::endl; + } + + std::pair line = std::make_pair(final_pca, tangent); return line; @@ -406,10 +478,10 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); unsigned int layer = TrkrDefs::getLayer(cluster_key); - auto x = cluster->getLocalX() * 10; // mm - auto z = cluster->getLocalY() * 10; - if(trkrId == TrkrDefs::tpcId) { z = convertTimeToZ(cluster_key, cluster); } - float y = 0.0; // y is unused in local coordinates + auto x = cluster->getLocalX(); // in cm + auto y = cluster->getLocalY(); + if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } + float z = 0.0; // y is unused in local coordinates // Make a transform that applies small translations in the surface frame for(unsigned int itrans = 0; itrans < 3; ++itrans) @@ -431,8 +503,10 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac Acts::Transform3 perturbationTranslation = makePerturbationTranslation(theseTransl); - Eigen::Vector3d clusterLocalPosition (x,y,z); // follows our convention for local coords, where x and z are non zero - Eigen::Vector3d finalCoords = perturbationTranslation*(clusterLocalPosition * 10.0); // clusterLocalPosition and result both in mm + // the perturbation translation here is entirely in the local frame + // our convention has (x,y) as local, applies until Acts global rotation occurs + Eigen::Vector3d clusterLocalPosition (x,y,z); + Eigen::Vector3d finalCoords = perturbationTranslation*(clusterLocalPosition * 10.0); // convert clusterLocalPosition to mm finalCoords /= 10.0; // convert mm back to cm // have to add corrections for TPC clusters after transformation to global @@ -452,7 +526,7 @@ std::vector HelicalFitter::getDerivativesAlignmentTranslations(Ac keeper(2) -= (finalCoords(2) - z); } - if(Verbosity() > 5) + if(Verbosity() > 2) { std::cout << " AlignmentTranslationsDerivs: finalCoords(0) " << finalCoords(0) << " finalCoords(1) " << finalCoords(1) << " finalCoords(2) " << finalCoords(2) << std::endl; @@ -495,7 +569,7 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); unsigned int layer = TrkrDefs::getLayer(cluster_key); - if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } + if(trkrId == TrkrDefs::tpcId) { z = convertTimeToZ(cluster_key, cluster); } if(Verbosity() > 1) { @@ -545,7 +619,7 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve keeper(2) -= (finalLocalPosition(2) - z); } - if(Verbosity() > 5) + if(Verbosity() > 2) { std::cout << " AlignmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " finalLocalPosition(1) " << finalLocalPosition(1) << " finalLocalPosition(2) " << finalLocalPosition(2) << std::endl; @@ -594,8 +668,6 @@ std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Ve Acts::Transform3 HelicalFitter::makePerturbationTransformation(Acts::Vector3 angles) { - // Note: Here beta is applied to the z axis and gamma is applied to the y axis because the geocontext transform - // will flip those axes when transforming to global coordinates Eigen::AngleAxisd alpha(angles(0), Eigen::Vector3d::UnitX()); Eigen::AngleAxisd beta(angles(1), Eigen::Vector3d::UnitY()); Eigen::AngleAxisd gamma(angles(2), Eigen::Vector3d::UnitZ()); @@ -620,7 +692,7 @@ float HelicalFitter::convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster * double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north unsigned int side = TpcDefs::getSide(cluster_key); if(side == 0) zloc = -zloc; - float z = zloc * 10.0; + float z = zloc; // in cm return z; } @@ -811,7 +883,7 @@ Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu return clus_sigma; } -void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5]) +void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5], unsigned int layer) { float radius = fitpars[0]; float x0 = fitpars[1]; @@ -826,7 +898,7 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A // dx/dradius // increasing R changes both local x and local y very little! - float dx_dr = 0; + // float dx_dr = 0; /* OR: change R and transform fitpoint to local coords */ @@ -839,6 +911,13 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A fitpoint_local_now /= Acts::UnitConstants::cm; Acts::Vector3 dres = fitpoint_local_now - fitpoint_local; float dx_dx0 = dres(0) / dx0; + /* + std::cout << " dx/dx0 " << dx_dx0 << std::endl + << " fitpoint_local_now " << std::endl + << fitpoint_local_now << std::endl + << " fitpoint_local " << std::endl + << fitpoint_local << std::endl; + */ float dy0 = 0.01; // changing y0 changes global y by the same amount @@ -849,19 +928,28 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A fitpoint_local_now /= Acts::UnitConstants::cm; dres = fitpoint_local_now - fitpoint_local; float dx_dy0 = dres(0) / dy0; + /* + std::cout << " dx/dy0 " << dx_dy0 << std::endl + << " fitpoint_local_now " << std::endl + << fitpoint_local_now << std::endl + << " fitpoint_local " << std::endl + << fitpoint_local << std::endl; + */ if(Verbosity() > 1) { - std::cout << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; - std::cout << " LclDerivsX: dx_dx0 " << dx_dx0 << " dx_dy0 " << dx_dy0 << " dx_dr " << dx_dr << std::endl; + std::cout << " layer " << layer << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; + std::cout << " LclDerivsX: dx_dx0 " << dx_dx0 << " dx_dy0 " << dx_dy0 << std::endl; } - for(int i=0;i<5;++i) {lcl_derivative[i] = 0.0;} + for(int i=0;i& fitpars, float lcl_derivative[5]) + +void HelicalFitter::getLocalDerivativesZ(Surface surf, Acts::Vector3& fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5], unsigned int layer) { // the local coord corresponding to z is local-y. // changes in z global translate directly to y-local @@ -870,17 +958,53 @@ void HelicalFitter::getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vectortransform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); + fitpoint_local_now /= Acts::UnitConstants::cm; + Acts::Vector3 dres = fitpoint_local_now - fitpoint_local; + float dz_dz0 = dres(1) / dz0; + /* + std::cout << " dz/dz0 " << dz_dz0 << std::endl + << " fitpoint_local_now " << std::endl + << fitpoint_local_now << std::endl + << " fitpoint_local " << std::endl + << fitpoint_local << std::endl; + */ + + float dzslope = 0.01; + fitpoint_now(0) = fitpoint(0); + fitpoint_now(1) = fitpoint(1); + fitpoint_now(2) = fitpoint(2) + dzslope * cluster_radius; + fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); + fitpoint_local_now /= Acts::UnitConstants::cm; + dres = fitpoint_local_now - fitpoint_local; + float dz_dzslope = dres(1) / dzslope; + /* + std::cout << " dz/dzslope " << dz_dzslope << std::endl + << " fitpoint_local_now " << std::endl + << fitpoint_local_now << std::endl + << " fitpoint_local " << std::endl + << fitpoint_local << std::endl; + */ if(Verbosity() > 1) { - std::cout << " x " << fitpoint(0)<<" y "< angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { // y - relevant global pars are alpha, beta, gamma, dy (ipar 0,1,2,4) @@ -931,7 +1055,7 @@ void HelicalFitter::getGlobalDerivativesY( std::vector angleDeriv } } } -*/ + void HelicalFitter::getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) { @@ -946,7 +1070,7 @@ void HelicalFitter::getGlobalDerivativesZ( std::vector angleDeriv glbl_derivative[3] = translDerivs[0](2); // dz/dx = 0 glbl_derivative[4] = translDerivs[1](2); // dz/dy = 0 - glbl_derivative[5] = translDerivs[2](2); // dz/dz + glbl_derivative[5] = translDerivs[2](2); // dz/dz = 1 for(int i=0; i< NGL; ++i) { @@ -962,8 +1086,8 @@ void HelicalFitter::printBuffers(int index, Acts::Vector2 residual, Acts::Vector for (int il=0;il& fitpars, float lcl_derivative[5]); - void getLocalDerivativesZ(Acts::Vector3& fitpoint, std::vector& fitpars, float lcl_derivative[5]); + void getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, + float lcl_derivative[5], unsigned int layer); + void getLocalDerivativesZ(Surface surf, Acts::Vector3& fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, + float lcl_derivative[5], unsigned int layer); void getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - // void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); + void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_layer_fixed(unsigned int layer); diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index c07eaea5bb..2a374cfee9 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -32,7 +32,10 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { - localVerbosity = 0; + localVerbosity = 3; + + std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_translations + << " use new transforms = " << use_new_transforms << std::endl; getNodes(topNode); @@ -88,15 +91,25 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + + Acts::Transform3 transform; + if(use_new_transforms) + { + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + } + else + { + transform = makeTransform(surf, millepedeTranslation, sensorAngles); + } Acts::GeometryIdentifier id = surf->geometryId(); - + if(localVerbosity) { - //Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); + std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; std::cout << " final mvtx transform:" << std::endl << transform.matrix() << std::endl; - // std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; + Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); + std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; } transformMap->addTransform(id,transform); } @@ -112,10 +125,18 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } surf = surfMaps.getSiliconSurface(hitsetkey); - //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); - Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + + Acts::Transform3 transform; + if(use_new_transforms) + { + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + } + else + { + transform = makeTransform(surf, millepedeTranslation, sensorAngles); + } Acts::GeometryIdentifier id = surf->geometryId(); - + if(localVerbosity) { std::cout << " Add transform for INTT with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; @@ -141,10 +162,18 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) for(unsigned int subsurfkey = subsurfkey_min; subsurfkeygeometryId(); - + + Acts::Transform3 transform; + if(use_new_transforms) + { + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + } + else + { + transform = makeTransform(surf, millepedeTranslation, sensorAngles); + } + Acts::GeometryIdentifier id = surf->geometryId(); + if(localVerbosity) { std::cout << " Add transform for TPC with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; @@ -162,8 +191,16 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) millepedeTranslation = millepedeTranslation + perturbationTranslation; } surf = surfMaps.getMMSurface(hitsetkey); - //Acts::Transform3 transform = makeTransform(surf, millepedeTranslation, sensorAngles); - Acts::Transform3 transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + + Acts::Transform3 transform; + if(use_new_transforms) + { + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + } + else + { + transform = makeTransform(surf, millepedeTranslation, sensorAngles); + } Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -245,6 +282,9 @@ Eigen::Matrix3d AlignmentTransformation::modifyRotationConvention(Eigen::Matrix3 // exchanging column 2 and 3 (y with z) // flipping the signs of the original content of column 2 + // this method will exchange the y and z columns for any rotation matrix + // it therefore can convert either (x,z,y) to (x',y',z') or (x,y,z) to (x',z',y') + Eigen::Matrix3d actsRotationMatrix; actsRotationMatrix(0,0) = rotationMatrix(0,0); actsRotationMatrix(1,0) = rotationMatrix(1,0); @@ -291,6 +331,7 @@ Acts::Transform3 AlignmentTransformation::makeAffineMatrix(Eigen::Matrix3d rotat return affineMatrix; } +// currently used as the transform maker Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen::Vector3d millepedeTranslation, Eigen::Vector3d sensorAngles) { //define null matrices @@ -305,10 +346,12 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) //===================================================== - // So our beginning local position vector should be (x,z,y) - // and our MP (local) alignment translation vector should be (dx,dz,dy) - // We don't worry about the angle parameter order, since they are - // just arbitrary parameters that will be fitted to data + // Our MP (local) alignment translation vector (dx,dy,dz) + // should be converted to (dx,dz,dy) before applying the Acts transform to global + // It seems we can just interchange the x and y coordinates for this + // Swapping y and z is a rotation around the x axis, resulting in a left handed coordinate system + // why is this not a problem??? + // It does mean that the order of the rotations is different from (x,y,z), but they are just fitted free parameters //===================================================== Eigen::AngleAxisd alpha(sensorAngles(0), Eigen::Vector3d::UnitX()); @@ -318,13 +361,22 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: Eigen::Matrix3d millepedeRotation = q.matrix(); Acts::Transform3 mpRotationAffine; - mpRotationAffine.linear() = millepedeRotation; + mpRotationAffine.linear() = millepedeRotation; mpRotationAffine.translation() = nullTranslation; // create alignment translation matrix Acts::Transform3 mpTranslationAffine; - mpTranslationAffine.linear() = nullRotation; - mpTranslationAffine.translation() = millepedeTranslation; + mpTranslationAffine.linear() = nullRotation; + if(use_global_translations) + { + mpTranslationAffine.translation() = millepedeTranslation; + } + else + { + // offsets should now be in local frame, so (dx,dz,dy) + Eigen::Vector3d millepedeTranslationxzy(millepedeTranslation(0), millepedeTranslation(2), millepedeTranslation(1)); + mpTranslationAffine.translation() = millepedeTranslationxzy; + } // get the acts transform components Acts::Transform3 actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); @@ -341,19 +393,35 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: //Put them together into a combined transform - // EITHER: put the mp translations in the global frame - // Acts::Transform3 transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; - // OR (new): put the mp translations in the local coordinate frame - Acts::Transform3 transform = actsTranslationAffine * actsRotationAffine * mpTranslationAffine * mpRotationAffine; + + Acts::Transform3 transform; + if(use_global_translations) + { + // put the mp translations in the global frame + transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; + } + else + { + // put the mp translations in the local coordinate frame + transform = actsTranslationAffine * actsRotationAffine * mpTranslationAffine * mpRotationAffine; + } if(localVerbosity > 2) { std::cout << "newMakeTransform" << std::endl; + std::cout << " use_global_translations = " << use_global_translations << std::endl; std::cout << "mpRotationAffine: "<< std::endl<< mpRotationAffine.matrix() < Date: Wed, 19 Apr 2023 07:32:43 -0400 Subject: [PATCH 260/468] remove XploadInterface --- offline/framework/ffamodules/Makefile.am | 10 +- .../framework/ffamodules/XploadInterface.cc | 123 ------------------ .../framework/ffamodules/XploadInterface.h | 37 ------ 3 files changed, 3 insertions(+), 167 deletions(-) delete mode 100644 offline/framework/ffamodules/XploadInterface.cc delete mode 100644 offline/framework/ffamodules/XploadInterface.h diff --git a/offline/framework/ffamodules/Makefile.am b/offline/framework/ffamodules/Makefile.am index 12f0a809a5..8f926fb419 100644 --- a/offline/framework/ffamodules/Makefile.am +++ b/offline/framework/ffamodules/Makefile.am @@ -18,23 +18,19 @@ libffamodules_la_LIBADD = \ -lffaobjects \ -lphhepmc_io \ -lsphenixnpc \ - -lSubsysReco \ - -lxpload \ - -lstdc++fs + -lSubsysReco pkginclude_HEADERS = \ CDBInterface.h \ FlagHandler.h \ HeadReco.h \ - SyncReco.h \ - XploadInterface.h + SyncReco.h libffamodules_la_SOURCES = \ CDBInterface.cc \ FlagHandler.cc \ HeadReco.cc \ - SyncReco.cc \ - XploadInterface.cc + SyncReco.cc BUILT_SOURCES = testexternals.cc diff --git a/offline/framework/ffamodules/XploadInterface.cc b/offline/framework/ffamodules/XploadInterface.cc deleted file mode 100644 index ff78249d6f..0000000000 --- a/offline/framework/ffamodules/XploadInterface.cc +++ /dev/null @@ -1,123 +0,0 @@ -#include "XploadInterface.h" - -#include -#include - -#include -#include -#include // for SubsysReco - -#include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject -#include -#include - -#include - -#include // for uint64_t -#include // for operator<<, basic_ostream, endl -#include // for pair -#include // for vector - -XploadInterface *XploadInterface::__instance = nullptr; - -XploadInterface *XploadInterface::instance() -{ - if (__instance) - { - return __instance; - } - __instance = new XploadInterface(); - return __instance; -} - -//____________________________________________________________________________.. -XploadInterface::XploadInterface(const std::string &name) - : SubsysReco(name) -{ - Fun4AllServer *se = Fun4AllServer::instance(); - se->addNewSubsystem(this); -} - -//____________________________________________________________________________.. -int XploadInterface::End(PHCompositeNode *topNode) -{ - PHNodeIterator iter(topNode); - PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); - CdbUrlSave *cdburls = findNode::getClass(runNode, "CdbUrl"); - if (!cdburls) - { - cdburls = new CdbUrlSavev1(); - PHIODataNode *newNode = new PHIODataNode(cdburls, "CdbUrl", "PHObject"); - runNode->addNode(newNode); - } - else - { - std::set> tmp_set; - for (const auto & cdburl : *cdburls) - { - tmp_set.insert(cdburl); - } - // remove duplicates in our set - // not possible using for range loops, iterator gets invalidated - for (auto itr = m_UrlVector.cbegin(); itr != m_UrlVector.cend();) - { - if (tmp_set.find(*itr) != tmp_set.end()) - { - if (Verbosity()) - { - std::cout << "removing already saved: domain " << std::get<0>(*itr) - << ", url: " << std::get<1>(*itr) - << ", timestamp: " << std::get<2>(*itr) << std::endl; - } - itr = m_UrlVector.erase(itr); - } - else - { - ++itr; - } - } - } - for (auto &tuple : m_UrlVector) - { - cdburls->AddUrl(tuple); - } - if (Verbosity() > 0) - { - cdburls->identify(); - } - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -void XploadInterface::Print(const std::string & /* what */) const -{ - for (auto &iter : m_UrlVector) - { - std::cout << "domain: " << std::get<0>(iter) - << ", url: " << std::get<1>(iter) - << ", timestamp: " << std::get<2>(iter) << std::endl; - } -} - -std::string XploadInterface::getUrl(const std::string &domain, const std::string &filename) -{ - std::string return_url = filename; - recoConsts *rc = recoConsts::instance(); - uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP", 12345678912345); - xpload::Result result = xpload::fetch(rc->get_StringFlag("XPLOAD_TAG", "TEST"), domain, timestamp, xpload::Configurator(rc->get_StringFlag("XPLOAD_CONFIG", "sPHENIX_cdb"))); - if (!result.payload.empty()) - { - return_url = result.payload; - } - auto pret = m_UrlVector.insert(make_tuple(domain, return_url, timestamp)); - if (!pret.second && Verbosity() > 1) - { - std::cout << "duplicate entry " << domain << ", url: " << return_url - << ", time stamp: " << timestamp << std::endl; - } - return return_url; -} diff --git a/offline/framework/ffamodules/XploadInterface.h b/offline/framework/ffamodules/XploadInterface.h deleted file mode 100644 index 92093b1d53..0000000000 --- a/offline/framework/ffamodules/XploadInterface.h +++ /dev/null @@ -1,37 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef FFAMODULES_XPLOADINTERFACE_H -#define FFAMODULES_XPLOADINTERFACE_H - -#include - -#include // for uint64_t -#include -#include -#include // for tuple - -class PHCompositeNode; - -class XploadInterface : public SubsysReco -{ - public: - static XploadInterface *instance(); - - ~XploadInterface() override {} - - /// Called at the end of all processing. - int End(PHCompositeNode *topNode) override; - - void Print(const std::string &what = "ALL") const override; - - std::string getUrl(const std::string &domain, const std::string &filename = ""); - - private: - XploadInterface(const std::string &name = "XploadInterface"); - - static XploadInterface *__instance; - - std::set> m_UrlVector; -}; - -#endif // FFAMODULES_XPLOADINTERFACE_H From 4727ebfad97c332e129444ed233662460f7f6d9f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 19 Apr 2023 08:23:25 -0400 Subject: [PATCH 261/468] remove xpload --- .../g4detectors/PHG4FullProjSpacalCellReco.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc index d9b6fc7b84..b160160716 100644 --- a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc +++ b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc @@ -32,7 +32,7 @@ #include // for PHWHERE #include -#include +#include #include // for TAxis #include @@ -543,16 +543,16 @@ void PHG4FullProjSpacalCellReco::LightCollectionModel::load_data_from_CDB( const std::string &histogram_fiber_model) { recoConsts *rc = recoConsts::instance(); - xpload::Result result = xpload::fetch(rc->get_StringFlag("XPLOAD_TAG"), domain, rc->get_uint64Flag("TIMESTAMP"), xpload::Configurator(rc->get_StringFlag("XPLOAD_CONFIG"))); - if (result.payload.empty()) + std::string url = CDBInterface::instance()->getUrl(domain); + if (url.empty()) { std::cout << "No calibration for domain " << domain << " for timestamp " << rc->get_uint64Flag("TIMESTAMP") << std::endl; gSystem->Exit(1); } - TFile *fin = TFile::Open(result.payload.c_str()); + TFile *fin = TFile::Open(url.c_str()); if (!fin) { - std::cout << "could not open " << result.payload << std::endl; + std::cout << "could not open " << url << std::endl; gSystem->Exit(1); } if (data_grid_light_guide_efficiency) delete data_grid_light_guide_efficiency; From d6f97d4ab973983d084e83f899a8bb11d218310e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 19 Apr 2023 09:35:05 -0400 Subject: [PATCH 262/468] replace CaloCalibSimpleCorrFile by CDBTTree --- .../packages/CaloReco/RawTowerCalibration.cc | 97 +++++++++++++------ .../packages/CaloReco/RawTowerCalibration.h | 66 +++++-------- 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/offline/packages/CaloReco/RawTowerCalibration.cc b/offline/packages/CaloReco/RawTowerCalibration.cc index 1c571803e9..f65888ba97 100644 --- a/offline/packages/CaloReco/RawTowerCalibration.cc +++ b/offline/packages/CaloReco/RawTowerCalibration.cc @@ -11,12 +11,12 @@ #include #include -#include -#include -#include - #include +#include + +#include + #include #include @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -40,7 +42,7 @@ RawTowerCalibration::RawTowerCalibration(const std::string &name) : SubsysReco(name) , _calib_algorithm(kNo_calibration) - , detector("NONE") + , m_Detector("NONE") , _calib_tower_node_prefix("CALIB") , _raw_tower_node_prefix("RAW") , _tower_calib_params(name) @@ -48,6 +50,11 @@ RawTowerCalibration::RawTowerCalibration(const std::string &name) //_tower_type = -1; } +RawTowerCalibration::~RawTowerCalibration() +{ + delete m_CDBTTree; +} + int RawTowerCalibration::InitRun(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -58,7 +65,7 @@ int RawTowerCalibration::InitRun(PHCompositeNode *topNode) "DST")); if (!dstNode) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "DST Node missing, doing nothing." << std::endl; exit(1); } @@ -75,7 +82,7 @@ int RawTowerCalibration::InitRun(PHCompositeNode *topNode) if (_calib_algorithm == kDbfile_tbt_gain_corr) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "kDbfile_tbt_gain_corr chosen but not implemented" << std::endl; return Fun4AllReturnCodes::ABORTRUN; @@ -88,7 +95,7 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) { if (Verbosity()) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "Process event entered" << std::endl; } @@ -188,9 +195,33 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) // else if // eventally this will be done exclusively of tow_by_tow else if (_calib_algorithm == kDbfile_tbt_gain_corr) { - if (!_cal_dbfile) + if (m_Detector.c_str()[0] == 'H') + { + std::string url = CDBInterface::instance()->getUrl("HCALTBYTCORR"); + if (url.empty()) + { + std::cout << PHWHERE << " Could not get Hcal Calibration for domain HCALTBYTCORR" << std::endl; + gSystem->Exit(1); + exit(1); + } + + m_CDBTTree = new CDBTTree(url); + } + else if (m_Detector.c_str()[0] == 'C') + { + std::string url = CDBInterface::instance()->getUrl("CEMCTBYTCORR"); + if (url.empty()) + { + std::cout << PHWHERE << " Could not get Cemc Calibration for domain CEMCTBYTCORR" << std::endl; + gSystem->Exit(1); + exit(1); + } + + m_CDBTTree = new CDBTTree(url); + } + if (!m_CDBTTree) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "kDbfile_tbt_gain_corr chosen but no file loaded" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } @@ -200,8 +231,10 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) const int eta = raw_tower->get_bineta(); const int phi = raw_tower->get_binphi(); + unsigned int etaphikey = phi; + etaphikey = (etaphikey << 16U) + eta; - gain_factor = _cal_dbfile->getCorr(eta, phi); + gain_factor = m_CDBTTree->GetFloatValue(etaphikey,"etaphi"); const double raw_energy = raw_tower->get_energy(); RawTower *calib_tower = new RawTowerv2(*raw_tower); @@ -215,7 +248,7 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) } else { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << " invalid calibration algorithm #" << _calib_algorithm << std::endl; @@ -273,9 +306,9 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) } else if (_calib_algorithm == kDbfile_tbt_gain_corr) { - if (!_cal_dbfile) + if (!m_CDBTTree) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "kDbfile_tbt_gain_corr chosen but no file loaded" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } @@ -283,15 +316,17 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) float gain_factor = -888; const int eta = _raw_towerinfos->getTowerEtaBin(key); const int phi = _raw_towerinfos->getTowerPhiBin(key); + unsigned int etaphikey = phi; + etaphikey = (etaphikey << 16U) + eta; - gain_factor = _cal_dbfile->getCorr(eta, phi); + gain_factor = m_CDBTTree->GetFloatValue(etaphikey,"etaphi"); const double raw_energy = raw_tower->get_energy(); float corr_energy = raw_energy * gain_factor * _calib_const_GeV_ADC; calib_tower->set_energy(corr_energy); } else { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << " invalid calibration algorithm #" << _calib_algorithm << std::endl; @@ -331,7 +366,7 @@ int RawTowerCalibration::process_event(PHCompositeNode * /*topNode*/) if (Verbosity()) { - std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "input sum energy = " << _raw_towers->getTotalEdep() << ", output sum digitalized value = " << _calib_towers->getTotalEdep() << std::endl; @@ -351,18 +386,18 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) "PHCompositeNode", "RUN")); if (!runNode) { - std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "Run Node missing, doing nothing." << std::endl; throw std::runtime_error( "Failed to find Run node in RawTowerCalibration::CreateNodes"); } - TowerGeomNodeName = "TOWERGEOM_" + detector; + TowerGeomNodeName = "TOWERGEOM_" + m_Detector; rawtowergeom = findNode::getClass(topNode, TowerGeomNodeName); if (!rawtowergeom) { - std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << " " << TowerGeomNodeName << " Node missing, doing bail out!" << std::endl; throw std::runtime_error( @@ -378,7 +413,7 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) "PHCompositeNode", "DST")); if (!dstNode) { - std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << "DST Node missing, doing nothing." << std::endl; throw std::runtime_error( "Failed to find DST node in RawTowerCalibration::CreateNodes"); @@ -386,12 +421,12 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) if (m_UseTowerInfo != 1) { - RawTowerNodeName = "TOWER_" + _raw_tower_node_prefix + "_" + detector; + RawTowerNodeName = "TOWER_" + _raw_tower_node_prefix + "_" + m_Detector; _raw_towers = findNode::getClass(dstNode, RawTowerNodeName); if (!_raw_towers) { - std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << " " << RawTowerNodeName << " Node missing, doing bail out!" << std::endl; throw std::runtime_error( @@ -400,11 +435,11 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) } if (m_UseTowerInfo > 0) { - RawTowerInfoNodeName = "TOWERINFO_" + _raw_tower_node_prefix + "_" + detector; + RawTowerInfoNodeName = "TOWERINFO_" + _raw_tower_node_prefix + "_" + m_Detector; _raw_towerinfos = findNode::getClass(dstNode, RawTowerInfoNodeName); if (!_raw_towerinfos) { - std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_Detector << "::" << __PRETTY_FUNCTION__ << " " << RawTowerInfoNodeName << " Node missing, doing bail out!" << std::endl; throw std::runtime_error( @@ -415,17 +450,17 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) // Create the tower nodes on the tree PHNodeIterator dstiter(dstNode); PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst( - "PHCompositeNode", detector)); + "PHCompositeNode", m_Detector)); if (!DetNode) { - DetNode = new PHCompositeNode(detector); + DetNode = new PHCompositeNode(m_Detector); dstNode->addNode(DetNode); } // Be careful as a previous calibrator may have been registered for this detector if (m_UseTowerInfo != 1) { - CaliTowerNodeName = "TOWER_" + _calib_tower_node_prefix + "_" + detector; + CaliTowerNodeName = "TOWER_" + _calib_tower_node_prefix + "_" + m_Detector; _calib_towers = findNode::getClass(DetNode, CaliTowerNodeName); if (!_calib_towers) @@ -437,16 +472,16 @@ void RawTowerCalibration::CreateNodes(PHCompositeNode *topNode) } if (m_UseTowerInfo > 0) { - CaliTowerInfoNodeName = "TOWERINFO_" + _calib_tower_node_prefix + "_" + detector; + CaliTowerInfoNodeName = "TOWERINFO_" + _calib_tower_node_prefix + "_" + m_Detector; _calib_towerinfos = findNode::getClass(DetNode, CaliTowerInfoNodeName); if (!_calib_towerinfos) { TowerInfoContainerv1::DETECTOR detec; - if (detector == "CEMC") + if (m_Detector == "CEMC") { detec = TowerInfoContainer::DETECTOR::EMCAL; } - else if (detector == "HCALIN" || detector == "HCALOUT") + else if (m_Detector == "HCALIN" || m_Detector == "HCALOUT") { detec = TowerInfoContainer::DETECTOR::HCAL; } diff --git a/offline/packages/CaloReco/RawTowerCalibration.h b/offline/packages/CaloReco/RawTowerCalibration.h index f464dc449e..edeab81e43 100644 --- a/offline/packages/CaloReco/RawTowerCalibration.h +++ b/offline/packages/CaloReco/RawTowerCalibration.h @@ -9,7 +9,7 @@ #include #include -class CaloCalibSimpleCorrFile; +class CDBTTree; class PHCompositeNode; class RawTowerContainer; class TowerInfoContainerv1; @@ -22,21 +22,17 @@ class RawTowerCalibration : public SubsysReco { public: RawTowerCalibration(const std::string &name = "RawTowerCalibration"); - ~RawTowerCalibration() override - { - } + ~RawTowerCalibration() override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void - Detector(const std::string &d) + void Detector(const std::string &d) { - detector = d; + m_Detector = d; _tower_calib_params.set_name(d); } - void - TowerType(const int type) + void TowerType(const int type) { _tower_type = type; } @@ -62,80 +58,67 @@ class RawTowerCalibration : public SubsysReco kBothTowers = 2 }; - enu_calib_algorithm - get_calib_algorithm() const + enu_calib_algorithm get_calib_algorithm() const { return _calib_algorithm; } - void - set_calib_algorithm(enu_calib_algorithm calibAlgorithm) + void set_calib_algorithm(enu_calib_algorithm calibAlgorithm) { _calib_algorithm = calibAlgorithm; } - double - get_calib_const_GeV_ADC() const + double get_calib_const_GeV_ADC() const { return _calib_const_GeV_ADC; } - void - set_calib_const_GeV_ADC(double calibConstGeVAdc) + void set_calib_const_GeV_ADC(double calibConstGeVAdc) { _calib_const_GeV_ADC = calibConstGeVAdc; } - void - set_variable_GeV_ADC(const bool value) + void set_variable_GeV_ADC(const bool value) { _GeV_ADC_file = value; } - std::string - get_calib_tower_node_prefix() const + std::string get_calib_tower_node_prefix() const { return _calib_tower_node_prefix; } - void - set_calib_tower_node_prefix(const std::string &calibTowerNodePrefix) + void set_calib_tower_node_prefix(const std::string &calibTowerNodePrefix) { _calib_tower_node_prefix = calibTowerNodePrefix; } - double - get_pedstal_ADC() const + double get_pedstal_ADC() const { return _pedstal_ADC; } - void - set_pedstal_ADC(double pedstalAdc) + void set_pedstal_ADC(double pedstalAdc) { _pedstal_ADC = pedstalAdc; } - void - set_variable_pedestal(const bool value) + void set_variable_pedestal(const bool value) { _pedestal_file = value; } - std::string - get_raw_tower_node_prefix() const + std::string get_raw_tower_node_prefix() const { return _raw_tower_node_prefix; } - void - set_raw_tower_node_prefix(const std::string &rawTowerNodePrefix) + void set_raw_tower_node_prefix(const std::string &rawTowerNodePrefix) { _raw_tower_node_prefix = rawTowerNodePrefix; } - void - set_zero_suppression_GeV(double) + void set_zero_suppression_GeV(double) { std::cout << "RawTowerCalibration::set_zero_suppression_GeV is deprecated!" << std::endl << " See discussion at https://github.com/sPHENIX-Collaboration/coresoftware/pull/867" << std::endl @@ -143,8 +126,7 @@ class RawTowerCalibration : public SubsysReco } //! Get the parameters for update. Useful fields are listed in SetDefaultParameters(); - PHParameters & - GetCalibrationParameters() + PHParameters &GetCalibrationParameters() { return _tower_calib_params; } @@ -164,10 +146,8 @@ class RawTowerCalibration : public SubsysReco } protected: - void - CreateNodes(PHCompositeNode *topNode); + void CreateNodes(PHCompositeNode *topNode); - enu_calib_algorithm _calib_algorithm; RawTowerContainer *_calib_towers = nullptr; RawTowerContainer *_raw_towers = nullptr; @@ -177,7 +157,9 @@ class RawTowerCalibration : public SubsysReco RawTowerGeomContainer *rawtowergeom = nullptr; - std::string detector; + enu_calib_algorithm _calib_algorithm; + + std::string m_Detector; std::string RawTowerNodeName; std::string RawTowerInfoNodeName; std::string CaliTowerNodeName; @@ -208,7 +190,7 @@ class RawTowerCalibration : public SubsysReco std::string m_CalibrationFileName; bool m_UseConditionsDB = false; - CaloCalibSimpleCorrFile *_cal_dbfile = nullptr; + CDBTTree *m_CDBTTree = nullptr; RawTowerCalibration::ProcessTowerType m_UseTowerInfo = RawTowerCalibration::ProcessTowerType::kBothTowers; // 0 just produce RawTowers, 1 just produce TowerInfo objects, and 2 produce both }; From 384cce0494b9f753bb8d5113b62234f3eda436f7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 19 Apr 2023 09:43:17 -0400 Subject: [PATCH 263/468] replace CaloCalibSimpleCorrFile by CDBTTree --- simulation/g4simulation/g4calo/Makefile.am | 12 ++--- .../g4calo/RawTowerBuilderByHitIndex.cc | 4 +- .../g4simulation/g4calo/RawTowerDigitizer.cc | 47 ++++++++++++------- .../g4simulation/g4calo/RawTowerDigitizer.h | 4 +- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/simulation/g4simulation/g4calo/Makefile.am b/simulation/g4simulation/g4calo/Makefile.am index 080ec27a94..ca4d138a0a 100644 --- a/simulation/g4simulation/g4calo/Makefile.am +++ b/simulation/g4simulation/g4calo/Makefile.am @@ -31,17 +31,17 @@ libg4calo_la_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib libg4calo_la_LIBADD = \ - -lphool \ - -lSubsysReco \ + -lcalo_io \ + -lcdbobjects \ -lfun4all \ -lg4detectors_io \ -lg4testbench \ - -lphg4hit \ - -lphparameter \ -lgsl \ -lgslcblas \ - -lcaloCalibDBFile \ - -lcalo_io + -lphool \ + -lphg4hit \ + -lphparameter \ + -lSubsysReco ################################################ # linking tests diff --git a/simulation/g4simulation/g4calo/RawTowerBuilderByHitIndex.cc b/simulation/g4simulation/g4calo/RawTowerBuilderByHitIndex.cc index edc660c119..0e35184566 100644 --- a/simulation/g4simulation/g4calo/RawTowerBuilderByHitIndex.cc +++ b/simulation/g4simulation/g4calo/RawTowerBuilderByHitIndex.cc @@ -113,7 +113,7 @@ int RawTowerBuilderByHitIndex::process_event(PHCompositeNode *topNode) m_Towers->AddTower(tower->get_id(), tower); } - tower->add_ecell((g4hit_i->get_index_j() << 16) + g4hit_i->get_index_k(), g4hit_i->get_light_yield()); + tower->add_ecell((g4hit_i->get_index_j() << 16U) + g4hit_i->get_index_k(), g4hit_i->get_light_yield()); tower->set_energy(tower->get_energy() + g4hit_i->get_light_yield()); tower->add_eshower(g4hit_i->get_shower_id(), g4hit_i->get_edep()); } @@ -228,7 +228,7 @@ bool RawTowerBuilderByHitIndex::ReadGeometryFromTable() while (getline(istream_mapping, line_mapping)) { /* Skip lines starting with / including a '#' */ - if (line_mapping.find("#") != std::string::npos) + if (line_mapping.find('#') != std::string::npos) { if (Verbosity() > 0) { diff --git a/simulation/g4simulation/g4calo/RawTowerDigitizer.cc b/simulation/g4simulation/g4calo/RawTowerDigitizer.cc index c68513b8af..4b00f313dc 100644 --- a/simulation/g4simulation/g4calo/RawTowerDigitizer.cc +++ b/simulation/g4simulation/g4calo/RawTowerDigitizer.cc @@ -13,15 +13,16 @@ #include #include -#include -#include -#include +#include + +#include + +#include #include // for Fun4AllBase::VERBOSITY_MORE #include #include // for SubsysReco -#include #include #include @@ -59,6 +60,7 @@ RawTowerDigitizer::RawTowerDigitizer(const std::string &name) RawTowerDigitizer::~RawTowerDigitizer() { gsl_rng_free(m_RandomGenerator); + delete m_CDBTTree; } void RawTowerDigitizer::set_seed(const unsigned int iseed) @@ -95,11 +97,27 @@ int RawTowerDigitizer::InitRun(PHCompositeNode *topNode) { if (m_Detector.c_str()[0] == 'H') { - m_CalDBFile = new HcalCaloCalibSimpleCorrFilev1(); + std::string url = CDBInterface::instance()->getUrl("HCALGAINSCORR"); + if (url.empty()) + { + std::cout << PHWHERE << " Could not get Hcal Calibration for domain HCALGAINSCORR" << std::endl; + gSystem->Exit(1); + exit(1); + } + + m_CDBTTree = new CDBTTree(url); } else if (m_Detector.c_str()[0] == 'C') { - m_CalDBFile = new CEmcCaloCalibSimpleCorrFilev1(); + std::string url = CDBInterface::instance()->getUrl("CEMCGAINSCORR"); + if (url.empty()) + { + std::cout << PHWHERE << " Could not get Cemc Calibration for domain CEMCGAINSCORR" << std::endl; + gSystem->Exit(1); + exit(1); + } + + m_CDBTTree = new CDBTTree(url); } else { @@ -108,15 +126,6 @@ int RawTowerDigitizer::InitRun(PHCompositeNode *topNode) << std::endl; gSystem->Exit(1); } - - if (!m_DecalFileName.empty()) - { - m_CalDBFile->Open(m_DecalFileName.c_str()); - } - else - { - m_Decal = false; - } //warnings for bad file names handled inside Open } @@ -254,7 +263,9 @@ int RawTowerDigitizer::process_event(PHCompositeNode */**topNode*/) { if (m_DoDecal && m_Decal) { - float decal_fctr = m_CalDBFile->getCorr(eta, phi); + unsigned int etaphikey = phi; + etaphikey = (etaphikey << 16U) + eta; + float decal_fctr = m_CDBTTree->GetFloatValue(etaphikey,"etaphi"); if (m_DecalInverse) { @@ -324,7 +335,9 @@ int RawTowerDigitizer::process_event(PHCompositeNode */**topNode*/) { if (m_DoDecal && m_Decal) { - float decal_fctr = m_CalDBFile->getCorr(eta, phi); + unsigned int etaphikey = phi; + etaphikey = (etaphikey << 16U) + eta; + float decal_fctr = m_CDBTTree->GetFloatValue(etaphikey,"etaphi"); if (m_DecalInverse) { decal_fctr = 1.0 / decal_fctr; diff --git a/simulation/g4simulation/g4calo/RawTowerDigitizer.h b/simulation/g4simulation/g4calo/RawTowerDigitizer.h index 07d3dcd1bd..a261a9c9d2 100644 --- a/simulation/g4simulation/g4calo/RawTowerDigitizer.h +++ b/simulation/g4simulation/g4calo/RawTowerDigitizer.h @@ -11,7 +11,7 @@ #include #include -class CaloCalibSimpleCorrFile; +class CDBTTree; class PHCompositeNode; class RawTower; class TowerInfo; @@ -278,7 +278,7 @@ class RawTowerDigitizer : public SubsysReco bool m_Decal = true; std::string m_DecalFileName; bool m_UseConditionsDB = false; - CaloCalibSimpleCorrFile *m_CalDBFile = nullptr; + CDBTTree *m_CDBTTree = nullptr; RawTowerDigitizer::ProcessTowerType m_UseTowerInfo = RawTowerDigitizer::ProcessTowerType::kBothTowers; // 0 just produce RawTowers, 1 just produce TowerInfo objects, and 2 produce both From 7fd5f2709809b2c0a5b7fb1e0f12464085fa1ebf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 19 Apr 2023 12:27:11 -0400 Subject: [PATCH 264/468] add --enable-online to build online version --- offline/packages/CaloBase/Makefile.am | 6 ++++++ offline/packages/CaloBase/configure.ac | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 5b5fe55826..9ac2dfdc90 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -4,6 +4,11 @@ AUTOMAKE_OPTIONS = foreign # List of shared libraries to produce +if USE_ONLINE +pkginclude_HEADERS = \ + TowerInfoDefs.h + +else lib_LTLIBRARIES = \ libcalo_io.la @@ -115,6 +120,7 @@ libcalo_io_la_SOURCES = \ TowerInfov1.cc \ TowerInfoDefs.cc \ TowerInfoContainerv1.cc +endif # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h diff --git a/offline/packages/CaloBase/configure.ac b/offline/packages/CaloBase/configure.ac index 5dcd946757..0c8dd5cd01 100644 --- a/offline/packages/CaloBase/configure.ac +++ b/offline/packages/CaloBase/configure.ac @@ -17,5 +17,15 @@ esac CINTDEFS=" -noIncludePaths -inlineInputHeader " AC_SUBST(CINTDEFS) +AC_ARG_ENABLE(online, + [ --enable-online build using for online [default=no]], + [case "${enableval}" in + yes) online=true ;; + no) online=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-online) ;; + esac], + online=false) +AM_CONDITIONAL(USE_ONLINE, test "x$online" = xtrue) + AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 318a3452f613c2dd60f9cb53bb54b6bdaeb9bec6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 19 Apr 2023 14:27:08 -0400 Subject: [PATCH 265/468] Change coordinates to local instead of global --- .../trackbase_historic/SvtxAlignmentState.h | 2 +- .../packages/trackreco/ActsAlignmentStates.cc | 60 ++++++++++++------- .../packages/trackreco/ActsAlignmentStates.h | 6 +- offline/packages/trackreco/PHActsTrkFitter.cc | 8 +-- offline/packages/trackreco/PHActsTrkFitter.h | 3 +- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/offline/packages/trackbase_historic/SvtxAlignmentState.h b/offline/packages/trackbase_historic/SvtxAlignmentState.h index a3d82e261d..a1b207800c 100644 --- a/offline/packages/trackbase_historic/SvtxAlignmentState.h +++ b/offline/packages/trackbase_historic/SvtxAlignmentState.h @@ -16,7 +16,7 @@ class SvtxAlignmentState : public PHObject /// the definition in millepede (track state parameters) const static int NLOC = 6; /// Number of residual parameters - const static int NRES = 3; + const static int NRES = 2; typedef Eigen::Matrix GlobalMatrix; typedef Eigen::Matrix LocalMatrix; diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index 06c1e18e42..b0226599bc 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -34,8 +35,9 @@ namespace } } // namespace -void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, - SvtxTrack* track) +void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, + SvtxTrack* track, + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { const auto mj = traj.multiTrajectory(); const auto& tips = traj.tips(); @@ -55,7 +57,16 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, const auto& surface = state.referenceSurface(); const auto& sl = static_cast(state.uncalibrated()); auto ckey = sl.cluskey(); - + Acts::Vector2 loc = Acts::Vector2::Zero(); + + std::visit([&](const auto& meas) { + std::cout << meas.parameters() << std::endl; + std::cout << meas.parameters().rows() << ", " << meas.parameters().cols() << std::endl; + std::cout << meas.parameters()[0] << ", " << meas.parameters()[1] << std::endl; + loc(0) = meas.parameters()[0]; + loc(1) = meas.parameters()[1]; + }, measurements[sl.index()]); + if (m_verbosity > 2) { std::cout << "sl index and ckey " << sl.index() << ", " @@ -75,23 +86,23 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, { makeTpcGlobalCorrections(ckey, crossing, clusGlobal); } - + /// convert to acts units clusGlobal *= Acts::UnitConstants::cm; const Acts::FreeVector globalStateParams = Acts::detail::transformBoundToFreeParameters(surface, m_tGeometry->geometry().getGeoContext(), state.smoothed()); Acts::Vector3 stateGlobal = globalStateParams.segment<3>(Acts::eFreePos0); - Acts::Vector3 residual = clusGlobal - stateGlobal; - + Acts::Vector3 globalResidual = clusGlobal - stateGlobal; + Acts::Vector3 clus_sigma(0, 0, 0); - if (m_clusterVersion == 3 || m_clusterVersion == 5) + if (m_clusterVersion != 4) { clus_sigma(2) = clus->getZError() * Acts::UnitConstants::cm; clus_sigma(0) = clus->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; clus_sigma(1) = clus->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; } - else if (m_clusterVersion == 4) + else { double clusRadius = sqrt(clusGlobal(0) * clusGlobal(0) + clusGlobal(1) * clusGlobal(1)); auto para_errors = m_clusErrPara.get_simple_cluster_error(clus, clusRadius, ckey); @@ -101,13 +112,22 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, clus_sigma(0) = sqrt(exy2 / 2.0); clus_sigma(1) = sqrt(exy2 / 2.0); } + + const Acts::ActsDynamicMatrix H = state.effectiveProjector(); + /// Acts residual, in local coordinates + + auto localResidual = loc - H * state.smoothed(); + if (m_verbosity > 2) { std::cout << "clus global is " << clusGlobal.transpose() << std::endl << "state global is " << stateGlobal.transpose() << std::endl - << "Residual is " << residual.transpose() << std::endl; + << "Residual is " << globalResidual.transpose() << std::endl; std::cout << " clus errors are " << clus_sigma.transpose() << std::endl; + std::cout << " clus loc is " << loc.transpose() << std::endl; + std::cout << " state loc is " << (H * state.smoothed()).transpose() << std::endl; + std::cout << " local residual is " << localResidual.transpose() << std::endl; } // Get the derivative of alignment (global) parameters w.r.t. measurement or residual @@ -119,23 +139,19 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, Acts::FreeVector pathDerivative = Acts::FreeVector::Zero(); pathDerivative.head<3>() = direction; - const Acts::ActsDynamicMatrix H = state.effectiveProjector(); - - /// Acts residual, in local coordinates - //auto actslocres = state.effectiveCalibrated() - H * state.smoothed(); - - // Get the derivative of bound parameters w.r.t. alignment parameters + + // Get the derivative of bound parameters wrt alignment parameters Acts::AlignmentToBoundMatrix d = surface.alignmentToBoundDerivative(m_tGeometry->geometry().getGeoContext(), freeParams, pathDerivative); // Get the derivative of bound parameters wrt track parameters Acts::FreeToBoundMatrix j = surface.freeToBoundJacobian(m_tGeometry->geometry().getGeoContext(), freeParams); - + // derivative of residual wrt track parameters auto dLocResTrack = -H * j; // derivative of residual wrt alignment parameters auto dLocResAlignment = -H * d; - if (m_verbosity > 4) + if (m_verbosity > 3) { std::cout << " derivative of resiudal wrt track params " << std::endl << dLocResTrack << std::endl @@ -176,7 +192,7 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, sphenixRot(4, 7) = direction.y() * p2; sphenixRot(5, 7) = direction.z() * p2; - const auto dGlobResTrack = rot * dLocResTrack * sphenixRot.transpose(); + const auto dGlobResTrack = dLocResTrack * sphenixRot.transpose(); if (m_verbosity > 3) { @@ -186,15 +202,16 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, << dGlobResTrack << std::endl; } - + auto svtxstate = std::make_unique(); - svtxstate->set_residual(residual); + svtxstate->set_residual(localResidual); svtxstate->set_local_derivative_matrix(dGlobResTrack); - svtxstate->set_global_derivative_matrix(dGlobResAlignment); + svtxstate->set_global_derivative_matrix(dLocResAlignment); svtxstate->set_cluster_key(ckey); if(m_analytic) { + /* auto surf = m_tGeometry->maps().getSurface(ckey, clus); auto anglederivs = getDerivativesAlignmentAngles(clusGlobal, ckey, clus, surf, @@ -203,6 +220,7 @@ void ActsAlignmentStates::fillAlignmentStateMap(Trajectory traj, getGlobalDerivatives(anglederivs,analytic); svtxstate->set_global_derivative_matrix(analytic); + */ } statevec.push_back(svtxstate.release()); diff --git a/offline/packages/trackreco/ActsAlignmentStates.h b/offline/packages/trackreco/ActsAlignmentStates.h index 0eed5655dc..d4eb6dc930 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.h +++ b/offline/packages/trackreco/ActsAlignmentStates.h @@ -14,6 +14,7 @@ #include #include #include +#include class PHCompositeNode; class SvtxTrack; @@ -32,8 +33,9 @@ class ActsAlignmentStates ActsAlignmentStates() {} ~ActsAlignmentStates() {} void clusterVersion(const int v) { m_clusterVersion = v; } - void fillAlignmentStateMap(Trajectory traj, - SvtxTrack* track); + void fillAlignmentStateMap(const Trajectory& traj, + SvtxTrack* track, + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); void verbosity(const int verb) { m_verbosity = verb; } void analyticGlobalDer(bool a) { m_analytic = a; } void distortionContainers(TpcDistortionCorrectionContainer* stat, diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 7875c5bd22..9fce578285 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -427,7 +427,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) unsigned int trid = m_directedTrackMap->size(); newTrack.set_id(trid); - if( getTrackFitResult(fitOutput, &newTrack) ) + if( getTrackFitResult(fitOutput, &newTrack, measurements) ) { m_directedTrackMap->insertWithKey(&newTrack, trid); } } else { @@ -435,7 +435,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) unsigned int trid = m_trackMap->size(); newTrack.set_id(trid); - if( getTrackFitResult(fitOutput, &newTrack)) + if( getTrackFitResult(fitOutput, &newTrack, measurements)) { m_trackMap->insertWithKey(&newTrack, trid); } } @@ -750,7 +750,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, return sourcelinks; } -bool PHActsTrkFitter::getTrackFitResult(const FitResult &fitOutput, SvtxTrack* track) +bool PHActsTrkFitter::getTrackFitResult(const FitResult &fitOutput, SvtxTrack* track, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool @@ -804,7 +804,7 @@ bool PHActsTrkFitter::getTrackFitResult(const FitResult &fitOutput, SvtxTrack* t { if(track->get_silicon_seed() && track->get_tpc_seed()) { - m_alignStates.fillAlignmentStateMap(trajectory, track); + m_alignStates.fillAlignmentStateMap(trajectory, track, measurements); } } diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 6d97e75c02..604a58362d 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -143,7 +143,8 @@ class PHActsTrkFitter : public SubsysReco SurfacePtrVec& surfaces) const; void checkSurfaceVec(SurfacePtrVec& surfaces) const; - bool getTrackFitResult(const FitResult& fitOutput, SvtxTrack* track); + bool getTrackFitResult(const FitResult& fitOutput, SvtxTrack* track, + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); Acts::BoundSymMatrix setDefaultCovariance() const; void printTrackSeed(const ActsTrackFittingAlgorithm::TrackParameters& seed) const; From d38f0e2850592b616d520a54cb258db2e308c8bc Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 19 Apr 2023 19:52:44 -0400 Subject: [PATCH 266/468] create global tag if it does not exist --- offline/database/sphenixnpc/sphenixnpc.cc | 40 ++++++++++++++++++++--- offline/database/sphenixnpc/sphenixnpc.h | 2 +- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index 26a53d7f2c..743f38e1a1 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -62,14 +62,44 @@ nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) return makeResp(url_dict_[pl_type]); } -nlohmann::json sphenixnpc::cache_set_GlobalTag(const std::string &name) +int sphenixnpc::cache_set_GlobalTag(const std::string &name) { - if (name != m_CachedGlobalTag) + int iret = 0; + if (name == m_CachedGlobalTag) // global tag already set { - url_dict_ = nlohmann::json{}; - m_CachedGlobalTag = name; + return iret; } - return nopayloadclient::Client::setGlobalTag(name); + url_dict_ = nlohmann::json{}; + m_CachedGlobalTag = name; + //return nopayloadclient::Client::setGlobalTag(name); + nopayloadclient::Client::setGlobalTag(name); + bool found_gt = false; + nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_gt = it.value().at("name"); + std::cout << "global tag: " << exist_gt << std::endl; + if (exist_gt == name) + { + found_gt = true; + break; + } + } + if (!found_gt) + { + resp = nopayloadclient::Client::createGlobalTag(); + iret = resp["code"]; + if (iret != 0) + { + std::cout << "Error creating global tag, msg: " << resp["msg"] << std::endl; + } + else + { + std::cout << "sphenixnpc: Created new global tag " << name << std::endl; + } + } + return iret; } nlohmann::json sphenixnpc::clearCache() diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 35d0886fac..3f83b00fd9 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -22,7 +22,7 @@ class sphenixnpc : public nopayloadclient::Client int createGlobalTag(const std::string &tagname); int createDomain(const std::string &domain); nlohmann::json get(const std::string &pl_type, long long iov); - nlohmann::json cache_set_GlobalTag(const std::string &name); + int cache_set_GlobalTag(const std::string &name); nlohmann::json clearCache() override; std::string getCalibrationFile(const std::string &type, uint64_t iov); int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); From 7b8bc56e9954340f9402e1b730d0812cd94387c5 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 19 Apr 2023 21:44:42 -0400 Subject: [PATCH 267/468] default to old behavior of SAMPA presample=0 postsample=5 --- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index cfc7576356..ba515da366 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -67,8 +67,8 @@ class PHG4TpcDigitizer : public SubsysReco float ADCSignalConversionGain; float ADCNoiseConversionGain; //! SAMPA zero-suppression digitization parameter - unsigned int m_nPreSample = 2; - unsigned int m_nPostSample = 3; + unsigned int m_nPreSample = 0; + unsigned int m_nPostSample = 5; bool skip_noise = false; From c752fb3071492487ff3a775044e91af63799cbc8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 20 Apr 2023 08:21:53 -0400 Subject: [PATCH 268/468] add verbosity --- .../packages/trackreco/ActsAlignmentStates.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index b0226599bc..aa8b484e5a 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -147,14 +147,16 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, Acts::FreeToBoundMatrix j = surface.freeToBoundJacobian(m_tGeometry->geometry().getGeoContext(), freeParams); // derivative of residual wrt track parameters - auto dLocResTrack = -H * j; + auto dLocResTrackActs = -H * j; // derivative of residual wrt alignment parameters auto dLocResAlignment = -H * d; if (m_verbosity > 3) { + std::cout << "free to bound jacobian " << std::endl + << j << std::endl; std::cout << " derivative of resiudal wrt track params " << std::endl - << dLocResTrack << std::endl + << dLocResTrackActs << std::endl << " derivative of residual wrt alignment params " << std::endl << dLocResAlignment << std::endl; } @@ -192,20 +194,24 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, sphenixRot(4, 7) = direction.y() * p2; sphenixRot(5, 7) = direction.z() * p2; - const auto dGlobResTrack = dLocResTrack * sphenixRot.transpose(); + const auto dLocResTrack = dLocResTrackActs * sphenixRot.transpose(); if (m_verbosity > 3) { std::cout << "derivative of residual wrt alignment parameters glob " << std::endl << dGlobResAlignment << std::endl; std::cout << "derivative of residual wrt track parameters glob " << std::endl - << dGlobResTrack << std::endl; + << dLocResTrack << std::endl; } - + SvtxAlignmentState::LocalMatrix aligncalc = SvtxAlignmentState::LocalMatrix::Zero(); + aligncalc(0,0) = -1; + aligncalc(0,1) = 0; + aligncalc(0,2) = 0.; + auto svtxstate = std::make_unique(); svtxstate->set_residual(localResidual); - svtxstate->set_local_derivative_matrix(dGlobResTrack); + svtxstate->set_local_derivative_matrix(dLocResTrack); svtxstate->set_global_derivative_matrix(dLocResAlignment); svtxstate->set_cluster_key(ckey); From 7ff2f3cb1eedcb4fb7ecf70078f4ba3917e25f37 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 20 Apr 2023 09:41:54 -0400 Subject: [PATCH 269/468] Move track association to GlobalVertexReco --- offline/packages/trackreco/Makefile.am | 1 - .../trackreco/PHActsVertexPropagator.cc | 71 +------------------ .../trackreco/PHActsVertexPropagator.h | 1 - .../g4simulation/g4vertex/GlobalVertexReco.cc | 29 ++++++++ 4 files changed, 32 insertions(+), 70 deletions(-) diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index 29404d795d..b339d1b542 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -159,7 +159,6 @@ libtrack_reco_la_LIBADD = \ -lgenfit2 \ -lgenfit2exp \ -lPHGenFit \ - -lg4bbc_io \ -lg4tpc \ -lg4intt \ -lg4mvtx \ diff --git a/offline/packages/trackreco/PHActsVertexPropagator.cc b/offline/packages/trackreco/PHActsVertexPropagator.cc index 679bab3284..1553bcc185 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.cc +++ b/offline/packages/trackreco/PHActsVertexPropagator.cc @@ -12,8 +12,6 @@ #include #include -#include - #include #include #include @@ -39,7 +37,7 @@ int PHActsVertexPropagator::InitRun(PHCompositeNode* topNode) int returnval = getNodes(topNode); return returnval; } -int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) +int PHActsVertexPropagator::process_event(PHCompositeNode*) { std::vector deletedKeys; for (const auto& [trackKey, trajectory] : *m_trajectories) @@ -87,12 +85,10 @@ int PHActsVertexPropagator::process_event(PHCompositeNode* topNode) } setVtxChi2(); - - if (m_vertexMap->size() == 0) + if (m_vertexMap->size() == 0 && Verbosity() > 2) { - setTrackVertexToBbc(topNode); + std::cout << "Propagated tracks to PerigeeSurface at (0,0,0) as no track vertices were found" << std::endl; } - /// Erase the trajectories that were removed from the track cleaner for (auto& key : deletedKeys) { @@ -205,67 +201,6 @@ Acts::Vector3 PHActsVertexPropagator::getVertex(const unsigned int vtxid) return Acts::Vector3::Zero(); } -void PHActsVertexPropagator::setTrackVertexToBbc(PHCompositeNode* topNode) -{ - auto bbcmap = findNode::getClass(topNode, "BbcOut"); - if (!bbcmap) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE << "Won't propagate tracks as no vertex was found" - << std::endl; - } - return; - } - - float z = bbcmap->get_VertexPoint(); - float zerr = bbcmap->get_dVertexPoint(); - if (std::isnan(z) or std::isnan(zerr)) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE - << "No vertex found in the event, track parameters are WRT (0,0,0})" - << std::endl; - } - - return; - } - - /// If we found no vertices in the event, associate track to bbc - auto vertex = std::make_unique(); - vertex->set_chisq(0.); - vertex->set_ndof(0); - vertex->set_t0(bbcmap->get_TimeZero()); - vertex->set_id(0); - vertex->set_x(0); - vertex->set_y(0); - vertex->set_z(z); - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - vertex->set_error(i, j, 0.); - } - } - vertex->set_error(2, 2, zerr * zerr); - m_vertexMap->insert(vertex.release()); - - if (Verbosity() > 1) - { - std::cout << "Set track vertex to propagate to BBC vertex " - << bbcmap->get_VertexPoint() << " +/- " - << bbcmap->get_dVertexPoint() << std::endl; - } - - for (auto& [key, track] : *m_trackMap) - { - track->set_vertex_id(0); - } - - return; -} - int PHActsVertexPropagator::End(PHCompositeNode*) { return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/trackreco/PHActsVertexPropagator.h b/offline/packages/trackreco/PHActsVertexPropagator.h index 3cac5853e5..59f0682861 100644 --- a/offline/packages/trackreco/PHActsVertexPropagator.h +++ b/offline/packages/trackreco/PHActsVertexPropagator.h @@ -36,7 +36,6 @@ class PHActsVertexPropagator : public SubsysReco private: int getNodes(PHCompositeNode *topNode); - void setTrackVertexToBbc(PHCompositeNode *topNode); ActsPropagator::BoundTrackParamResult propagateTrack(const Acts::BoundTrackParameters ¶ms, const unsigned int vtxid); diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index 71e28c2ed8..fb0f463ab9 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -10,6 +10,8 @@ #include +#include +#include #include #include @@ -295,6 +297,33 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } } + + /// Associate any tracks that were not assigned a track-vertex + auto trackmap = findNode::getClass(topNode, "SvtxTrackMap"); + if (trackmap) + { + for (const auto &[tkey, track] : *trackmap) + { + float maxdz = std::numeric_limits::max(); + float vtxid = std::numeric_limits::max(); + + for (const auto &[vkey, vertex] : *globalmap) + { + float dz = track->get_z() - vertex->get_z(); + if (fabs(dz) < maxdz) + { + maxdz = dz; + vtxid = vkey; + } + } + track->set_vertex_id(vtxid); + if (Verbosity()) + { + std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; + } + } + } + if (Verbosity()) { globalmap->identify(); From e5ea2af611868a6918025374bf1d8a27f0b440e9 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 20 Apr 2023 11:43:59 -0400 Subject: [PATCH 270/468] Added ntuple into CMMatcher --- .../PHTpcCentralMembraneClusterizer.cc | 25 ++-- .../PHTpcCentralMembraneClusterizer.h | 1 - .../tpccalib/PHTpcCentralMembraneMatcher.cc | 50 +++++++- .../tpccalib/PHTpcCentralMembraneMatcher.h | 15 ++- offline/packages/trackbase/CMFlashCluster.h | 30 +++++ .../packages/trackbase/CMFlashClusterv3.cc | 82 ++++++++++++ offline/packages/trackbase/CMFlashClusterv3.h | 117 ++++++++++++++++++ .../trackbase/CMFlashClusterv3LinkDef.h | 5 + offline/packages/trackbase/Makefile.am | 4 + 9 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 offline/packages/trackbase/CMFlashClusterv3.cc create mode 100644 offline/packages/trackbase/CMFlashClusterv3.h create mode 100644 offline/packages/trackbase/CMFlashClusterv3LinkDef.h diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index 2c662d73d0..4559d4a44c 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -160,6 +159,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } + //use peak in z distributions to identify if there is a CM Flash. Peak should be >20% of entries (needs to be tuned) + if(hz_pos->GetMaximum() < 0.2*hz_pos->GetEntries() || hz_neg->GetMaximum() < 0.2*hz_neg->GetEntries()) return Fun4AllReturnCodes::EVENT_OK; + //loop over histos for each pair of layers, count number of bins above threshold //for a given layer, layer pair with higher average value above threshold will be better match for meta-clustering for(int i=0; i<47; i++){ @@ -319,9 +321,10 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) else if(nPairAbove_neg[layer[i]-8] >= nRowsMatch) layerMatch = layer[i]-1; } } - + //if the match is default and the layer is on the edge of a module, identify it as being across the gap - if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39 || layer[i] == 7) ) isAcrossGap[i] = true; + // if(layerMatch == -1 && (layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39 || layer[i] == 7) ) isAcrossGap[i] = true; + if(layer[i] == 22 || layer[i] == 23 || layer[i] == 38 || layer[i] == 39 || layer[i] == 7) isAcrossGap[i] = true; float bestphidist=maxphidist; for (int j=0;j 0) @@ -484,7 +488,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(_histos) hClustE[2]->Fill(energy[i]); // These single cluster cases have good phi, but do not have a good radius centroid estimate - may want to skip them, record nclusters and identify if across gap - if(layer[i] == 7) isAcrossGap[i] = true; + // if(layer[i] == 7) isAcrossGap[i] = true; aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); nclusters.push_back(1); @@ -498,7 +502,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) for(unsigned int iv = 0; iv setX(avepos[iv].X()); cmfc->setY(avepos[iv].Y()); @@ -567,6 +571,11 @@ int PHTpcCentralMembraneClusterizer::End(PHCompositeNode * /*topNode*/ ) hDistRowAdj->Write(); hDist2Adj->Write(); + for(int i=0; i<47; i++){ + hphi_reco_pair_pos[i]->Write(); + hphi_reco_pair_neg[i]->Write(); + } + m_histogramfile->Close(); } diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h index 0a5ff8db9e..4994ac75e5 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.h @@ -24,7 +24,6 @@ class CMFlashClusterContainer; class PHG4TpcCylinderGeomContainer; class TF1; -class TNtuple; class TFile; class TH1F; class TH2F; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index e89be37628..f4da5696b5 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -265,6 +266,8 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) hdr3_double = new TH1F("hdr3_double", "outer dr double", 200,-max_dr, max_dr); hdrphi = new TH1F("hdrphi","r * dphi", 200, -0.05, 0.05); hnclus = new TH1F("hnclus", " nclusters ", 3, 0., 3.); + + fout2.reset ( new TFile(m_histogramfilename2.c_str(),"RECREATE") ); } hit_r_phi = new TH2F("hit_r_phi","hit r vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); @@ -272,6 +275,8 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); + match_ntup = new TNtuple("match_ntup","Match NTuple","event:truthR:truthPhi:recoR:recoPhi:recoZ:nclus:r1:phi1:e1:layer1:r2:phi2:e2:layer2"); + // Get truth cluster positions //===================== @@ -367,8 +372,15 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) { std::vector reco_pos; + std::vector pos1; + std::vector pos2; std::vector reco_nclusters; - + std::vector reco_adc; + std::vector adc1; + std::vector adc2; + std::vector layer1; + std::vector layer2; + // reset output distortion correction container histograms for( const auto& harray:{m_dcc_out->m_hDRint, m_dcc_out->m_hDPint, m_dcc_out->m_hDZint, m_dcc_out->m_hentries} ) { for( const auto& h:harray ) { h->Reset(); } } @@ -376,6 +388,11 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) clust_r_phi_pos->Reset(); clust_r_phi_neg->Reset(); + if(!m_corrected_CMcluster_map || m_corrected_CMcluster_map->size() < 100){ + m_event_index++; + return Fun4AllReturnCodes::EVENT_OK; + } + // read the reconstructed CM clusters auto clusrange = m_corrected_CMcluster_map->getClusters(); for (auto cmitr = clusrange.first; @@ -385,6 +402,7 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) const auto& [cmkey, cmclus_orig] = *cmitr; CMFlashCluster *cmclus = cmclus_orig; const unsigned int nclus = cmclus->getNclusters(); + const unsigned int adc = cmclus->getAdc(); if(m_useOnly_nClus2 && nclus != 2) continue; @@ -397,10 +415,22 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) TVector3 tmp_pos(pos[0], pos[1], pos[2]); - if(isRGap) continue; + TVector3 tmp_pos1(cmclus->getX1(), cmclus->getY1(), cmclus->getZ1()); + TVector3 tmp_pos2(cmclus->getX2(), cmclus->getY2(), cmclus->getZ2()); + + + + if(nclus == 1 && isRGap) continue; reco_pos.push_back(tmp_pos); + pos1.push_back(tmp_pos1); + pos2.push_back(tmp_pos2); reco_nclusters.push_back(nclus); + reco_adc.push_back(adc); + adc1.push_back(cmclus->getAdc1()); + adc2.push_back(cmclus->getAdc2()); + layer1.push_back(cmclus->getLayer1()); + layer2.push_back(cmclus->getLayer2()); if(tmp_pos.Z() < 0) clust_r_phi_neg->Fill(tmp_pos.Phi(),tmp_pos.Perp()); else clust_r_phi_pos->Fill(tmp_pos.Phi(),tmp_pos.Perp()); @@ -660,6 +690,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) m_cm_flash_diffs->addDifferenceSpecifyKey(key, cmdiff); + match_ntup->Fill(m_event_index,m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z(),nclus,pos1[p.second].Perp(),pos1[p.second].Phi(),adc1[p.second],layer1[p.second],pos2[p.second].Perp(),pos2[p.second].Phi(),adc2[p.second],layer2[p.second]); + // store cluster position const double clus_r = reco_pos[p.second].Perp(); double clus_phi = reco_pos[p.second].Phi(); @@ -721,6 +753,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) << std::endl; } } + + m_event_index++; return Fun4AllReturnCodes::EVENT_OK; } @@ -772,6 +806,16 @@ int PHTpcCentralMembraneMatcher::End(PHCompositeNode * /*topNode*/ ) fout->Close(); } + if(m_savehistograms && fout2) + { + fout2->cd(); + + match_ntup->Write(); + hit_r_phi->Write(); + clust_r_phi_pos->Write(); + clust_r_phi_neg->Write(); + } + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 80afe3bae3..4f7ede5593 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -28,6 +28,7 @@ class TH1F; class TH1D; class TH2F; class TGraph; +class TNtuple; class TVector3; class PHTpcCentralMembraneMatcher : public SubsysReco @@ -115,11 +116,19 @@ class PHTpcCentralMembraneMatcher : public SubsysReco std::unique_ptr fout; + + std::unique_ptr fout2; + std::string m_histogramfilename2 = "CMMatcher.root"; + TH2F *hit_r_phi; TH2F *clust_r_phi_pos; TH2F *clust_r_phi_neg; + TNtuple *match_ntup = nullptr; + + int m_event_index = 0; + //@} /// radius cut for matching clusters to pad, for size 2 clusters @@ -133,16 +142,16 @@ class PHTpcCentralMembraneMatcher : public SubsysReco //@{ /// distortion correction grid size along phi - int m_phibins = 36; + int m_phibins = 24; static constexpr float m_phiMin = 0; static constexpr float m_phiMax = 2.*M_PI; /// distortion correction grid size along r - int m_rbins = 16; + int m_rbins = 12; static constexpr float m_rMin = 20; // cm - static constexpr float m_rMax = 78; // cm + static constexpr float m_rMax = 80; // cm //@} diff --git a/offline/packages/trackbase/CMFlashCluster.h b/offline/packages/trackbase/CMFlashCluster.h index cc2cf5f423..0de1ed2bc3 100644 --- a/offline/packages/trackbase/CMFlashCluster.h +++ b/offline/packages/trackbase/CMFlashCluster.h @@ -52,11 +52,41 @@ class CMFlashCluster : public PHObject virtual void setY(float) {} virtual float getZ() const { return NAN; } virtual void setZ(float) {} + + virtual float getX1() const { return NAN; } + virtual void setX1(float) {} + virtual float getY1() const { return NAN; } + virtual void setY1(float) {} + virtual float getZ1() const { return NAN; } + virtual void setZ1(float) {} + + virtual float getX2() const { return NAN; } + virtual void setX2(float) {} + virtual float getY2() const { return NAN; } + virtual void setY2(float) {} + virtual float getZ2() const { return NAN; } + virtual void setZ2(float) {} + + + virtual void setLayer1(unsigned int) {} + virtual unsigned int getLayer1() const { return UINT_MAX; } + + virtual void setLayer2(unsigned int) {} + virtual unsigned int getLayer2() const { return UINT_MAX; } + // // cluster info // virtual void setAdc(unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } + + + virtual void setAdc1(unsigned int) {} + virtual unsigned int getAdc1() const { return UINT_MAX; } + + virtual void setAdc2(unsigned int) {} + virtual unsigned int getAdc2() const { return UINT_MAX; } + virtual unsigned int getNclusters() const {return UINT_MAX;} virtual void setNclusters( unsigned int) {} virtual void setIsRGap(bool) {} diff --git a/offline/packages/trackbase/CMFlashClusterv3.cc b/offline/packages/trackbase/CMFlashClusterv3.cc new file mode 100644 index 0000000000..122e8d0c90 --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv3.cc @@ -0,0 +1,82 @@ +/** + * @file trackbase/CMFlashClusterv3.cc + * @author Ben Kimelman + * @date March 2023 + * @brief Implementation of CMFlashClusterv3 + */ +#include "CMFlashClusterv3.h" + +#include +#include // for swap + +void CMFlashClusterv3::identify(std::ostream& os) const +{ + os << "---CMFlashClusterv3--------------------" << std::endl; + + os << " (x,y,z) = (" << m_pos[0]; + os << ", " << m_pos[1] << ", "; + os << m_pos[2] << ") cm"; + + os << " adc = " << getAdc() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int CMFlashClusterv3::isValid() const +{ + if(std::isnan(getX())) return 0; + if(std::isnan(getY())) return 0; + if(std::isnan(getZ())) return 0; + + + if(std::isnan(getX1())) return 0; + if(std::isnan(getY1())) return 0; + if(std::isnan(getZ1())) return 0; + + + if(std::isnan(getX2())) return 0; + if(std::isnan(getY2())) return 0; + if(std::isnan(getZ2())) return 0; + + if (m_adc == 0xFFFFFFFF) return 0; + if (m_adc1 == 0xFFFFFFFF) return 0; + if (m_adc2 == 0xFFFFFFFF) return 0; + + return 1; +} + +void CMFlashClusterv3::CopyFrom( const CMFlashCluster& source ) +{ + // do nothing if copying onto oneself + if( this == &source ) return; + + // parent class method + CMFlashCluster::CopyFrom( source ); + + setX( source.getX() ); + setY( source.getY() ); + setZ( source.getZ() ); + + + setX1( source.getX1() ); + setY1( source.getY1() ); + setZ1( source.getZ1() ); + + setX2( source.getX2() ); + setY2( source.getY2() ); + setZ2( source.getZ2() ); + + setLayer1( source.getLayer1() ); + setLayer2( source.getLayer2() ); + + setAdc( source.getAdc() ); + setAdc1( source.getAdc1() ); + setAdc2( source.getAdc2() ); + setIsRGap( source.getIsRGap() ); + setIsPhiGap( source.getIsPhiGap() ); + +} + diff --git a/offline/packages/trackbase/CMFlashClusterv3.h b/offline/packages/trackbase/CMFlashClusterv3.h new file mode 100644 index 0000000000..c107220d3d --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv3.h @@ -0,0 +1,117 @@ +/** + * @file trackbase/CMFlashClusterv3.h + * @author Ben Kimelman + * @date March 2023 + * @brief Version 3 of CMFlashCluster + */ +#ifndef TRACKBASE_CMFLASHCLUSTERV3_H +#define TRACKBASE_CMFLASHCLUSTERV3_H + +#include "CMFlashCluster.h" + +#include + +class PHObject; + +/** + * @brief Version 3 of CMFlashCluster + * + *Adding variable to keep track of clusters + *put into metaclusters + * + */ +class CMFlashClusterv3 : public CMFlashCluster +{ + public: + //! ctor + CMFlashClusterv3() = default; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override {} + int isValid() const override; + PHObject* CloneMe() const override { return new CMFlashClusterv3(*this); } + + //! copy content from base class + void CopyFrom( const CMFlashCluster& ) override; + + //! copy content from base class + void CopyFrom( CMFlashCluster* source ) override + { CopyFrom( *source ); } + + // + // cluster position + // + float getX() const override { return m_pos[0]; } + void setX(float x) override { m_pos[0] = x; } + float getY() const override { return m_pos[1]; } + void setY(float y) override { m_pos[1] = y; } + float getZ() const override { return m_pos[2]; } + void setZ(float z) override { m_pos[2] = z; } + + + float getX1() const override { return m_pos1[0]; } + void setX1(float x) override { m_pos1[0] = x; } + float getY1() const override { return m_pos1[1]; } + void setY1(float y) override { m_pos1[1] = y; } + float getZ1() const override { return m_pos1[2]; } + void setZ1(float z) override { m_pos1[2] = z; } + + float getX2() const override { return m_pos2[0]; } + void setX2(float x) override { m_pos2[0] = x; } + float getY2() const override { return m_pos2[1]; } + void setY2(float y) override { m_pos2[1] = y; } + float getZ2() const override { return m_pos2[2]; } + void setZ2(float z) override { m_pos2[2] = z; } + + unsigned int getLayer1() const override {return m_layer1;} + void setLayer1(unsigned int layer) override { m_layer1 = layer;} + unsigned int getLayer2() const override {return m_layer2;} + void setLayer2(unsigned int layer) override { m_layer2 = layer;} + + unsigned int getNclusters() const override {return m_nclusters;} + void setNclusters(unsigned int n) override { m_nclusters = n;} + bool getIsRGap() const override { return m_isRGap; } + void setIsRGap(bool isRGap) override { m_isRGap = isRGap;} + bool getIsPhiGap() const override { return m_isPhiGap; } + void setIsPhiGap(bool isPhiGap) override { m_isPhiGap = isPhiGap;} + + // + // cluster info + // + unsigned int getAdc() const override { return m_adc; } + void setAdc(unsigned int adc) override { m_adc = adc; } + + unsigned int getAdc1() const override { return m_adc1; } + void setAdc1(unsigned int adc) override { m_adc1 = adc; } + + unsigned int getAdc2() const override { return m_adc2; } + void setAdc2(unsigned int adc) override { m_adc2 = adc; } + + protected: + + /// mean cluster position + float m_pos[3] = {NAN, NAN, NAN}; + + float m_pos1[3] = {NAN, NAN, NAN}; + float m_pos2[3] = {NAN, NAN, NAN}; + + /// cluster sum adc + unsigned int m_adc = 0xFFFFFFFF; + unsigned int m_adc1 = 0xFFFFFFFF; + unsigned int m_adc2 = 0xFFFFFFFF; + + unsigned int m_layer1 = UINT_MAX; + unsigned int m_layer2 = UINT_MAX; + + /// number of TPC clusters used to create this central mebrane cluster + unsigned int m_nclusters = UINT_MAX; + + /// bools to identify if meta-cluster is across sector/module gaps + bool m_isRGap = false; + bool m_isPhiGap = false; + + ClassDefOverride(CMFlashClusterv3, 1) +}; + +#endif //TRACKBASE_CMFLASHCLUSTERV3_H diff --git a/offline/packages/trackbase/CMFlashClusterv3LinkDef.h b/offline/packages/trackbase/CMFlashClusterv3LinkDef.h new file mode 100644 index 0000000000..baa1677ab2 --- /dev/null +++ b/offline/packages/trackbase/CMFlashClusterv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class CMFlashClusterv3+; + +#endif diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 26adc5b225..cee64707aa 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -32,6 +32,7 @@ pkginclude_HEADERS = \ CMFlashClusterContainerv1.h \ CMFlashClusterv1.h \ CMFlashClusterv2.h \ + CMFlashClusterv3.h \ CMFlashDifference.h \ CMFlashDifferenceContainer.h \ CMFlashDifferenceContainerv1.h \ @@ -91,6 +92,7 @@ ROOTDICTS = \ CMFlashCluster_Dict.cc \ CMFlashClusterv1_Dict.cc \ CMFlashClusterv2_Dict.cc \ + CMFlashClusterv3_Dict.cc \ CMFlashDifferenceContainer_Dict.cc \ CMFlashDifferenceContainerv1_Dict.cc \ CMFlashDifference_Dict.cc \ @@ -143,6 +145,7 @@ nobase_dist_pcm_DATA = \ CMFlashCluster_Dict_rdict.pcm \ CMFlashClusterv1_Dict_rdict.pcm \ CMFlashClusterv2_Dict_rdict.pcm \ + CMFlashClusterv3_Dict_rdict.pcm \ CMFlashDifferenceContainer_Dict_rdict.pcm \ CMFlashDifferenceContainerv1_Dict_rdict.pcm \ CMFlashDifference_Dict_rdict.pcm \ @@ -195,6 +198,7 @@ libtrack_io_la_SOURCES = \ CMFlashClusterContainerv1.cc \ CMFlashClusterv1.cc \ CMFlashClusterv2.cc \ + CMFlashClusterv3.cc \ CMFlashDifferenceContainerv1.cc \ CMFlashDifferencev1.cc \ ClusterErrorPara.cc \ From 94881177fb3a643aad802f4a585410dd9c2785a8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 20 Apr 2023 13:34:08 -0400 Subject: [PATCH 271/468] add track analysis utils helper class --- .../packages/trackbase_historic/Makefile.am | 6 +- .../trackbase_historic/TrackAnalysisUtils.cc | 66 +++++++++++++++++++ .../trackbase_historic/TrackAnalysisUtils.h | 23 +++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 offline/packages/trackbase_historic/TrackAnalysisUtils.cc create mode 100644 offline/packages/trackbase_historic/TrackAnalysisUtils.h diff --git a/offline/packages/trackbase_historic/Makefile.am b/offline/packages/trackbase_historic/Makefile.am index 186a621837..3086da04e8 100644 --- a/offline/packages/trackbase_historic/Makefile.am +++ b/offline/packages/trackbase_historic/Makefile.am @@ -54,7 +54,8 @@ pkginclude_HEADERS = \ SvtxVertex.h \ SvtxVertex_v1.h \ SvtxVertexMap.h \ - SvtxVertexMap_v1.h + SvtxVertexMap_v1.h \ + TrackAnalysisUtils.h ROOTDICTS = \ TrackSeed_Dict.cc \ @@ -165,7 +166,8 @@ libtrackbase_historic_io_la_SOURCES = \ SvtxVertex.cc \ SvtxVertex_v1.cc \ SvtxVertexMap.cc \ - SvtxVertexMap_v1.cc + SvtxVertexMap_v1.cc \ + TrackAnalysisUtils.cc libtrackbase_historic_io_la_LDFLAGS = \ -L$(libdir) \ diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc new file mode 100644 index 0000000000..d67e5898fd --- /dev/null +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -0,0 +1,66 @@ +#include "TrackAnalysisUtils.h" +#include "SvtxTrack.h" +#include "SvtxVertex.h" + +TrackAnalysisUtils::DCAPair TrackAnalysisUtils::get_dca(SvtxTrack* track, + SvtxVertex* svtxVertex) +{ + TrackAnalysisUtils::DCAPair pair; + if (!track or !svtxVertex) + { + std::cout << "You passed a nullptr, can't calculate DCA" << std::endl; + return pair; + } + + Acts::Vector3 pos(track->get_x(), + track->get_y(), + track->get_z()); + Acts::Vector3 mom(track->get_px(), + track->get_py(), + track->get_pz()); + + Acts::Vector3 vertex(svtxVertex->get_x(), + svtxVertex->get_y(), + svtxVertex->get_z()); + + pos -= vertex; + + Acts::ActsSymMatrix<3> posCov; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + posCov(i, j) = track->get_error(i, j); + } + } + + Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.)); + float phi = atan2(r(1), r(0)); + + Acts::RotationMatrix3 rot; + Acts::RotationMatrix3 rot_T; + rot(0, 0) = cos(phi); + rot(0, 1) = -sin(phi); + rot(0, 2) = 0; + rot(1, 0) = sin(phi); + rot(1, 1) = cos(phi); + rot(1, 2) = 0; + rot(2, 0) = 0; + rot(2, 1) = 0; + rot(2, 2) = 1; + + rot_T = rot.transpose(); + + Acts::Vector3 pos_R = rot * pos; + Acts::ActsSymMatrix<3> rotCov = rot * posCov * rot_T; + + //! First pair is DCA_xy +/- DCA_xy_err + pair.first.first = pos_R(0); + pair.first.second = sqrt(rotCov(0, 0)); + + //! Second pair is DCA_z +/- DCA_z_err + pair.second.first = pos_R(2); + pair.second.second = sqrt(rotCov(2, 2)); + + return pair; +} diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h new file mode 100644 index 0000000000..f1e3d2aecd --- /dev/null +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -0,0 +1,23 @@ +#ifndef _TRACKBASEHISTORIC_TRACKANALYSISUTILS_H +#define _TRACKBASEHISTORIC_TRACKANALYSISUTILS_H + +#include + +class SvtxTrack; +class SvtxVertex; + +class TrackAnalysisUtils +{ + public: + using DCA = std::pair; + using DCAPair = std::pair; + + TrackAnalysisUtils() = default; + ~TrackAnalysisUtils() {} + + DCAPair get_dca(SvtxTrack* track, SvtxVertex* svtxVertex); + + private: +}; + +#endif From e5f0d69d411d82b37dc22c8bb8cd2887addaca05 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 20 Apr 2023 13:34:54 -0400 Subject: [PATCH 272/468] fix typo --- simulation/g4simulation/g4vertex/GlobalVertexReco.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index fb0f463ab9..5f3e104758 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -305,8 +305,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) for (const auto &[tkey, track] : *trackmap) { float maxdz = std::numeric_limits::max(); - float vtxid = std::numeric_limits::max(); - + unsigned int vtxid = std::numeric_limits::max(); + for (const auto &[vkey, vertex] : *globalmap) { float dz = track->get_z() - vertex->get_z(); From 4dd95e7041bd2d3b22c447ce4ce60e4433e06b3c Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Thu, 20 Apr 2023 15:21:18 -0400 Subject: [PATCH 273/468] updated the calowaveform processing chain to handle zero suppressed channels, missing packets, and short packets --- offline/packages/CaloReco/CaloTowerBuilder.cc | 80 +++++++++---- offline/packages/CaloReco/CaloTowerBuilder.h | 2 + .../packages/CaloReco/CaloWaveformFitting.cc | 106 +++++++++++------- .../packages/CaloReco/CaloWaveformFitting.h | 11 +- .../CaloReco/CaloWaveformProcessing.cc | 16 ++- .../CaloReco/CaloWaveformProcessing.h | 9 ++ 6 files changed, 153 insertions(+), 71 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index e801587e0e..f219bfe507 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -40,13 +40,14 @@ CaloTowerBuilder::~CaloTowerBuilder() int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); - + WaveformProcessing->set_softwarezerosuppression(true,40); if (m_dettype == CaloTowerBuilder::CEMC) { m_detector = "CEMC"; - m_packet_low = 6017; - m_packet_high = 6032; + m_packet_low = 6001; + m_packet_high = 6128; // 6001, 60128 + m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_cemc_template.root"); } else if (m_dettype == CaloTowerBuilder::HCALIN) @@ -54,6 +55,7 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_packet_low = 7001; m_packet_high = 7008; m_detector = "HCALIN"; + m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ihcal_template.root"); } else if (m_dettype == CaloTowerBuilder::HCALOUT) @@ -61,13 +63,15 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_detector = "HCALOUT"; m_packet_low = 8001; m_packet_high = 8008; + m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ohcal_template.root"); } else if (m_dettype == CaloTowerBuilder::EPD) { m_detector = "EPD"; m_packet_low = 9001; - m_packet_high = 9016; + m_packet_high = 9005; + m_nchannels = 186; WaveformProcessing->set_template_file("testbeam_cemc_template.root"); // place holder until we have EPD templates } WaveformProcessing->initialize_processing(); @@ -95,29 +99,61 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) for (int pid = m_packet_low; pid <= m_packet_high; pid++) { Packet *packet = _event->getPacket(pid); - if (!packet) - { - return Fun4AllReturnCodes::DISCARDEVENT; - } - for (int channel = 0; channel < packet->iValue(0, "CHANNELS"); channel++) - { - std::vector waveform; - waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nsamples; samp++) - { - waveform.push_back(packet->iValue(samp, channel)); - } - waveforms.push_back(waveform); - waveform.clear(); - } - delete packet; + if (packet) + { + int nchannels = packet->iValue(0, "CHANNELS"); + if (nchannels > m_nchannels) // packet is corrupted and reports too many channels + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + for (int channel = 0; channel < nchannels; channel++) + { + std::vector waveform; + waveform.reserve(m_nsamples); + for (int samp = 0; samp < m_nsamples; samp++) + { + waveform.push_back(packet->iValue(samp, channel)); + } + waveforms.push_back(waveform); + waveform.clear(); + } + if (nchannels < m_nchannels) + { + for (int channel = 0; channel waveform; + waveform.reserve(m_nsamples); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(0); + } + waveforms.push_back(waveform); + waveform.clear(); + } + } + delete packet; + } + else // if the packet is missing treat constitutent channels as zero suppressed + { + for (int channel = 0; channel waveform; + waveform.reserve(2); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(0); + } + waveforms.push_back(waveform); + waveform.clear(); + } + } } } else // placeholder for adding simulation { return Fun4AllReturnCodes::EVENT_OK; } - + std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); for (int i = 0; i < n_channels; i++) @@ -125,7 +161,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) m_CaloInfoContainer->get_tower_at_channel(i)->set_time(processed_waveforms.at(i).at(1)); m_CaloInfoContainer->get_tower_at_channel(i)->set_energy(processed_waveforms.at(i).at(0)); } - + waveforms.clear(); return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index 3ce5e78af3..5dfbac3bd8 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -55,6 +55,8 @@ class CaloTowerBuilder : public SubsysReco int m_packet_low = INT_MIN; int m_packet_high = INT_MIN; int m_nsamples = 16; + int m_nchannels = 192; + int m_nzerosuppsamples = 2; bool m_isdata = true; }; diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 362eb695af..40e491f1ac 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -51,52 +51,72 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit auto func = [&](std::vector &v) { int size1 = v.size() - 1; - auto h = new TH1F(Form("h_%d", (int) round(v.at(size1))), "", size1, 0, size1); - float maxheight = 0; - int maxbin = 0; - for (int i = 0; i < size1; i++) - { - h->SetBinContent(i + 1, v.at(i)); - if (v.at(i) > maxheight) + + if (size1 == _nzerosuppresssamples) { - maxheight = v.at(i); - maxbin = i; + v.push_back(v.at(0)); + v.push_back(-1); // set time to -1 to indicate zero suppressed + v.push_back(v.at(1)); } - } - float pedestal = 1500; - if (maxbin > 4) - { - pedestal = 0.5 * (v.at(maxbin - 4) + v.at(maxbin - 5)); - } - else if (maxbin > 3) - { - pedestal = (v.at(maxbin - 4)); - } else - { - pedestal = 0.5 * (v.at(size1 - 3) + v.at(size1 - 2)); - } - - - auto f = new TF1(Form("f_%d", (int) round(v.at(size1))), this,&CaloWaveformFitting::template_function, 0, 31, 3,"CaloWaveformFitting","template_function"); - ROOT::Math::WrappedMultiTF1 *fitFunction = new ROOT::Math::WrappedMultiTF1(*f, 3); - ROOT::Fit::BinData data(v.size() - 1, 1); - ROOT::Fit::FillData(data, h); - ROOT::Fit::Chi2Function *EPChi2 = new ROOT::Fit::Chi2Function(data, *fitFunction); - ROOT::Fit::Fitter *fitter = new ROOT::Fit::Fitter(); - fitter->Config().MinimizerOptions().SetMinimizerType("GSLMultiFit"); - double params[] = {static_cast(maxheight), static_cast(maxbin - 5), static_cast(pedestal)}; - fitter->Config().SetParamsSettings(3, params); - fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); - for (int i = 0; i < 3; i++) - { - v.push_back(f->GetParameter(i)); - } - h->Delete(); - f->Delete(); - delete fitFunction; - delete fitter; - delete EPChi2; + { + auto h = new TH1F(Form("h_%d", (int) round(v.at(size1))), "", size1, 0, size1); + float maxheight = 0; + int maxbin = 0; + for (int i = 0; i < size1; i++) + { + h->SetBinContent(i + 1, v.at(i)); + if (v.at(i) > maxheight) + { + maxheight = v.at(i); + maxbin = i; + } + } + float pedestal = 1500; + if (maxbin > 4) + { + pedestal = 0.5 * (v.at(maxbin - 4) + v.at(maxbin - 5)); + } + else if (maxbin > 3) + { + pedestal = (v.at(maxbin - 4)); + } + else + { + pedestal = 0.5 * (v.at(size1 - 3) + v.at(size1 - 2)); + } + + if (_bdosoftwarezerosuppression && maxheight - pedestal < _nsoftwarezerosuppression) + { + // std::cout << "software zero suppression happened " << std::endl; + h->Delete(); + v.push_back(v.at(6)); + v.push_back(-1); + v.push_back(pedestal); + } + else + { + auto f = new TF1(Form("f_%d", (int) round(v.at(size1))), this,&CaloWaveformFitting::template_function, 0, 31, 3,"CaloWaveformFitting","template_function"); + ROOT::Math::WrappedMultiTF1 *fitFunction = new ROOT::Math::WrappedMultiTF1(*f, 3); + ROOT::Fit::BinData data(v.size() - 1, 1); + ROOT::Fit::FillData(data, h); + ROOT::Fit::Chi2Function *EPChi2 = new ROOT::Fit::Chi2Function(data, *fitFunction); + ROOT::Fit::Fitter *fitter = new ROOT::Fit::Fitter(); + fitter->Config().MinimizerOptions().SetMinimizerType("GSLMultiFit"); + double params[] = {static_cast(maxheight), static_cast(maxbin - 5), static_cast(pedestal)}; + fitter->Config().SetParamsSettings(3, params); + fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); + for (int i = 0; i < 3; i++) + { + v.push_back(f->GetParameter(i)); + } + h->Delete(); + f->Delete(); + delete fitFunction; + delete fitter; + delete EPChi2; + } + } }; t.Foreach(func, chnlvector); diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 6b9bae72b8..0703892d6d 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -24,7 +24,13 @@ class CaloWaveformFitting return; } - int get_nthreads() + void set_softwarezerosuppression(bool usezerosuppression,int softwarezerosuppression) + { + _nsoftwarezerosuppression = softwarezerosuppression; + _bdosoftwarezerosuppression = usezerosuppression; + } + + int get_nthreads() { return _nthreads; } @@ -40,6 +46,9 @@ class CaloWaveformFitting TProfile *h_template = nullptr; double template_function(double *x, double *par); int _nthreads = 1; + int _nzerosuppresssamples = 2; + int _nsoftwarezerosuppression = 40; + bool _bdosoftwarezerosuppression = false; std::string m_template_input_file; std::string url_template; diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index e8487ee035..8b037c3913 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -1,7 +1,7 @@ #include "CaloWaveformProcessing.h" #include "CaloWaveformFitting.h" -#include +#include #include @@ -18,15 +18,21 @@ void CaloWaveformProcessing::initialize_processing() if (m_processingtype == CaloWaveformProcessing::TEMPLATE) { std::string calibrations_repo_template = std::string(calibrationsroot) + "/WaveformProcessing/templates/" + m_template_input_file; - url_template = XploadInterface::instance()->getUrl(m_template_input_file, calibrations_repo_template); + url_template = CDBInterface::instance()->getUrl(m_template_input_file, calibrations_repo_template); m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); m_Fitter->set_nthreads(get_nthreads()); + + if (_bdosoftwarezerosuppression == true) + { + std::cout << "hey zero suppression is on! " << std::endl; + m_Fitter->set_softwarezerosuppression(_bdosoftwarezerosuppression,_nsoftwarezerosuppression); + } } - if (m_processingtype == CaloWaveformProcessing::ONNX) - { + else if (m_processingtype == CaloWaveformProcessing::ONNX) + { std::string calibrations_repo_model = std::string(calibrationsroot) + "/WaveformProcessing/models/" + m_model_name; - url_onnx = XploadInterface::instance()->getUrl(m_model_name, calibrations_repo_model); + url_onnx = CDBInterface::instance()->getUrl(m_model_name, calibrations_repo_model); onnxmodule = onnxSession(url_onnx); } } diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index cf184bf018..86a518ad53 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -52,6 +52,13 @@ class CaloWaveformProcessing : public SubsysReco int get_nthreads(); + void set_softwarezerosuppression(bool usezerosuppression,int softwarezerosuppression) + { + _nsoftwarezerosuppression = softwarezerosuppression; + _bdosoftwarezerosuppression = usezerosuppression; + } + + std::vector> process_waveform(std::vector> waveformvector); std::vector> calo_processing_ONNX(std::vector> chnlvector); @@ -62,6 +69,8 @@ class CaloWaveformProcessing : public SubsysReco CaloWaveformProcessing::process m_processingtype = CaloWaveformProcessing::NONE; int _nthreads = 1; + int _nsoftwarezerosuppression = 40; + bool _bdosoftwarezerosuppression = false; std::string m_template_input_file; std::string url_template; From d1e8114ab90f0280c6d091f53fa687126b61986c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 20 Apr 2023 18:28:58 -0400 Subject: [PATCH 274/468] fix bug --- simulation/g4simulation/g4vertex/GlobalVertexReco.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index 5f3e104758..322e26074f 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -304,6 +304,12 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) { for (const auto &[tkey, track] : *trackmap) { + //! Check that the vertex hasn't already been assigned + auto trackvtxid = track->get_vertex_id(); + if(svtxmap->get(trackvtxid) != nullptr) + { + continue; + } float maxdz = std::numeric_limits::max(); unsigned int vtxid = std::numeric_limits::max(); From 901e2db117725911735b184977831f871b1cb3d0 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 20 Apr 2023 23:02:00 -0400 Subject: [PATCH 275/468] Moving to new localderivatives calculation. --- .../HelicalFitter.cc | 151 ++++++++++++++---- .../TrackerMillepedeAlignment/HelicalFitter.h | 6 +- .../trackbase/AlignmentTransformation.cc | 17 +- .../trackbase/AlignmentTransformation.h | 2 +- 4 files changed, 138 insertions(+), 38 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index f128fd7bfd..bd472f2877 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -180,9 +180,10 @@ int HelicalFitter::process_event(PHCompositeNode*) Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; - + /* std::cout << " inverse transform used for fitpoint:" << std::endl << surf->transform(_tGeometry->geometry().getGeoContext()).inverse().matrix() << std::endl; std::cout << "local-global transform " << std::endl << surf->transform(_tGeometry->geometry().getGeoContext()).matrix() << std::endl; + */ auto xloc = cluster->getLocalX(); // in cm auto zloc = cluster->getLocalY(); @@ -219,17 +220,20 @@ int HelicalFitter::process_event(PHCompositeNode*) std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); - float lcl_derivative[NLC]; + float lcl_derivativeX[NLC]; + float lcl_derivativeY[NLC]; float glbl_derivative[NGL]; + getLocalDerivativesXY(surf, global, fitpoint, fitpars, lcl_derivativeX, lcl_derivativeY, layer); + // Add the measurement separately for each coordinate direction to Mille // set the derivatives non-zero only for parameters we want to be optimized // local parameter numbering is arbitrary: // using 0=x0, 1=y0, 2=z0, 3=R, 4=zslope - getLocalDerivativesX(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); + //getLocalDerivativesX(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); getGlobalDerivativesX(angleDerivs, translDerivs, glbl_derivative, layer); - if(Verbosity() > 1) - { std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } + // if(Verbosity() > 1) + //{ std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) @@ -243,19 +247,24 @@ int HelicalFitter::process_event(PHCompositeNode*) << " xglob " << global(0) << " fitxglob " << fitpoint(0) << " yglob " << global(1) << " fityglob " << fitpoint(1) << " dzloc " << residual(1) - << " dxx0 " << lcl_derivative[0] << " label " << 1 << " dxy0 " << lcl_derivative[1] << " label " << 2 + << " X0 " << fitpars[1] << " Y0 " << fitpars[2] + << " derivx0 " << lcl_derivativeX[0] << " label " << 1 + << " derivx1 " << lcl_derivativeX[1] << " label " << 2 + << " derivx2 " << lcl_derivativeX[2] << " label " << 3 + << " derivx3 " << lcl_derivativeX[3] << " label " << 4 + << " derivx4 " << lcl_derivativeX[4] << " label " << 5 << " glbl_derivative " << glbl_derivative[3] << " label " << glbl_label[3] << std::endl; } } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters - { _mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} + { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} - getLocalDerivativesZ(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); - //getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); - getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); // in local coords alpha and dx are applied to x axis, beta and "dz" to y axis + //getLocalDerivativesZ(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); + getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); + //getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); // in local coords alpha and dx are applied to x axis, beta and "dz" to y axis // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) @@ -269,17 +278,21 @@ int HelicalFitter::process_event(PHCompositeNode*) << " xglob " << global(0) << " fitxglob " << fitpoint(0) << " yglob " << global(1) << " fityglob " << fitpoint(1) << " dxloc " << residual(0) - << " dzz0 " << lcl_derivative[2] << " label " << 3 << " dzzslope " << lcl_derivative[4] << " label " << 5 + << " zslope " << fitpars[3] << " Z0 " << fitpars[4] + << " derivy0 " << lcl_derivativeY[0] << " label " << 1 + << " derivy1 " << lcl_derivativeY[1] << " label " << 2 + << " derivy2 " << lcl_derivativeY[2] << " label " << 3 + << " derivy3 " << lcl_derivativeY[3] << " label " << 4 + << " derivy4 " << lcl_derivativeY[4] << " label " << 5 << " glbl_derivative " << glbl_derivative[5] << " label " << glbl_label[5] - // << " glbl_derivative " << glbl_derivative[4] << " label " << glbl_label[4] << std::endl; } } - if(Verbosity() > 1) - { std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } + // if(Verbosity() > 1) + //{ std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivative, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} + {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} } // close out this track @@ -324,15 +337,16 @@ Acts::Vector3 HelicalFitter::get_line_plane_intersection(Acts::Vector3 PCA, Acts // The solution is: float d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal); Acts::Vector3 intersection = PCA + d * tangent; + /* std::cout << " intersection: " << intersection(0) << " " << intersection(1) << " " << intersection(2) << " " << std::endl; std::cout << " sensor_center: " << sensor_center(0) << " " << sensor_center(1) << " " << sensor_center(2) << " " << std::endl; std::cout << " sensor_normal: " << sensor_normal(0) << " " << sensor_normal(1) << " " << sensor_normal(2) << " " << std::endl; - + */ return intersection; } -std::pair HelicalFitter::get_helix_tangent(std::vector& fitpars, Acts::Vector3 global) +std::pair HelicalFitter::get_helix_tangent(const std::vector& fitpars, Acts::Vector3 global) { // no analytic solution for the coordinates of the closest approach of a helix to a point // Instead, we get the PCA in x and y to the circle, and the PCA in z to the z vs R line at the R of the PCA @@ -883,6 +897,88 @@ Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu return clus_sigma; } +// new one +void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer) +{ + // Calculate the derivatives of the residual wrt the track parameters numerically + std::vector temp_fitpars; + + std::vector fitpars_delta; + fitpars_delta[0] = 0.1; // radius, cm + fitpars_delta[1] = 0.1; // X0, cm + fitpars_delta[2] = 0.1; // Y0, cm + fitpars_delta[3] = 0.1; // zslope, cm + fitpars_delta[4] = 0.1; // Z0, cm + + for(unsigned int ip = 0; ip < fitpars.size(); ++ip) + { + temp_fitpars[ip] = fitpars[ip]; + } + + // calculate projX and projY vectors once for the optimum fit parameters + // std::pair tangent = get_helix_tangent(fitpars, global) + std::pair tangent = get_helix_tangent(fitpars, fitpoint); + + Acts::Vector3 projX, projY; + get_projectionXY(surf, tangent, projX, projY); + + + Acts::Vector3 intersection = get_helix_surface_intersection(surf, temp_fitpars, global); + + // loop over the track fit parameters + for(unsigned int ip = 0; ip < fitpars.size(); ++ip) + { + temp_fitpars[ip] += fitpars_delta[ip]; + + Acts::Vector3 temp_intersection = get_helix_surface_intersection(surf, temp_fitpars, global); + Acts::Vector3 intersection_delta = temp_intersection - intersection; + std::cout << "Layer " << layer << " local parameter " << ip << ":" << std::endl; + std::cout << " intersection " << intersection(0) << " " << intersection(1) << " " << intersection(2) << std::endl; + std::cout << " intersection " << temp_intersection(0) << " " << temp_intersection(1) << " " << temp_intersection(2) << std::endl; + std::cout << " intersection " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + + // convert to delta-intersection / delta-parameter + intersection_delta /= fitpars_delta[ip]; + std::cout << " intersection_delta / delta_p " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + + // calculate the change in residual for X and Y + lcl_derivativeX[ip] = intersection_delta.dot(projX); + lcl_derivativeY[ip] = intersection_delta.dot(projY); + std::cout << " ip " << ip << " derivativeX " << lcl_derivativeX[ip] << " " << " derivativeY " << lcl_derivativeY[ip] << std::endl; + + temp_fitpars[ip] = fitpars[ip]; + } +} + +void HelicalFitter::get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3 projY) +{ + // we only need the direction part of the tangent + Acts::Vector3 tanvec = tangent.second; + + // get the plane of the surface + Acts::Vector3 sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm; // convert to cm + // sensorNormal is the Z vector + Acts::Vector3 Z = -surf->normal(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm; + + // get surface X and Y unit vectors in global frame + // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 + Acts::Vector3 xloc(1.0,0.0,0.0); + Acts::Vector3 xglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm); + xglob /= Acts::UnitConstants::cm; + Acts::Vector3 yloc(0.0,1.0,0.0); + Acts::Vector3 yglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm); + yglob /= Acts::UnitConstants::cm; + + Acts::Vector3 X = (xglob-sensorCenter) / (xglob-sensorCenter).norm(); + Acts::Vector3 Y = (yglob-sensorCenter) / (yglob-sensorCenter).norm(); + + projX = X - (tanvec.dot(X) / tanvec.dot(Z)) * Z; + projY = Y - (tanvec.dot(Y) / tanvec.dot(Z)) * Z; + + return; +} + +// old one void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, float lcl_derivative[5], unsigned int layer) { float radius = fitpars[0]; @@ -897,11 +993,8 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A // Do these numerically // dx/dradius - // increasing R changes both local x and local y very little! + // Assume that increasing R changes both local x and local y very little! // float dx_dr = 0; - /* - OR: change R and transform fitpoint to local coords - */ // dx/dx0 // changing x0 changes global x by the same amount @@ -909,8 +1002,8 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A Acts::Vector3 fitpoint_now(fitpoint(0)+dx0, fitpoint(1), fitpoint(2)); Acts::Vector3 fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); fitpoint_local_now /= Acts::UnitConstants::cm; - Acts::Vector3 dres = fitpoint_local_now - fitpoint_local; - float dx_dx0 = dres(0) / dx0; + Acts::Vector3 dfitpoint = fitpoint_local_now - fitpoint_local; + float dx_dx0 = dfitpoint(0) / dx0; /* std::cout << " dx/dx0 " << dx_dx0 << std::endl << " fitpoint_local_now " << std::endl @@ -926,8 +1019,8 @@ void HelicalFitter::getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, A fitpoint_now(2) = fitpoint(2); fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); fitpoint_local_now /= Acts::UnitConstants::cm; - dres = fitpoint_local_now - fitpoint_local; - float dx_dy0 = dres(0) / dy0; + dfitpoint = fitpoint_local_now - fitpoint_local; + float dx_dy0 = dfitpoint(0) / dy0; /* std::cout << " dx/dy0 " << dx_dy0 << std::endl << " fitpoint_local_now " << std::endl @@ -971,8 +1064,8 @@ void HelicalFitter::getLocalDerivativesZ(Surface surf, Acts::Vector3& fitpoint, Acts::Vector3 fitpoint_now(fitpoint(0), fitpoint(1), fitpoint(2)+dz0); Acts::Vector3 fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); fitpoint_local_now /= Acts::UnitConstants::cm; - Acts::Vector3 dres = fitpoint_local_now - fitpoint_local; - float dz_dz0 = dres(1) / dz0; + Acts::Vector3 dfitpoint = fitpoint_local_now - fitpoint_local; + float dz_dz0 = dfitpoint(1) / dz0; /* std::cout << " dz/dz0 " << dz_dz0 << std::endl << " fitpoint_local_now " << std::endl @@ -987,8 +1080,8 @@ void HelicalFitter::getLocalDerivativesZ(Surface surf, Acts::Vector3& fitpoint, fitpoint_now(2) = fitpoint(2) + dzslope * cluster_radius; fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); fitpoint_local_now /= Acts::UnitConstants::cm; - dres = fitpoint_local_now - fitpoint_local; - float dz_dzslope = dres(1) / dzslope; + dfitpoint = fitpoint_local_now - fitpoint_local; + float dz_dzslope = dfitpoint(1) / dzslope; /* std::cout << " dz/dzslope " << dz_dzslope << std::endl << " fitpoint_local_now " << std::endl diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index a5e0f0ce15..34ba0cfddd 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -86,7 +86,7 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface Acts::Vector2 get_circle_point_pca(float radius, float x0, float y0, Acts::Vector3 global); Acts::Vector3 get_line_plane_intersection(Acts::Vector3 PCA, Acts::Vector3 tangent, Acts::Vector3 sensor_center, Acts::Vector3 sensor_normal); - std::pair get_helix_tangent(std::vector& fitpars, Acts::Vector3 global); + std::pair get_helix_tangent(const std::vector& fitpars, Acts::Vector3 global); Acts::Vector3 get_helix_surface_intersection(Surface surf, std::vector& fitpars, Acts::Vector3 global); int getLabelBase(Acts::GeometryIdentifier id); @@ -111,6 +111,10 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); + void getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer); + + void get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3 projY); + TpcClusterZCrossingCorrection m_clusterCrossingCorrection; TpcDistortionCorrectionContainer* _dcc_static{nullptr}; TpcDistortionCorrectionContainer* _dcc_average{nullptr}; diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 2a374cfee9..40bf4f5e89 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -32,9 +32,12 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { - localVerbosity = 3; + localVerbosity = 0; - std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_translations + use_new_transforms = true; + use_global_millepede_translations = 0; + + std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_millepede_translations << " use new transforms = " << use_new_transforms << std::endl; getNodes(topNode); @@ -367,7 +370,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: // create alignment translation matrix Acts::Transform3 mpTranslationAffine; mpTranslationAffine.linear() = nullRotation; - if(use_global_translations) + if(use_global_millepede_translations > 0) { mpTranslationAffine.translation() = millepedeTranslation; } @@ -395,7 +398,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: Acts::Transform3 transform; - if(use_global_translations) + if(use_global_millepede_translations > 0) { // put the mp translations in the global frame transform = mpTranslationAffine * actsTranslationAffine * actsRotationAffine * mpRotationAffine; @@ -409,16 +412,16 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(Surface surf, Eigen:: if(localVerbosity > 2) { std::cout << "newMakeTransform" << std::endl; - std::cout << " use_global_translations = " << use_global_translations << std::endl; + std::cout << " use_global_translations = " << use_global_millepede_translations << std::endl; std::cout << "mpRotationAffine: "<< std::endl<< mpRotationAffine.matrix() < 0) { std::cout << "mpTranslationAffine: " << std::endl << mpTranslationAffine.matrix() < Date: Fri, 21 Apr 2023 11:51:47 -0400 Subject: [PATCH 276/468] Local derivatives new method working. --- .../HelicalFitter.cc | 41 ++++++++++--------- .../TrackerMillepedeAlignment/HelicalFitter.h | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index bd472f2877..0be609148e 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -240,6 +240,7 @@ int HelicalFitter::process_event(PHCompositeNode*) { if(layer < 7) { + // radius = fitpars[0], X0 = fitpars[1], Y0 = fitpars[2], zslope = fitpars[3], Z0 = fitpars[4] std::cout << "Local residualsX: layer " << layer << " phi " << phi * 180 / M_PI << " beta " << beta * 180.90 / M_PI << " dxloc " << residual(0) << " error " << clus_sigma(0) << " xloc " << xloc << " fitxloc " << fitpoint_local(0) @@ -248,11 +249,11 @@ int HelicalFitter::process_event(PHCompositeNode*) << " yglob " << global(1) << " fityglob " << fitpoint(1) << " dzloc " << residual(1) << " X0 " << fitpars[1] << " Y0 " << fitpars[2] - << " derivx0 " << lcl_derivativeX[0] << " label " << 1 - << " derivx1 " << lcl_derivativeX[1] << " label " << 2 - << " derivx2 " << lcl_derivativeX[2] << " label " << 3 - << " derivx3 " << lcl_derivativeX[3] << " label " << 4 - << " derivx4 " << lcl_derivativeX[4] << " label " << 5 + << " derivx R " << lcl_derivativeX[0] << " label " << 1 + << " derivx X0 " << lcl_derivativeX[1] << " label " << 2 + << " derivx Y0 " << lcl_derivativeX[2] << " label " << 3 + << " derivx Zslope " << lcl_derivativeX[3] << " label " << 4 + << " derivx Z0" << lcl_derivativeX[4] << " label " << 5 << " glbl_derivative " << glbl_derivative[3] << " label " << glbl_label[3] << std::endl; } @@ -279,11 +280,11 @@ int HelicalFitter::process_event(PHCompositeNode*) << " yglob " << global(1) << " fityglob " << fitpoint(1) << " dxloc " << residual(0) << " zslope " << fitpars[3] << " Z0 " << fitpars[4] - << " derivy0 " << lcl_derivativeY[0] << " label " << 1 - << " derivy1 " << lcl_derivativeY[1] << " label " << 2 - << " derivy2 " << lcl_derivativeY[2] << " label " << 3 - << " derivy3 " << lcl_derivativeY[3] << " label " << 4 - << " derivy4 " << lcl_derivativeY[4] << " label " << 5 + << " derivy R " << lcl_derivativeY[0] << " label " << 1 + << " derivy X0 " << lcl_derivativeY[1] << " label " << 2 + << " derivy Y0 " << lcl_derivativeY[2] << " label " << 3 + << " derivy Zslope " << lcl_derivativeY[3] << " label " << 4 + << " derivy Z0 " << lcl_derivativeY[4] << " label " << 5 << " glbl_derivative " << glbl_derivative[5] << " label " << glbl_label[5] << std::endl; } @@ -904,22 +905,22 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Ac std::vector temp_fitpars; std::vector fitpars_delta; - fitpars_delta[0] = 0.1; // radius, cm - fitpars_delta[1] = 0.1; // X0, cm - fitpars_delta[2] = 0.1; // Y0, cm - fitpars_delta[3] = 0.1; // zslope, cm - fitpars_delta[4] = 0.1; // Z0, cm + fitpars_delta.push_back(0.1); // radius, cm + fitpars_delta.push_back(0.1); // X0, cm + fitpars_delta.push_back(0.1); // Y0, cm + fitpars_delta.push_back(0.1); // zslope, cm + fitpars_delta.push_back(0.1); // Z0, cm for(unsigned int ip = 0; ip < fitpars.size(); ++ip) { - temp_fitpars[ip] = fitpars[ip]; + temp_fitpars.push_back(fitpars[ip]); } // calculate projX and projY vectors once for the optimum fit parameters // std::pair tangent = get_helix_tangent(fitpars, global) std::pair tangent = get_helix_tangent(fitpars, fitpoint); - Acts::Vector3 projX, projY; + Acts::Vector3 projX(0,0,0), projY(0,0,0); get_projectionXY(surf, tangent, projX, projY); @@ -934,8 +935,8 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Ac Acts::Vector3 intersection_delta = temp_intersection - intersection; std::cout << "Layer " << layer << " local parameter " << ip << ":" << std::endl; std::cout << " intersection " << intersection(0) << " " << intersection(1) << " " << intersection(2) << std::endl; - std::cout << " intersection " << temp_intersection(0) << " " << temp_intersection(1) << " " << temp_intersection(2) << std::endl; - std::cout << " intersection " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + std::cout << " temp_intersection " << temp_intersection(0) << " " << temp_intersection(1) << " " << temp_intersection(2) << std::endl; + std::cout << " intersection_delta " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; // convert to delta-intersection / delta-parameter intersection_delta /= fitpars_delta[ip]; @@ -950,7 +951,7 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Ac } } -void HelicalFitter::get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3 projY) +void HelicalFitter::get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3& projY) { // we only need the direction part of the tangent Acts::Vector3 tanvec = tangent.second; diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index 34ba0cfddd..3cf70610f1 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -113,7 +113,7 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface void getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer); - void get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3 projY); + void get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3& projY); TpcClusterZCrossingCorrection m_clusterCrossingCorrection; TpcDistortionCorrectionContainer* _dcc_static{nullptr}; From 4fdd29770838d527e476db87aece1cf9b30d1689 Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Sat, 22 Apr 2023 12:56:54 -0400 Subject: [PATCH 277/468] Removing double D0 from MC jets --- .../packages/ResonanceJetTagging/ResonanceJetTagging.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc b/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc index d43c655b67..8cbde974d0 100644 --- a/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc +++ b/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc @@ -732,12 +732,12 @@ void ResonanceJetTagging::findMCTaggedJets(PHCompositeNode *topNode) decayIDs.push_back((*it)->barcode()); } //if not, look into GEANT - } + } else { PHG4TruthInfoContainer::ConstRange range = m_truthinfo->GetParticleRange(); for(PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) - { + { PHG4Particle* g4particle = iter->second; PHG4Particle* mother = nullptr; if (g4particle->get_parent_id() != 0) mother = m_truthinfo->GetParticle(g4particle->get_parent_id()); @@ -769,6 +769,10 @@ void ResonanceJetTagging::findMCTaggedJets(PHCompositeNode *topNode) { continue; } + if (std::abs((*p)->pdg_id()) == m_tag_pdg) + { + continue; + } partPDG = database->GetParticle((*p)->pdg_id()); double hepmcPartPt = std::sqrt(((*p)->momentum().px() * (*p)->momentum().px()) + ((*p)->momentum().py() * (*p)->momentum().py())); From 978b15da0ce77ab11b2c27da78f9d865c189cf73 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Sun, 23 Apr 2023 23:33:30 -0400 Subject: [PATCH 278/468] Implement new global derivatives method. Change transforms default to specify translations in global frame. --- .../HelicalFitter.cc | 136 +++++++++++++----- .../TrackerMillepedeAlignment/HelicalFitter.h | 4 +- .../trackbase/AlignmentTransformation.cc | 2 +- 3 files changed, 102 insertions(+), 40 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 0be609148e..f568272c2a 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -121,9 +121,6 @@ int HelicalFitter::process_event(PHCompositeNode*) std::vector global_vec; std::vector cluskey_vec; - - ////getTrackletClusters(tracklet, global_vec, cluskey_vec); // store cluster corrected global positions in a vector - // Get a vector of cluster keys from the tracklet getTrackletClusterList(tracklet, cluskey_vec); // store cluster global positions in a vector @@ -170,7 +167,7 @@ int HelicalFitter::process_event(PHCompositeNode*) // What we need now is to find the point on the surface at which the helix would intersect // If we have that point, we can transform the fit back to local coords - // we have fitpars for the helix and the cluster key, from which we get the surface + // we have fitpars for the helix, and the cluster key - from which we get the surface Surface surf = _tGeometry->maps().getSurface(cluskey, cluster); Acts::Vector3 fitpoint = get_helix_surface_intersection(surf, fitpars, global); @@ -180,11 +177,6 @@ int HelicalFitter::process_event(PHCompositeNode*) Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; - /* - std::cout << " inverse transform used for fitpoint:" << std::endl << surf->transform(_tGeometry->geometry().getGeoContext()).inverse().matrix() << std::endl; - std::cout << "local-global transform " << std::endl << surf->transform(_tGeometry->geometry().getGeoContext()).matrix() << std::endl; - */ - auto xloc = cluster->getLocalX(); // in cm auto zloc = cluster->getLocalY(); if(trkrid == TrkrDefs::tpcId) { zloc = convertTimeToZ(cluskey, cluster); } @@ -222,18 +214,24 @@ int HelicalFitter::process_event(PHCompositeNode*) float lcl_derivativeX[NLC]; float lcl_derivativeY[NLC]; - float glbl_derivative[NGL]; + getLocalDerivativesXY(surf, global, fitpars, lcl_derivativeX, lcl_derivativeY, layer); - getLocalDerivativesXY(surf, global, fitpoint, fitpars, lcl_derivativeX, lcl_derivativeY, layer); + float glbl_derivativeX[NGL]; + float glbl_derivativeY[NGL]; + getGlobalDerivativesXY(surf, global, fitpoint, fitpars, glbl_derivativeX, glbl_derivativeY, layer); + + for(unsigned int i = 0; i < NGL; ++i) + { + if(is_layer_param_fixed(layer, i) || is_layer_fixed(layer)) + { + glbl_derivativeX[i] = 0; + glbl_derivativeY[i] = 0; + } + } // Add the measurement separately for each coordinate direction to Mille // set the derivatives non-zero only for parameters we want to be optimized // local parameter numbering is arbitrary: - // using 0=x0, 1=y0, 2=z0, 3=R, 4=zslope - //getLocalDerivativesX(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); - getGlobalDerivativesX(angleDerivs, translDerivs, glbl_derivative, layer); - // if(Verbosity() > 1) - //{ std::cout << "layer " << layer << " X buffers:" << std::endl; printBuffers(0, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) @@ -253,20 +251,20 @@ int HelicalFitter::process_event(PHCompositeNode*) << " derivx X0 " << lcl_derivativeX[1] << " label " << 2 << " derivx Y0 " << lcl_derivativeX[2] << " label " << 3 << " derivx Zslope " << lcl_derivativeX[3] << " label " << 4 - << " derivx Z0" << lcl_derivativeX[4] << " label " << 5 - << " glbl_derivative " << glbl_derivative[3] << " label " << glbl_label[3] + << " derivx Z0 " << lcl_derivativeX[4] << " label " << 5 + << " glblderivX alpha " << glbl_derivativeX[0] << " label " << glbl_label[0] + << " glblderivX beta " << glbl_derivativeX[1] << " label " << glbl_label[1] + << " glblderivX gamma " << glbl_derivativeX[2] << " label " << glbl_label[2] + << " glblderivX xtrans " << glbl_derivativeX[3] << " label " << glbl_label[3] + << " glblderivX ytrans " << glbl_derivativeX[4] << " label " << glbl_label[4] + << " glblderivX ztrans " << glbl_derivativeX[5] << " label " << glbl_label[5] << std::endl; } - } - + } + if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters - { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivative, glbl_label, residual(0), _error_inflation*clus_sigma(0));} + { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivativeX, glbl_label, residual(0), _error_inflation*clus_sigma(0));} - - //getLocalDerivativesZ(surf, fitpoint, fitpoint_local, fitpars, lcl_derivative, layer); - getGlobalDerivativesZ(angleDerivs, translDerivs, glbl_derivative, layer); - //getGlobalDerivativesY(angleDerivs, translDerivs, glbl_derivative, layer); // in local coords alpha and dx are applied to x axis, beta and "dz" to y axis - // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) { @@ -285,15 +283,18 @@ int HelicalFitter::process_event(PHCompositeNode*) << " derivy Y0 " << lcl_derivativeY[2] << " label " << 3 << " derivy Zslope " << lcl_derivativeY[3] << " label " << 4 << " derivy Z0 " << lcl_derivativeY[4] << " label " << 5 - << " glbl_derivative " << glbl_derivative[5] << " label " << glbl_label[5] + << " glblderivY alpha " << glbl_derivativeY[0] << " label " << glbl_label[0] + << " glblderivY beta " << glbl_derivativeY[1] << " label " << glbl_label[1] + << " glblderivY gamma " << glbl_derivativeY[2] << " label " << glbl_label[2] + << " glblderivY xtrans " << glbl_derivativeY[3] << " label " << glbl_label[3] + << " glblderivY ytrans " << glbl_derivativeY[4] << " label " << glbl_label[4] + << " glblderivY ztrans " << glbl_derivativeY[5] << " label " << glbl_label[5] << std::endl; } } - // if(Verbosity() > 1) - //{ std::cout << "layer " << layer << " Z buffers:" << std::endl; printBuffers(1, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivative, glbl_label, residual(1), _error_inflation*clus_sigma(1));} + {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivativeY, glbl_label, residual(1), _error_inflation*clus_sigma(1));} } // close out this track @@ -899,7 +900,7 @@ Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster *cluster, TrkrDefs::clu } // new one -void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer) +void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer) { // Calculate the derivatives of the residual wrt the track parameters numerically std::vector temp_fitpars; @@ -918,7 +919,7 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Ac // calculate projX and projY vectors once for the optimum fit parameters // std::pair tangent = get_helix_tangent(fitpars, global) - std::pair tangent = get_helix_tangent(fitpars, fitpoint); + std::pair tangent = get_helix_tangent(fitpars, global); // should this be global, not fitpoint? Acts::Vector3 projX(0,0,0), projY(0,0,0); get_projectionXY(surf, tangent, projX, projY); @@ -933,24 +934,83 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Ac Acts::Vector3 temp_intersection = get_helix_surface_intersection(surf, temp_fitpars, global); Acts::Vector3 intersection_delta = temp_intersection - intersection; - std::cout << "Layer " << layer << " local parameter " << ip << ":" << std::endl; - std::cout << " intersection " << intersection(0) << " " << intersection(1) << " " << intersection(2) << std::endl; - std::cout << " temp_intersection " << temp_intersection(0) << " " << temp_intersection(1) << " " << temp_intersection(2) << std::endl; - std::cout << " intersection_delta " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + if(Verbosity() > 1) + { + std::cout << "Layer " << layer << " local parameter " << ip << ":" << std::endl; + std::cout << " intersection " << intersection(0) << " " << intersection(1) << " " << intersection(2) << std::endl; + std::cout << " temp_intersection " << temp_intersection(0) << " "<< temp_intersection(1) << " "<< temp_intersection(2)<< std::endl; + std::cout << " intersection_delta " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + } // convert to delta-intersection / delta-parameter intersection_delta /= fitpars_delta[ip]; - std::cout << " intersection_delta / delta_p " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; + + if(Verbosity() > 1) + {std::cout << " intersection_delta / delta_p " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl;} // calculate the change in residual for X and Y lcl_derivativeX[ip] = intersection_delta.dot(projX); lcl_derivativeY[ip] = intersection_delta.dot(projY); - std::cout << " ip " << ip << " derivativeX " << lcl_derivativeX[ip] << " " << " derivativeY " << lcl_derivativeY[ip] << std::endl; + if(Verbosity() > 1) + {std::cout << " ip " << ip << " derivativeX " << lcl_derivativeX[ip] << " " << " derivativeY " << lcl_derivativeY[ip] << std::endl;} temp_fitpars[ip] = fitpars[ip]; } } +void HelicalFitter::getGlobalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float glbl_derivativeX[6], float glbl_derivativeY[6], unsigned int layer) +{ + Acts::Vector3 unitx(1, 0, 0); + Acts::Vector3 unity(0, 1, 0); + Acts::Vector3 unitz(0, 0, 1); + + // calculate projX and projY vectors once for the optimum fit parameters + std::pair tangent = get_helix_tangent(fitpars, global); // should this be global, not fitpoint? + + Acts::Vector3 projX(0,0,0), projY(0,0,0); + get_projectionXY(surf, tangent, projX, projY); + + // translations + + glbl_derivativeX[3] = unitx.dot(projX); + glbl_derivativeX[4] = unity.dot(projX); + glbl_derivativeX[5] = unitz.dot(projX); + + glbl_derivativeY[3] = unitx.dot(projY); + glbl_derivativeY[4] = unity.dot(projY); + glbl_derivativeY[5] = unitz.dot(projY); + + // rotations + + // need center of sensor to intersection point + Acts::Vector3 sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm; // convert to cm + Acts::Vector3 OM = fitpoint - sensorCenter; + + glbl_derivativeX[0] = (unitx.cross(OM)).dot(projX); + glbl_derivativeX[1] = (unity.cross(OM)).dot(projX); + glbl_derivativeX[2] = (unitz.cross(OM)).dot(projX); + + glbl_derivativeY[0] = (unitx.cross(OM)).dot(projY); + glbl_derivativeY[1] = (unity.cross(OM)).dot(projY); + glbl_derivativeY[2] = (unitz.cross(OM)).dot(projY); + + if(Verbosity() > 1) + { + std::cout << " glbl_derivativesX for layer " << layer << std::endl; + for(unsigned int i = 0; i < 6; ++i) + { + std::cout << " i " << i << " glbl_derivative " << glbl_derivativeX[i] << std::endl; + } + + std::cout << " glbl_derivativesY for layer " << layer << std::endl; + for(unsigned int i = 0; i < 6; ++i) + { + std::cout << " i " << i << " glbl_derivative " << glbl_derivativeY[i] << std::endl; + } + } + + +} void HelicalFitter::get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3& projY) { // we only need the direction part of the tangent diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index 3cf70610f1..a8bce86a37 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -111,7 +111,9 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); - void getLocalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer); + void getLocalDerivativesXY(Surface surf, Acts::Vector3 global, const std::vector& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer); + + void getGlobalDerivativesXY(Surface surf, Acts::Vector3 global, Acts::Vector3 fitpoint, const std::vector& fitpars, float glb_derivativeX[6], float glbl_derivativeY[6], unsigned int layer); void get_projectionXY(Surface surf, std::pair tangent, Acts::Vector3& projX, Acts::Vector3& projY); diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 88196d0435..652d4154c3 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -35,7 +35,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) localVerbosity = 0; use_new_transforms = true; - use_global_millepede_translations = 0; + use_global_millepede_translations = 1; std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_millepede_translations << " use new transforms = " << use_new_transforms << std::endl; From 0b95bc0e05b54562012d698c72375a83d76d9594 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 24 Apr 2023 11:12:03 -0400 Subject: [PATCH 279/468] compatible with nopayload update --- offline/database/sphenixnpc/sphenixnpc.cc | 31 ++++++++++++++--------- offline/database/sphenixnpc/sphenixnpc.h | 1 - 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index 743f38e1a1..d964b8637f 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -20,12 +20,17 @@ sphenixnpc::~sphenixnpc() int sphenixnpc::createGlobalTag(const std::string &tagname) { setGlobalTag(tagname); - nlohmann::json result = nopayloadclient::Client::createGlobalTag(); - if (Verbosity()) + nlohmann::json resp = nopayloadclient::Client::createGlobalTag(); + int iret = resp["code"]; + if (iret != 0) { - std::cout << result << std::endl; + std::cout << "Error creating global tag, msg: " << resp["msg"] << std::endl; } - return 0; + else + { + std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; + } + return iret; } int sphenixnpc::deleteGlobalTag(const std::string &tagname) @@ -41,7 +46,7 @@ int sphenixnpc::deleteGlobalTag(const std::string &tagname) nlohmann::json sphenixnpc::getUrlDict(long long iov) { - return nopayloadclient::Client::getUrlDict(0, iov); + return nopayloadclient::Client::getUrlDict(iov,iov); } nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) @@ -49,6 +54,9 @@ nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) if (url_dict_.is_null()) { nlohmann::json resp = getUrlDict(iov); + std::cout << "response" << std::endl; + std::cout << resp << std::endl; + std::cout << "end response" << std::endl; if (resp["code"] != 0) { return resp; @@ -62,17 +70,16 @@ nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) return makeResp(url_dict_[pl_type]); } -int sphenixnpc::cache_set_GlobalTag(const std::string &name) +int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) { int iret = 0; - if (name == m_CachedGlobalTag) // global tag already set + if (tagname == m_CachedGlobalTag) // global tag already set { return iret; } url_dict_ = nlohmann::json{}; - m_CachedGlobalTag = name; - //return nopayloadclient::Client::setGlobalTag(name); - nopayloadclient::Client::setGlobalTag(name); + m_CachedGlobalTag = tagname; + nopayloadclient::Client::setGlobalTag(tagname); bool found_gt = false; nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; @@ -80,7 +87,7 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &name) { std::string exist_gt = it.value().at("name"); std::cout << "global tag: " << exist_gt << std::endl; - if (exist_gt == name) + if (exist_gt == tagname) { found_gt = true; break; @@ -96,7 +103,7 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &name) } else { - std::cout << "sphenixnpc: Created new global tag " << name << std::endl; + std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; } } return iret; diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 3f83b00fd9..c5c02df8c1 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -13,7 +13,6 @@ class sphenixnpc : public nopayloadclient::Client public: using nopayloadclient::Client::createGlobalTag; using nopayloadclient::Client::deleteGlobalTag; - using nopayloadclient::Client::getUrlDict; using nopayloadclient::Client::setGlobalTag; static sphenixnpc *instance(const std::string &globaltag = "NONE"); From 4a323e1af8623807ba4cffabd936a14085e39b79 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 24 Apr 2023 11:32:30 -0400 Subject: [PATCH 280/468] cosmetic changes to trigger jenkins --- offline/database/sphenixnpc/sphenixnpc.cc | 5 +++++ offline/database/sphenixnpc/sphenixnpc.h | 3 +++ offline/framework/ffaobjects/CdbUrlSavev1.h | 2 ++ offline/framework/fun4all/Fun4AllBase.cc | 1 + 4 files changed, 11 insertions(+) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index d964b8637f..ed7a82bc2d 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -49,6 +49,11 @@ nlohmann::json sphenixnpc::getUrlDict(long long iov) return nopayloadclient::Client::getUrlDict(iov,iov); } +nlohmann::json sphenixnpc::getUrlDict(long long iov1, long long iov2) +{ + return nopayloadclient::Client::getUrlDict(iov1,iov2); +} + nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) { if (url_dict_.is_null()) diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index c5c02df8c1..c6ac0eb1b6 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -5,8 +5,10 @@ #include +#include #include #include +#include class sphenixnpc : public nopayloadclient::Client { @@ -18,6 +20,7 @@ class sphenixnpc : public nopayloadclient::Client static sphenixnpc *instance(const std::string &globaltag = "NONE"); ~sphenixnpc(); nlohmann::json getUrlDict(long long iov); + nlohmann::json getUrlDict(long long iov1, long long iov2) override; int createGlobalTag(const std::string &tagname); int createDomain(const std::string &domain); nlohmann::json get(const std::string &pl_type, long long iov); diff --git a/offline/framework/ffaobjects/CdbUrlSavev1.h b/offline/framework/ffaobjects/CdbUrlSavev1.h index ca8da58a00..0138c339c0 100644 --- a/offline/framework/ffaobjects/CdbUrlSavev1.h +++ b/offline/framework/ffaobjects/CdbUrlSavev1.h @@ -11,6 +11,8 @@ #include #include // for vector<>::const_iterator, vector +class PHObject; + /// class CdbUrlSavev1 : public CdbUrlSave { diff --git a/offline/framework/fun4all/Fun4AllBase.cc b/offline/framework/fun4all/Fun4AllBase.cc index 002d07f598..eb6811fd9c 100644 --- a/offline/framework/fun4all/Fun4AllBase.cc +++ b/offline/framework/fun4all/Fun4AllBase.cc @@ -1,5 +1,6 @@ #include "Fun4AllBase.h" +#include #include #include From a1577d16128dfecb4b3090eb485427f1ebf4d32c Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 24 Apr 2023 13:41:52 -0400 Subject: [PATCH 281/468] Removed all unused code. Alignment transforms default to global translation parameters. --- .../HelicalFitter.cc | 411 +----------------- .../TrackerMillepedeAlignment/HelicalFitter.h | 13 +- .../trackbase/AlignmentTransformation.cc | 185 +------- .../trackbase/AlignmentTransformation.h | 10 +- 4 files changed, 16 insertions(+), 603 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index f568272c2a..3d0ec936cf 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -209,8 +209,8 @@ int HelicalFitter::process_event(PHCompositeNode*) // These derivatives are for the local parameters // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) - std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); - std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); + //std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); + //std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); float lcl_derivativeX[NLC]; float lcl_derivativeY[NLC]; @@ -487,218 +487,6 @@ Acts::Vector2 HelicalFitter::get_circle_point_pca(float radius, float x0, float return pca; } -std::vector HelicalFitter::getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) -{ - std::vector derivs_vector; - - unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); - unsigned int layer = TrkrDefs::getLayer(cluster_key); - - auto x = cluster->getLocalX(); // in cm - auto y = cluster->getLocalY(); - if(trkrId == TrkrDefs::tpcId) { y = convertTimeToZ(cluster_key, cluster); } - float z = 0.0; // y is unused in local coordinates - - // Make a transform that applies small translations in the surface frame - for(unsigned int itrans = 0; itrans < 3; ++itrans) - { - // creates transform that adds a perturbation translation along one axis, uses it to estimate derivative wrt perturbation translation - - Acts::Vector3 derivs(0,0,0); - Eigen::Vector3d theseTransl(0,0,0); - theseTransl[itrans] = sensorTransl[itrans]; // set the one we want to be non-zero - - Acts::Vector3 keeper(0,0,0); - for(int ip = 0; ip < 2; ++ip) - { - if(ip == 1) { theseTransl[itrans] *= -1; } // test both sides of zero - - if(Verbosity() > 1) - { std::cout << " trkrId " << trkrId << " layer " << layer << " cluster_key " << cluster_key - << " sensorTransl " << theseTransl[0] << " " << theseTransl[1] << " " << theseTransl[2] << std::endl; } - - Acts::Transform3 perturbationTranslation = makePerturbationTranslation(theseTransl); - - // the perturbation translation here is entirely in the local frame - // our convention has (x,y) as local, applies until Acts global rotation occurs - Eigen::Vector3d clusterLocalPosition (x,y,z); - Eigen::Vector3d finalCoords = perturbationTranslation*(clusterLocalPosition * 10.0); // convert clusterLocalPosition to mm - finalCoords /= 10.0; // convert mm back to cm - - // have to add corrections for TPC clusters after transformation to global - // if(trkrId == TrkrDefs::tpcId) { makeTpcGlobalCorrections(cluster_key, crossing, global); } - - // note that x, y and z cancel out here - if(ip == 0) - { - keeper(0) = (finalCoords(0) - x); - keeper(1) = (finalCoords(1) - y); - keeper(2) = (finalCoords(2) - z); - } - else - { - keeper(0) -= (finalCoords(0) - x); - keeper(1) -= (finalCoords(1) - y); - keeper(2) -= (finalCoords(2) - z); - } - - if(Verbosity() > 2) - { - std::cout << " AlignmentTranslationsDerivs: finalCoords(0) " << finalCoords(0) << " finalCoords(1) " - << finalCoords(1) << " finalCoords(2) " << finalCoords(2) << std::endl; - std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " - << keeper(2) << std::endl; - } - - if(Verbosity() > 20) { std::cout << " global " << global << std::endl; } - } - - // derivs vector contains: - // (dx/dx, dy/dx, dz/dx) (for itrans = 0) - // (dx/dy, dy/dy, dz/dy) (for itrans = 1) - // (dx/dz, dy/dz, dz/dz) (for itrans = 2) - - // Average the changes to get the estimate of the derivative - derivs(0) = keeper(0) / (2.0 * 0.1 * fabs(theseTransl[itrans])); // convert theseTransl to cm - if( isnan(derivs(0)) ) { derivs(0) = 0; } - derivs(1) = keeper(1) / (2.0 * 0.1 * fabs(theseTransl[itrans])); - if( isnan(derivs(1)) ) { derivs(1) = 0; } - derivs(2) = keeper(2) / (2.0 * 0.1 * fabs(theseTransl[itrans])); - if( isnan(derivs(2)) ) { derivs(2) = 0; } - derivs_vector.push_back(derivs); - - if(Verbosity() > 1) { std::cout << " AlignmentTranslationsDerivs: itrans " << itrans << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } - } - return derivs_vector; -} - -std::vector HelicalFitter::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) -{ - // We want the effect of a small rotation around the relevant axis in the local frame on the local coords - - std::vector derivs_vector; - - // transform the cluster local position using this additional rotation - auto x = cluster->getLocalX(); // cm - auto z = cluster->getLocalY(); - float y = 0; - - unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); - unsigned int layer = TrkrDefs::getLayer(cluster_key); - if(trkrId == TrkrDefs::tpcId) { z = convertTimeToZ(cluster_key, cluster); } - - if(Verbosity() > 1) - { - std::cout << " AlignmentAngleDerivs: clusterLocalPosition(0) " << x << " clusterLocalPosition(1) " << y - << " clusterLocalPosition(2) " << z << std::endl; - } - - for(unsigned int iangle = 0; iangle < 3; ++iangle) - { - // creates transform that adds a perturbation rotation around one axis, uses it to estimate derivative wrt perturbation rotation - - - Acts::Vector3 derivs(0,0,0); - Eigen::Vector3d theseAngles(0,0,0); - theseAngles[iangle] = sensorAngles[iangle]; // set the one we want to be non-zero - - Acts::Vector3 keeper(0,0,0); - for(int ip = 0; ip < 2; ++ip) - { - if(ip == 1) { theseAngles[iangle] *= -1; } // test both sides of zero - - if(Verbosity() > 1) - { std::cout << " trkrId " << trkrId << " layer " << layer << " cluster_key " << cluster_key - << " sensorAngles " << theseAngles[0] << " " << theseAngles[1] << " " << theseAngles[2] << std::endl; } - - Acts::Transform3 perturbationTransformation = makePerturbationTransformation(theseAngles); - - Eigen::Vector3d clusterLocalPosition (x,0,z); // our convention has (x,z) as local, applies until Acts global rotation occurs - Eigen::Vector3d finalLocalPosition = perturbationTransformation*(clusterLocalPosition * 10.0); // clusterLocalPosition and result both in mm - finalLocalPosition /= 10.0; // convert mm back to cm - - // Added corrections for TPC clusters after transformation to global - // The helical fit is to corrected data, so if we transform back to local, can - // we compare with the cluster local? What is needed here for the TPC? - - // note that x, y and z cancel out here - if(ip == 0) - { - keeper(0) = (finalLocalPosition(0) - x); - keeper(1) = (finalLocalPosition(1) - y); - keeper(2) = (finalLocalPosition(2) - z); - } - else - { - keeper(0) -= (finalLocalPosition(0) - x); - keeper(1) -= (finalLocalPosition(1) - y); - keeper(2) -= (finalLocalPosition(2) - z); - } - - if(Verbosity() > 2) - { - std::cout << " AlignmentAngleDerivs: finalLocalPosition(0) " << finalLocalPosition(0) << " finalLocalPosition(1) " << finalLocalPosition(1) - << " finalLocalPosition(2) " << finalLocalPosition(2) << std::endl; - std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; - } - - if(Verbosity() > 20) { std::cout << " global " << global << std::endl; } - } - - // derivs vector contains: - // (dx/dalpha, dz/dalpha) (for iangle = 0) - // (dx/dbeta, dz/dbeta) (for iangle = 1) - // (dx/dgamma, dz/dgamma) (for iangle = 2) - - // Average the changes to get the estimate of the derivative - derivs(0) = keeper(0) / (2.0 * fabs(theseAngles[iangle])); - if( isnan(derivs(0)) ) { derivs(0) = 0; } - derivs(1) = keeper(1) / (2.0 * fabs(theseAngles[iangle])); // this would be the unused y axis in the local coord frame - if( isnan(derivs(1)) ) { derivs(1) = 0; } - derivs(2) = keeper(2) / (2.0 * fabs(theseAngles[iangle])); - if( isnan(derivs(2)) ) { derivs(2) = 0; } - derivs_vector.push_back(derivs); - - if(Verbosity() > 1) { std::cout << " AlignmentAngleDerivs: iangle " << iangle << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; } - } - - return derivs_vector; -} - - Acts::Transform3 HelicalFitter::makePerturbationTranslation(Acts::Vector3 translations) - { - // combine unit rotation and perturbation translations in the local frame into an affine matrix - Acts::Transform3 perturbationTransformation; - - Eigen::AngleAxisd alpha(0.0, Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(0.0, Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(0.0, Eigen::Vector3d::UnitZ()); - Eigen::Quaternion q = gamma*beta*alpha; - Eigen::Matrix3d nullRotation = q.matrix(); - perturbationTransformation.linear() = nullRotation; - - perturbationTransformation.translation() = translations; - - return perturbationTransformation; - } - - Acts::Transform3 HelicalFitter::makePerturbationTransformation(Acts::Vector3 angles) - { - Eigen::AngleAxisd alpha(angles(0), Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(angles(1), Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(angles(2), Eigen::Vector3d::UnitZ()); - Eigen::Quaternion q = gamma*beta*alpha; - Eigen::Matrix3d perturbationRotation = q.matrix(); - - // combine rotation and translation into an affine matrix - Eigen::Vector3d nullTranslation(0,0,0); - Acts::Transform3 perturbationTransformation; - perturbationTransformation.linear() = perturbationRotation; - perturbationTransformation.translation() = nullTranslation; - - return perturbationTransformation; - } - float HelicalFitter::convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster *cluster) { // must convert local Y from cluster average time of arival to local cluster z position @@ -1039,201 +827,6 @@ void HelicalFitter::get_projectionXY(Surface surf, std::pair& fitpars, float lcl_derivative[5], unsigned int layer) -{ - float radius = fitpars[0]; - float x0 = fitpars[1]; - float y0 = fitpars[2]; - float x = fitpoint_local(0); - float y = fitpoint_local(2); - - // fitpoint is in global coords, fitpoint_local in local coords - // local x is unaffected by the z fit - // We only need to consider the circle fit paramaters - // Do these numerically - - // dx/dradius - // Assume that increasing R changes both local x and local y very little! - // float dx_dr = 0; - - // dx/dx0 - // changing x0 changes global x by the same amount - float dx0 = 0.01; - Acts::Vector3 fitpoint_now(fitpoint(0)+dx0, fitpoint(1), fitpoint(2)); - Acts::Vector3 fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); - fitpoint_local_now /= Acts::UnitConstants::cm; - Acts::Vector3 dfitpoint = fitpoint_local_now - fitpoint_local; - float dx_dx0 = dfitpoint(0) / dx0; - /* - std::cout << " dx/dx0 " << dx_dx0 << std::endl - << " fitpoint_local_now " << std::endl - << fitpoint_local_now << std::endl - << " fitpoint_local " << std::endl - << fitpoint_local << std::endl; - */ - - float dy0 = 0.01; - // changing y0 changes global y by the same amount - fitpoint_now(0) = fitpoint(0); - fitpoint_now(1) = fitpoint(1)+dy0; - fitpoint_now(2) = fitpoint(2); - fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); - fitpoint_local_now /= Acts::UnitConstants::cm; - dfitpoint = fitpoint_local_now - fitpoint_local; - float dx_dy0 = dfitpoint(0) / dy0; - /* - std::cout << " dx/dy0 " << dx_dy0 << std::endl - << " fitpoint_local_now " << std::endl - << fitpoint_local_now << std::endl - << " fitpoint_local " << std::endl - << fitpoint_local << std::endl; - */ - - if(Verbosity() > 1) { - std::cout << " layer " << layer << " x " << x << " y " << y << " x0 " << x0 << " y0 " << y0 << " R " << radius << std::endl; - std::cout << " LclDerivsX: dx_dx0 " << dx_dx0 << " dx_dy0 " << dx_dy0 << std::endl; - } - - for(int i=0;i& fitpars, float lcl_derivative[5], unsigned int layer) -{ - // the local coord corresponding to z is local-y. - // changes in z global translate directly to y-local - - float zslope = fitpars[3]; - float cluster_radius = sqrt(fitpoint(0)*fitpoint(0)+fitpoint(1)*fitpoint(1)); - float z0 = fitpars[4]; - - /* - // This is correct: - // z = z0 + zslope * cluster_radius - float dz_dz0 = 1.0; - float dz_dzslope = cluster_radius; - */ - - // This is safer: - - float dz0 = 0.01; - Acts::Vector3 fitpoint_now(fitpoint(0), fitpoint(1), fitpoint(2)+dz0); - Acts::Vector3 fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); - fitpoint_local_now /= Acts::UnitConstants::cm; - Acts::Vector3 dfitpoint = fitpoint_local_now - fitpoint_local; - float dz_dz0 = dfitpoint(1) / dz0; - /* - std::cout << " dz/dz0 " << dz_dz0 << std::endl - << " fitpoint_local_now " << std::endl - << fitpoint_local_now << std::endl - << " fitpoint_local " << std::endl - << fitpoint_local << std::endl; - */ - - float dzslope = 0.01; - fitpoint_now(0) = fitpoint(0); - fitpoint_now(1) = fitpoint(1); - fitpoint_now(2) = fitpoint(2) + dzslope * cluster_radius; - fitpoint_local_now = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_now * Acts::UnitConstants::cm); - fitpoint_local_now /= Acts::UnitConstants::cm; - dfitpoint = fitpoint_local_now - fitpoint_local; - float dz_dzslope = dfitpoint(1) / dzslope; - /* - std::cout << " dz/dzslope " << dz_dzslope << std::endl - << " fitpoint_local_now " << std::endl - << fitpoint_local_now << std::endl - << " fitpoint_local " << std::endl - << fitpoint_local << std::endl; - */ - - if(Verbosity() > 1) { - std::cout << " layer " << layer << " x " << fitpoint(0)<<" y "< angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) -{ - // local-x: relevant global pars are alpha, beta, gamma, dx (ipar 0,1,2,3) - // Because x is local x (i.e. r*phi) it is independent of local y (i.e. local z) - for(int i=0;i angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) -{ - // y - relevant global pars are alpha, beta, gamma, dy (ipar 0,1,2,4) - for(int i=0;i angleDerivs, std::vector translDerivs, float glbl_derivative[], unsigned int layer) -{ - // z - relevant global pars are alpha, beta, dz (ipar 0,1,5) - for(int i=0;i& fitpars, Acts::Vector3 global); int getLabelBase(Acts::GeometryIdentifier id); - Acts::Transform3 makePerturbationTransformation(Acts::Vector3 angles); - Acts::Transform3 makePerturbationTranslation(Acts::Vector3 translations); - std::vector getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); - std::vector getDerivativesAlignmentTranslations(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); + float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); void makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global); int getTpcRegion(int layer); Acts::Vector2 getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global); void getGlobalLabels(Surface surf, int glbl_label[]); - void getLocalDerivativesX(Surface surf, Acts::Vector3 fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, - float lcl_derivative[5], unsigned int layer); - void getLocalDerivativesZ(Surface surf, Acts::Vector3& fitpoint, Acts::Vector3& fitpoint_local, std::vector& fitpars, - float lcl_derivative[5], unsigned int layer); - void getGlobalDerivativesX( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - void getGlobalDerivativesY( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); - void getGlobalDerivativesZ( std::vector angleDerivs, std::vector translDerivs, float glbl_derivatives[], unsigned int layer); + void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 652d4154c3..ef9a887d4b 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -34,11 +34,9 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { localVerbosity = 0; - use_new_transforms = true; - use_global_millepede_translations = 1; - - std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_millepede_translations - << " use new transforms = " << use_new_transforms << std::endl; + // The default is to use translation parameters that are in global coordinates + use_global_millepede_translations = true; + std::cout << "AlignmentTransformation: use global translation perturbations = " << use_global_millepede_translations << std::endl; getNodes(topNode); @@ -96,14 +94,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) surf = surfMaps.getSiliconSurface(hitsetkey); Acts::Transform3 transform; - if(use_new_transforms) - { - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); - } - else - { - transform = makeTransform(surf, millepedeTranslation, sensorAngles); - } + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); + Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -111,8 +103,6 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; std::cout << " final mvtx transform:" << std::endl << transform.matrix() << std::endl; - Acts::Transform3 transform2 = makeTransform(surf, millepedeTranslation, sensorAngles); - std::cout << "mvtx transform2:" << std::endl << transform2.matrix() << std::endl; } transformMap->addTransform(id,transform); } @@ -130,14 +120,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) surf = surfMaps.getSiliconSurface(hitsetkey); Acts::Transform3 transform; - if(use_new_transforms) - { - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); - } - else - { - transform = makeTransform(surf, millepedeTranslation, sensorAngles); - } + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -167,14 +150,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) surf = surfMaps.getTpcSurface(hitsetkey,subsurfkey); Acts::Transform3 transform; - if(use_new_transforms) - { - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); - } - else - { - transform = makeTransform(surf, millepedeTranslation, sensorAngles); - } + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -196,14 +172,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) surf = surfMaps.getMMSurface(hitsetkey); Acts::Transform3 transform; - if(use_new_transforms) - { - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); - } - else - { - transform = makeTransform(surf, millepedeTranslation, sensorAngles); - } + transform = newMakeTransform(surf, millepedeTranslation, sensorAngles); Acts::GeometryIdentifier id = surf->geometryId(); if(localVerbosity) @@ -229,111 +198,6 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } -// no longer used -Eigen::Matrix3d AlignmentTransformation::rotateToGlobal(Surface surf) -{ - /* - Get ideal geometry rotation, by aligning surface to surface normal vector in global coordinates - URL: https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d - */ - - Eigen::Vector3d ylocal(0,1,0); - Eigen::Vector3d sensorNormal = -surf->normal(m_tGeometry->geometry().getGeoContext()); - sensorNormal = sensorNormal/sensorNormal.norm(); // make unit vector - double cosTheta = ylocal.dot(sensorNormal); - double sinTheta = (ylocal.cross(sensorNormal)).norm(); - Eigen::Vector3d vectorRejection = (sensorNormal - (ylocal.dot(sensorNormal))*ylocal)/(sensorNormal - (ylocal.dot(sensorNormal))*ylocal).norm(); - Eigen::Vector3d perpVector = sensorNormal.cross(ylocal); - - // Initialize and fill matrices (row,col) - Eigen::Matrix3d fInverse; - fInverse(0,0) = ylocal(0); - fInverse(1,0) = ylocal(1); - fInverse(2,0) = ylocal(2); - fInverse(0,1) = vectorRejection(0); - fInverse(1,1) = vectorRejection(1); - fInverse(2,1) = vectorRejection(2); - fInverse(0,2) = perpVector(0); - fInverse(1,2) = perpVector(1); - fInverse(2,2) = perpVector(2); - - Eigen::Matrix3d G; - G(0,0) = cosTheta; - G(0,1) = -sinTheta; - G(0,2) = 0; - G(1,0) = sinTheta; - G(1,1) = cosTheta; - G(1,2) = 0; - G(2,0) = 0; - G(2,1) = 0; - G(2,2) = 1; - - Eigen::Matrix3d globalRotation = fInverse * G * (fInverse.inverse()); - - if(localVerbosity > 2) - { - std::cout<< " global rotation: "<< std::endl << globalRotation < q = gamma*beta*alpha; - Eigen::Matrix3d millepedeRotation = q.matrix(); - - // Create ideal rotation matrix from ActsGeometry - Eigen::Matrix3d globalRotation = AlignmentTransformation::rotateToGlobal(surf); - Eigen::Matrix3d combinedRotation = globalRotation * millepedeRotation; - Eigen::Vector3d sensorCenter = surf->center(m_tGeometry->geometry().getGeoContext());//*0.1; - Eigen::Vector3d globalTranslation = sensorCenter + millepedeTranslation; - Acts::Transform3 transformation = AlignmentTransformation::makeAffineMatrix(combinedRotation,globalTranslation); - - if(localVerbosity > 2) - { - std::cout << "makeTransform:" << std::endl; - std::cout << "sensor center: " << std::endl << sensorCenter << std::endl << " millepede translation: " << std::endl << millepedeTranslation <(topNode, "ActsGeometry"); diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index a4de66fd93..bb61bee929 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -122,18 +122,10 @@ void setTPCParams(double tpcDevs[6]) int localVerbosity = 0; - int use_global_millepede_translations = 0; - bool use_new_transforms = true; + bool use_global_millepede_translations = true; - Acts::Transform3 makeTransform(Surface surf, Eigen::Vector3d millepedeTranslation, Eigen::Vector3d sensorAngles); Acts::Transform3 newMakeTransform(Surface surf, Eigen::Vector3d millepedeTranslation, Eigen::Vector3d sensorAngles); - Acts::Transform3 makeAffineMatrix(Eigen::Matrix3d rotationMatrix, Eigen::Vector3d translationVector); - - Eigen::Matrix3d modifyRotationConvention(Eigen::Matrix3d rotationMatrix); - - Eigen::Matrix3d rotateToGlobal(Surface surf); - alignmentTransformationContainer* transformMap = NULL; ActsGeometry* m_tGeometry = NULL; From 3843064cbfaf7bd0b03d76ef8b4cb93d43588b40 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 24 Apr 2023 15:12:49 -0400 Subject: [PATCH 282/468] iwyu to trigger jenkins --- offline/database/sphenixnpc/sphenixnpc.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index ed7a82bc2d..c42b1450cc 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -1,5 +1,11 @@ #include "sphenixnpc.h" +#include + +#include +#include +#include + sphenixnpc *sphenixnpc::__instance = nullptr; sphenixnpc *sphenixnpc::instance(const std::string &globaltag) From cadbdadd6277cb64b5fb87bd0fe53f6e5179f5be Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 24 Apr 2023 19:49:42 -0400 Subject: [PATCH 283/468] Dummy commit to trigger Jenkins. --- offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 3d0ec936cf..332042931a 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -730,6 +730,7 @@ void HelicalFitter::getLocalDerivativesXY(Surface surf, Acts::Vector3 global, co std::cout << " intersection_delta " << intersection_delta(0) << " " << intersection_delta(1) << " " << intersection_delta(2) << std::endl; } + // convert to delta-intersection / delta-parameter intersection_delta /= fitpars_delta[ip]; From c2465b7737c871b0a69f3d6be64c2b72552ef48e Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Tue, 25 Apr 2023 00:11:12 -0400 Subject: [PATCH 284/468] Remove unused variables. --- offline/packages/TrackerMillepedeAlignment/HelicalFitter.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index efd2e343d6..f42cbd81f1 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -118,9 +118,6 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface ClusterErrorPara _ClusErrPara; - float sensorAngles[3] = {0.01, 0.01, 0.01}; // perturbation values for each alignment angle - float sensorTransl[3] = {0.5, 0.5, 0.5}; // perturbation values for each translation direction (mm) - std::set fixed_layers; std::set> fixed_layer_params; From 7afbedfb2fe3e21ce11989d1eeb00dac9dcb1316 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 25 Apr 2023 14:59:20 -0400 Subject: [PATCH 285/468] Calculate global derivatives manually --- .../packages/trackreco/ActsAlignmentStates.cc | 221 ++++++++---------- .../packages/trackreco/ActsAlignmentStates.h | 4 +- 2 files changed, 105 insertions(+), 120 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index aa8b484e5a..a28712a4fd 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -57,30 +57,27 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, const auto& surface = state.referenceSurface(); const auto& sl = static_cast(state.uncalibrated()); auto ckey = sl.cluskey(); - Acts::Vector2 loc = Acts::Vector2::Zero(); - + Acts::Vector2 localMeas = Acts::Vector2::Zero(); + /// get the local measurement that acts used std::visit([&](const auto& meas) { - std::cout << meas.parameters() << std::endl; - std::cout << meas.parameters().rows() << ", " << meas.parameters().cols() << std::endl; - std::cout << meas.parameters()[0] << ", " << meas.parameters()[1] << std::endl; - loc(0) = meas.parameters()[0]; - loc(1) = meas.parameters()[1]; + localMeas(0) = meas.parameters()[0]; + localMeas(1) = meas.parameters()[1]; }, measurements[sl.index()]); if (m_verbosity > 2) { std::cout << "sl index and ckey " << sl.index() << ", " - << sl.cluskey() << std::endl; + << sl.cluskey() << " with local position " + << localMeas.transpose() << std::endl; } auto clus = m_clusterMap->findCluster(ckey); const auto trkrId = TrkrDefs::getTrkrId(ckey); - - /// Gets the global parameters from the state - const Acts::FreeVector freeParams = - Acts::MultiTrajectoryHelpers::freeSmoothed(m_tGeometry->geometry().getGeoContext(), state); - /// Calculate the residual in global coordinates + const Acts::Vector2 localState = state.effectiveProjector() * state.smoothed(); + /// Local residual between measurement and smoothed Acts state + const Acts::Vector2 localResidual = localMeas - localState; + Acts::Vector3 clusGlobal = m_tGeometry->getGlobalPosition(ckey, clus); if (trkrId == TrkrDefs::tpcId) { @@ -92,19 +89,18 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, const Acts::FreeVector globalStateParams = Acts::detail::transformBoundToFreeParameters(surface, m_tGeometry->geometry().getGeoContext(), state.smoothed()); Acts::Vector3 stateGlobal = globalStateParams.segment<3>(Acts::eFreePos0); - Acts::Vector3 globalResidual = clusGlobal - stateGlobal; - + Acts::Vector3 clus_sigma(0, 0, 0); - if (m_clusterVersion != 4) + if (m_clusterVersion != 4) { clus_sigma(2) = clus->getZError() * Acts::UnitConstants::cm; clus_sigma(0) = clus->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; clus_sigma(1) = clus->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; } - else + else { - double clusRadius = sqrt(clusGlobal(0) * clusGlobal(0) + clusGlobal(1) * clusGlobal(1)); + double clusRadius = sqrt(clusGlobal(0) * clusGlobal(0) + clusGlobal(1) * clusGlobal(1)) / Acts::UnitConstants::cm; auto para_errors = m_clusErrPara.get_simple_cluster_error(clus, clusRadius, ckey); float exy2 = para_errors.first * Acts::UnitConstants::cm2; float ez2 = para_errors.second * Acts::UnitConstants::cm2; @@ -113,122 +109,53 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, clus_sigma(1) = sqrt(exy2 / 2.0); } - const Acts::ActsDynamicMatrix H = state.effectiveProjector(); - /// Acts residual, in local coordinates - - auto localResidual = loc - H * state.smoothed(); - + if (m_verbosity > 2) { - std::cout << "clus global is " << clusGlobal.transpose() << std::endl - << "state global is " << stateGlobal.transpose() << std::endl - << "Residual is " << globalResidual.transpose() << std::endl; + << "state global is " << stateGlobal.transpose() << std::endl; std::cout << " clus errors are " << clus_sigma.transpose() << std::endl; - std::cout << " clus loc is " << loc.transpose() << std::endl; - std::cout << " state loc is " << (H * state.smoothed()).transpose() << std::endl; + std::cout << " clus loc is " << localMeas.transpose() << std::endl; + std::cout << " state loc is " << localState << std::endl; std::cout << " local residual is " << localResidual.transpose() << std::endl; } // Get the derivative of alignment (global) parameters w.r.t. measurement or residual - const Acts::Vector3 direction = freeParams.segment<3>(Acts::eFreeDir0); - // The derivative of free parameters w.r.t. path length. @note Here, we - // assumes a linear track model, i.e. negecting the change of track - // direction. Otherwise, we need to know the magnetic field at the free - // parameters - Acts::FreeVector pathDerivative = Acts::FreeVector::Zero(); - pathDerivative.head<3>() = direction; - - - // Get the derivative of bound parameters wrt alignment parameters - Acts::AlignmentToBoundMatrix d = - surface.alignmentToBoundDerivative(m_tGeometry->geometry().getGeoContext(), freeParams, pathDerivative); - // Get the derivative of bound parameters wrt track parameters - Acts::FreeToBoundMatrix j = surface.freeToBoundJacobian(m_tGeometry->geometry().getGeoContext(), freeParams); - - // derivative of residual wrt track parameters - auto dLocResTrackActs = -H * j; - // derivative of residual wrt alignment parameters - auto dLocResAlignment = -H * d; - - if (m_verbosity > 3) - { - std::cout << "free to bound jacobian " << std::endl - << j << std::endl; - std::cout << " derivative of resiudal wrt track params " << std::endl - << dLocResTrackActs << std::endl - << " derivative of residual wrt alignment params " << std::endl - << dLocResAlignment << std::endl; - } + /// The local bound parameters still have access to global phi/theta + double phi = state.smoothed()[Acts::eBoundPhi]; + double theta = state.smoothed()[Acts::eBoundTheta]; + const Acts::Vector3 tangent = Acts::makeDirectionUnitFromPhiTheta(phi,theta); + if(m_verbosity > 2) + { + std::cout << "tangent vector to track state is " << tangent.transpose() << std::endl; + } - /// The above matrices are in Acts local coordinates, so we need to convert them to - /// global coordinates with a rotation d(l0,l1)/d(x,y,z) - - const double cosTheta = direction.z(); - const double sinTheta = std::sqrt(square(direction.x()) + square(direction.y())); - const double invSinTheta = 1. / sinTheta; - const double cosPhi = direction.x() * invSinTheta; - const double sinPhi = direction.y() * invSinTheta; - Acts::ActsMatrix<3, 2> rot = Acts::ActsMatrix<3, 2>::Zero(); - rot(0, 0) = -sinPhi; - rot(0, 1) = -cosPhi * cosTheta; - rot(1, 0) = cosPhi; - rot(1, 1) = -sinPhi * cosTheta; - rot(2, 1) = sinTheta; - - /// this is a 3x6 matrix now of d(x_res,y_res,z_res)/d(dx,dy,dz,alpha,beta,gamma) - const auto dGlobResAlignment = rot * dLocResAlignment; - - /// Acts global coordinates are (x,y,z,t,hatx,haty,hatz,q/p) - /// So now rotate to x,y,z, px,py,pz - const double p = 1. / abs(globalStateParams[Acts::eFreeQOverP]); - const double p2 = square(p); - Acts::ActsMatrix<6, 8> sphenixRot = Acts::ActsMatrix<6, 8>::Zero(); - sphenixRot(0, 0) = 1; - sphenixRot(1, 1) = 1; - sphenixRot(2, 2) = 1; - sphenixRot(3, 4) = p; - sphenixRot(4, 5) = p; - sphenixRot(5, 6) = p; - sphenixRot(3, 7) = direction.x() * p2; - sphenixRot(4, 7) = direction.y() * p2; - sphenixRot(5, 7) = direction.z() * p2; - - const auto dLocResTrack = dLocResTrackActs * sphenixRot.transpose(); - - if (m_verbosity > 3) - { - std::cout << "derivative of residual wrt alignment parameters glob " << std::endl - << dGlobResAlignment << std::endl; - std::cout << "derivative of residual wrt track parameters glob " << std::endl - << dLocResTrack << std::endl; - } + std::pair projxy = + get_projectionXY(surface, tangent); - SvtxAlignmentState::LocalMatrix aligncalc = SvtxAlignmentState::LocalMatrix::Zero(); - aligncalc(0,0) = -1; - aligncalc(0,1) = 0; - aligncalc(0,2) = 0.; + Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); + Acts::Vector3 OM = stateGlobal - sensorCenter; + if(m_verbosity > 2) + { + std::cout << " global deriv calcs" << std::endl + << "stateGlobal: " << stateGlobal.transpose() + << ", sensor center " << sensorCenter.transpose() << std::endl + << ", OM " << OM.transpose() << std::endl << " projxy " + << projxy.first.transpose() << ", " + << projxy.second.transpose() << std::endl; + } auto svtxstate = std::make_unique(); svtxstate->set_residual(localResidual); - svtxstate->set_local_derivative_matrix(dLocResTrack); - svtxstate->set_global_derivative_matrix(dLocResAlignment); + //svtxstate->set_local_derivative_matrix(dLocResTrack); + svtxstate->set_global_derivative_matrix(makeGlobalDerivatives(OM, projxy)); svtxstate->set_cluster_key(ckey); - - if(m_analytic) - { - /* - auto surf = m_tGeometry->maps().getSurface(ckey, clus); - auto anglederivs = getDerivativesAlignmentAngles(clusGlobal, ckey, - clus, surf, - crossing); - SvtxAlignmentState::GlobalMatrix analytic = SvtxAlignmentState::GlobalMatrix::Zero(); - - getGlobalDerivatives(anglederivs,analytic); - svtxstate->set_global_derivative_matrix(analytic); - */ - } + auto somematrix = surface.localCartesianToBoundLocalDerivative( + m_tGeometry->geometry().getGeoContext(), stateGlobal); + std::cout << "localcartesiantoboundlocalderiv " << std::endl + << somematrix << std::endl; + statevec.push_back(svtxstate.release()); return true; }); @@ -244,6 +171,62 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, return; } +SvtxAlignmentState::GlobalMatrix +ActsAlignmentStates::makeGlobalDerivatives(const Acts::Vector3& OM, + const std::pair& projxy) +{ + SvtxAlignmentState::GlobalMatrix globalder = SvtxAlignmentState::GlobalMatrix::Zero(); + Acts::SymMatrix3 unit = Acts::SymMatrix3::Identity(); + + //! x residual rotations + globalder(0,0) = ((unit.col(0)).cross(OM)).dot(projxy.first); + globalder(0,1) = ((unit.col(1)).cross(OM)).dot(projxy.first); + globalder(0,2) = ((unit.col(2)).cross(OM)).dot(projxy.first); + //! x residual translations + globalder(0,3) = unit.col(0).dot(projxy.first); + globalder(0,4) = unit.col(1).dot(projxy.first); + globalder(0,5) = unit.col(2).dot(projxy.first); + + //! y residual rotations + globalder(1,0) = ((unit.col(0)).cross(OM)).dot(projxy.second); + globalder(1,1) = ((unit.col(1)).cross(OM)).dot(projxy.second); + globalder(1,2) = ((unit.col(2)).cross(OM)).dot(projxy.second); + //! y residual translations + globalder(1,3) = unit.col(0).dot(projxy.second); + globalder(1,4) = unit.col(1).dot(projxy.second); + globalder(1,5) = unit.col(2).dot(projxy.second); + + return globalder; + +} + +std::pair ActsAlignmentStates::get_projectionXY(const Acts::Surface& surface, const Acts::Vector3& tangent) +{ + Acts::Vector3 projx = Acts::Vector3::Zero(); + Acts::Vector3 projy = Acts::Vector3::Zero(); + + // get the plane of the surface + Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); + // sensorNormal is the Z vector + Acts::Vector3 Z = -surface.normal(m_tGeometry->geometry().getGeoContext()); + + // get surface X and Y unit vectors in global frame + // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 + Acts::Vector3 xloc(1.0,0.0,0.0); + Acts::Vector3 xglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * xloc; + + Acts::Vector3 yloc(0.0,1.0,0.0); + Acts::Vector3 yglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * yloc; + + Acts::Vector3 X = (xglob-sensorCenter) / (xglob-sensorCenter).norm(); + Acts::Vector3 Y = (yglob-sensorCenter) / (yglob-sensorCenter).norm(); + + projx = X - (tangent.dot(X) / tangent.dot(Z)) * Z; + projy = Y - (tangent.dot(Y) / tangent.dot(Z)) * Z; + + return std::make_pair(projx, projy); +} + void ActsAlignmentStates::getGlobalDerivatives(std::vector& anglederivs, SvtxAlignmentState::GlobalMatrix& analytic) { analytic(0,0) = 1; diff --git a/offline/packages/trackreco/ActsAlignmentStates.h b/offline/packages/trackreco/ActsAlignmentStates.h index d4eb6dc930..2504903f31 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.h +++ b/offline/packages/trackreco/ActsAlignmentStates.h @@ -56,7 +56,9 @@ class ActsAlignmentStates void getGlobalDerivatives(std::vector& anglederivs, SvtxAlignmentState::GlobalMatrix& analytic); Acts::Transform3 makePerturbationTransformation(Acts::Vector3 angles); float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); - + std::pair get_projectionXY(const Acts::Surface& surface, const Acts::Vector3& tangent); + SvtxAlignmentState::GlobalMatrix makeGlobalDerivatives(const Acts::Vector3& OM, const std::pair& projxy); + bool m_analytic = true; int m_verbosity = 0; int m_clusterVersion = 4; From b596c0140be4458d3bf1858d7445f320bcc187b7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 25 Apr 2023 17:40:30 -0400 Subject: [PATCH 286/468] Update CaloWaveformProcessing.cc I don't think anybody wants yet another meaningless printout where we do not know where it comes from --- offline/packages/CaloReco/CaloWaveformProcessing.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 646fb6f63d..4b6ecc47d0 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -25,7 +25,7 @@ void CaloWaveformProcessing::initialize_processing() if (_bdosoftwarezerosuppression == true) { - std::cout << "hey zero suppression is on! " << std::endl; + //std::cout << "hey zero suppression is on! " << std::endl; m_Fitter->set_softwarezerosuppression(_bdosoftwarezerosuppression,_nsoftwarezerosuppression); } } From 089a854787d1ed95679ab9e7becc01d58dd94912 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 25 Apr 2023 22:34:40 -0400 Subject: [PATCH 287/468] testing local derivative calculations --- .../packages/trackreco/ActsAlignmentStates.cc | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index a28712a4fd..1ab1beca72 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -1,4 +1,5 @@ #include "ActsAlignmentStates.h" +#include "ActsPropagator.h" #include #include @@ -43,8 +44,16 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, const auto& tips = traj.tips(); const auto& trackTip = tips.front(); const auto crossing = track->get_silicon_seed()->get_crossing(); - SvtxAlignmentStateMap::StateVec statevec; + /// trajectory (helix) paramters + const auto& params = traj.trackParameters(trackTip); + const auto boundparams = params.parameters(); + + ActsPropagator propagator(m_tGeometry); + + SvtxAlignmentStateMap::StateVec statevec; + if(m_verbosity > 2) std::cout << "Beginning alignment state creation for track " << track->get_id() << std::endl; + std::vector indices {Acts::eBoundLoc0, Acts::eBoundLoc1, Acts::eBoundPhi, Acts::eBoundTheta, Acts::eBoundQOverP, Acts::eBoundTime}; mj.visitBackwards(trackTip, [&](const auto& state) { /// Collect only track states which were used in smoothing of KF and are measurements @@ -53,7 +62,7 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, { return true; } - + const auto& surface = state.referenceSurface(); const auto& sl = static_cast(state.uncalibrated()); auto ckey = sl.cluskey(); @@ -145,20 +154,63 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, << projxy.second.transpose() << std::endl; } + //! this is the derivative of the state wrt to Acts track parameters + //! e.g. (d_0, z_0, phi, theta, q/p, t) + + auto localDeriv = -state.effectiveProjector() * state.jacobian(); + if(m_verbosity > 2) + { + std::cout << "local deriv " << std::endl << localDeriv << std::endl; + std::cout << "local deriv rows cols " << localDeriv.rows() << ", " << localDeriv.cols() << std::endl; + } + + SvtxAlignmentState::LocalMatrix locDerivCalc = SvtxAlignmentState::LocalMatrix::Zero(); + for(int nloc = 0; nloc < SvtxAlignmentState::NLOC; nloc++) + { + Acts::BoundVector newparam; + for(auto index : indices) + { + newparam[index] = boundparams[index]; + if(index == nloc) newparam[index ] = boundparams[index]+0.1; + } + const Acts::BoundTrackParameters newparams( + params.referenceSurface().getSharedPtr(), + newparam, params.charge(), params.covariance()); + propagator.verbosity(m_verbosity); + /// propagate the helix to the surface with the modified track parameters + auto result = propagator.propagateTrack(newparams, surface.getSharedPtr()); + if(result.ok()) + { + const Acts::Vector3 newStateGlob = result.value().second.position(m_tGeometry->geometry().getGeoContext()); + if(m_verbosity > 2) + { + std::cout << " kf state " << stateGlobal.transpose() + << std::endl << " new state " << newStateGlob.transpose() << std::endl; + } + Acts::Vector3 stateDiff = newStateGlob - stateGlobal; + stateDiff /= 0.1; + locDerivCalc(0, nloc) = stateDiff.dot(projxy.first); + locDerivCalc(1, nloc) = stateDiff.dot(projxy.second); + + } + } + if(m_verbosity > 2) + { + std::cout << "hand calculated local derivatives " + << std::endl << locDerivCalc << std::endl; + + } + + auto globDeriv = makeGlobalDerivatives(OM, projxy); auto svtxstate = std::make_unique(); + svtxstate->set_residual(localResidual); - //svtxstate->set_local_derivative_matrix(dLocResTrack); - svtxstate->set_global_derivative_matrix(makeGlobalDerivatives(OM, projxy)); - svtxstate->set_cluster_key(ckey); - auto somematrix = surface.localCartesianToBoundLocalDerivative( - m_tGeometry->geometry().getGeoContext(), stateGlobal); - - std::cout << "localcartesiantoboundlocalderiv " << std::endl - << somematrix << std::endl; - + svtxstate->set_local_derivative_matrix(localDeriv); + svtxstate->set_global_derivative_matrix(globDeriv); + svtxstate->set_cluster_key(ckey); + statevec.push_back(svtxstate.release()); - - return true; }); + return true; }); if (m_verbosity > 2) { From 2dfe9bc55789d7cf748b14f651183ff322251f83 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 26 Apr 2023 09:23:21 -0400 Subject: [PATCH 288/468] fix to use local --- .../MakeMilleFiles.cc | 21 +++++++++---------- .../MakeMilleFiles.h | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index 62913b94a6..336f46cc81 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -311,11 +311,12 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve // need standard deviation of measurements SvtxAlignmentState::ResidualVector clus_sigma = SvtxAlignmentState::ResidualVector::Zero(); + if (_cluster_version == 3) { - clus_sigma(2) = cluster->getZError() * Acts::UnitConstants::cm; - clus_sigma(0) = cluster->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; - clus_sigma(1) = cluster->getRPhiError() / sqrt(2) * Acts::UnitConstants::cm; + clus_sigma(1) = cluster->getZError() * Acts::UnitConstants::cm; + clus_sigma(0) = cluster->getRPhiError() * Acts::UnitConstants::cm; + } else if (_cluster_version == 4) { @@ -323,9 +324,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve auto para_errors = _ClusErrPara.get_simple_cluster_error(cluster, clusRadius, ckey); float exy2 = para_errors.first * Acts::UnitConstants::cm2; float ez2 = para_errors.second * Acts::UnitConstants::cm2; - clus_sigma(2) = sqrt(ez2); - clus_sigma(0) = sqrt(exy2 / 2.0); - clus_sigma(1) = sqrt(exy2 / 2.0); + clus_sigma(1) = sqrt(ez2); + clus_sigma(0) = sqrt(exy2); } else if(_cluster_version == 5) { @@ -334,9 +334,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,ckey); double phierror = sqrt(para_errors.first); double zerror = sqrt(para_errors.second); - clus_sigma(2) = zerror; - clus_sigma(0) = phierror/ sqrt(2); - clus_sigma(1) = phierror/ sqrt(2); + clus_sigma(1) = zerror; + clus_sigma(0) = phierror; } if (std::isnan(clus_sigma(0)) || @@ -364,7 +363,7 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve std::cout << std::endl; } - /// For N residual coordinates x,y,z + /// For N residual local coordinates x, z for (int i = 0; i < SvtxAlignmentState::NRES; ++i) { // Add the measurement separately for each coordinate direction to Mille @@ -419,7 +418,7 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve return; } -void MakeMilleFiles::printBuffers(int index, Acts::Vector3 residual, Acts::Vector3 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) +void MakeMilleFiles::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) { std::cout << " float buffer: " << " residual " << " " << residual(index); for (int il=0;il Date: Wed, 26 Apr 2023 09:23:31 -0400 Subject: [PATCH 289/468] Remove cross check code --- .../packages/trackreco/ActsAlignmentStates.cc | 58 ++++--------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index 1ab1beca72..8d4924da43 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -45,14 +45,15 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, const auto& trackTip = tips.front(); const auto crossing = track->get_silicon_seed()->get_crossing(); - /// trajectory (helix) paramters - const auto& params = traj.trackParameters(trackTip); - const auto boundparams = params.parameters(); - ActsPropagator propagator(m_tGeometry); SvtxAlignmentStateMap::StateVec statevec; - if(m_verbosity > 2) std::cout << "Beginning alignment state creation for track " << track->get_id() << std::endl; + if(m_verbosity > 2) + { + std::cout << "Beginning alignment state creation for track " + << track->get_id() << std::endl; + } + std::vector indices {Acts::eBoundLoc0, Acts::eBoundLoc1, Acts::eBoundPhi, Acts::eBoundTheta, Acts::eBoundQOverP, Acts::eBoundTime}; mj.visitBackwards(trackTip, [&](const auto& state) { @@ -156,50 +157,11 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, //! this is the derivative of the state wrt to Acts track parameters //! e.g. (d_0, z_0, phi, theta, q/p, t) - - auto localDeriv = -state.effectiveProjector() * state.jacobian(); + auto localDeriv = state.effectiveProjector() * state.jacobian(); if(m_verbosity > 2) { std::cout << "local deriv " << std::endl << localDeriv << std::endl; - std::cout << "local deriv rows cols " << localDeriv.rows() << ", " << localDeriv.cols() << std::endl; - } - - SvtxAlignmentState::LocalMatrix locDerivCalc = SvtxAlignmentState::LocalMatrix::Zero(); - for(int nloc = 0; nloc < SvtxAlignmentState::NLOC; nloc++) - { - Acts::BoundVector newparam; - for(auto index : indices) - { - newparam[index] = boundparams[index]; - if(index == nloc) newparam[index ] = boundparams[index]+0.1; - } - const Acts::BoundTrackParameters newparams( - params.referenceSurface().getSharedPtr(), - newparam, params.charge(), params.covariance()); - propagator.verbosity(m_verbosity); - /// propagate the helix to the surface with the modified track parameters - auto result = propagator.propagateTrack(newparams, surface.getSharedPtr()); - if(result.ok()) - { - const Acts::Vector3 newStateGlob = result.value().second.position(m_tGeometry->geometry().getGeoContext()); - if(m_verbosity > 2) - { - std::cout << " kf state " << stateGlobal.transpose() - << std::endl << " new state " << newStateGlob.transpose() << std::endl; - } - Acts::Vector3 stateDiff = newStateGlob - stateGlobal; - stateDiff /= 0.1; - locDerivCalc(0, nloc) = stateDiff.dot(projxy.first); - locDerivCalc(1, nloc) = stateDiff.dot(projxy.second); - - } - } - if(m_verbosity > 2) - { - std::cout << "hand calculated local derivatives " - << std::endl << locDerivCalc << std::endl; - - } + } auto globDeriv = makeGlobalDerivatives(OM, projxy); auto svtxstate = std::make_unique(); @@ -207,10 +169,10 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, svtxstate->set_residual(localResidual); svtxstate->set_local_derivative_matrix(localDeriv); svtxstate->set_global_derivative_matrix(globDeriv); - svtxstate->set_cluster_key(ckey); + svtxstate->set_cluster_key(ckey); statevec.push_back(svtxstate.release()); - return true; }); + return true; }); if (m_verbosity > 2) { From 90c040ce8872f4525d5223069926cf4ed3e09f7f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 26 Apr 2023 12:19:31 -0400 Subject: [PATCH 290/468] cross checked with helical fitter --- offline/packages/trackreco/ActsAlignmentStates.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index 8d4924da43..40d3b6c1bc 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -134,7 +134,11 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, /// The local bound parameters still have access to global phi/theta double phi = state.smoothed()[Acts::eBoundPhi]; double theta = state.smoothed()[Acts::eBoundTheta]; - const Acts::Vector3 tangent = Acts::makeDirectionUnitFromPhiTheta(phi,theta); + Acts::Vector3 tangent = Acts::makeDirectionUnitFromPhiTheta(phi,theta); + //! charge for phi is switched in Acts + tangent(0) *= -1; + tangent(1) *= -1; + if(m_verbosity > 2) { std::cout << "tangent vector to track state is " << tangent.transpose() << std::endl; @@ -145,6 +149,9 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); Acts::Vector3 OM = stateGlobal - sensorCenter; + + auto globDeriv = makeGlobalDerivatives(OM, projxy); + if(m_verbosity > 2) { std::cout << " global deriv calcs" << std::endl @@ -152,7 +159,8 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, << ", sensor center " << sensorCenter.transpose() << std::endl << ", OM " << OM.transpose() << std::endl << " projxy " << projxy.first.transpose() << ", " - << projxy.second.transpose() << std::endl; + << projxy.second.transpose() << std::endl + << "global derivatives " << std::endl << globDeriv << std::endl; } //! this is the derivative of the state wrt to Acts track parameters @@ -163,7 +171,6 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, std::cout << "local deriv " << std::endl << localDeriv << std::endl; } - auto globDeriv = makeGlobalDerivatives(OM, projxy); auto svtxstate = std::make_unique(); svtxstate->set_residual(localResidual); @@ -223,7 +230,7 @@ std::pair ActsAlignmentStates::get_projectionXY(co Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); // sensorNormal is the Z vector Acts::Vector3 Z = -surface.normal(m_tGeometry->geometry().getGeoContext()); - + // get surface X and Y unit vectors in global frame // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 Acts::Vector3 xloc(1.0,0.0,0.0); From 8e5462d5676f1af6c2c66733d522a4beb349a63e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 26 Apr 2023 13:43:38 -0400 Subject: [PATCH 291/468] clang-format and remove unused code --- .../MakeMilleFiles.cc | 102 +++++---- .../packages/trackreco/ActsAlignmentStates.cc | 214 +++--------------- .../packages/trackreco/ActsAlignmentStates.h | 15 +- 3 files changed, 96 insertions(+), 235 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index 336f46cc81..cafd1668c3 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -79,13 +79,12 @@ int MakeMilleFiles::process_event(PHCompositeNode* /*topNode*/) { // Outline: // - // loop over tracks + // loop over track alignment states // Make any track cuts here to skip undesirable tracks (maybe low pT?) // loop over track states+measurements for each track - // for each measurement - // Get measurement value and error (global, what to use for error?) + // for each measurement, performed in trackreco/ActsAlignmentStates.cc + // Get measurement value and error // Calculate derivatives and residuals from Acts jacobians - // Rotate residual-derivative matrices to global coordinates // These are stored in a map and unpacked for mille // Call _mille->mille() with arguments obtained from previous iteration: // local pars @@ -100,20 +99,19 @@ int MakeMilleFiles::process_event(PHCompositeNode* /*topNode*/) // Note: all units are in the Acts units of mm and GeV to avoid converting matrices if (Verbosity() > 0) - { - std::cout << PHWHERE << " track map size " << _track_map->size() << std::endl; - std::cout << "state map size " << _state_map->size() << std::endl; - } + { + std::cout << PHWHERE << " track map size " << _track_map->size() << std::endl; + std::cout << "state map size " << _state_map->size() << std::endl; + } for (auto [key, statevec] : *_state_map) { - // Check if track was removed from cleaner auto iter = _track_map->find(key); - if(iter == _track_map->end()) - { - continue; - } + if (iter == _track_map->end()) + { + continue; + } SvtxTrack* track = iter->second; @@ -133,10 +131,10 @@ int MakeMilleFiles::process_event(PHCompositeNode* /*topNode*/) _mille->end(); } - if(Verbosity() > 0 ) - { - std::cout << "Finished processing mille file " << std::endl; - } + if (Verbosity() > 0) + { + std::cout << "Finished processing mille file " << std::endl; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -303,20 +301,19 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve // The global alignment parameters are given initial values of zero by default, we do not specify them // We identify the global alignment parameters for this surface - const auto cluster = _cluster_map->findCluster(ckey); - const auto layer = TrkrDefs::getLayer(ckey); + TrkrCluster* cluster = _cluster_map->findCluster(ckey); + const unsigned int layer = TrkrDefs::getLayer(ckey); - const auto residual = state->get_residual(); - const auto& global = _tGeometry->getGlobalPosition(ckey, cluster); + const SvtxAlignmentState::ResidualVector residual = state->get_residual(); + const Acts::Vector3 global = _tGeometry->getGlobalPosition(ckey, cluster); // need standard deviation of measurements SvtxAlignmentState::ResidualVector clus_sigma = SvtxAlignmentState::ResidualVector::Zero(); - + if (_cluster_version == 3) { clus_sigma(1) = cluster->getZError() * Acts::UnitConstants::cm; clus_sigma(0) = cluster->getRPhiError() * Acts::UnitConstants::cm; - } else if (_cluster_version == 4) { @@ -327,11 +324,11 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve clus_sigma(1) = sqrt(ez2); clus_sigma(0) = sqrt(exy2); } - else if(_cluster_version == 5) + else if (_cluster_version == 5) { - double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); + double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); TrkrClusterv5* clusterv5 = dynamic_cast(cluster); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5,clusRadius,ckey); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5, clusRadius, ckey); double phierror = sqrt(para_errors.first); double zerror = sqrt(para_errors.second); clus_sigma(1) = zerror; @@ -339,8 +336,7 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve } if (std::isnan(clus_sigma(0)) || - std::isnan(clus_sigma(1)) || - std::isnan(clus_sigma(2))) + std::isnan(clus_sigma(1))) { continue; } @@ -370,8 +366,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve float glbl_derivative[SvtxAlignmentState::NGL]; for (int j = 0; j < SvtxAlignmentState::NGL; ++j) { - /// swap the order to match what is expected from the workflow - glbl_derivative[j] = state->get_global_derivative_matrix()(i, (j+3)%SvtxAlignmentState::NGL); + /// swap the order to match what is expected from the workflow + glbl_derivative[j] = state->get_global_derivative_matrix()(i, (j + 3) % SvtxAlignmentState::NGL); if (is_layer_fixed(layer) || is_layer_param_fixed(layer, j)) { @@ -404,11 +400,11 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve if (clus_sigma(i) < 1.0) // discards crazy clusters { - if(Verbosity() > 3) - { - std::cout << "ckey " << ckey << " and layer " << layer << " buffers:" << std::endl; - printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); - } + if (Verbosity() > 3) + { + std::cout << "ckey " << ckey << " and layer " << layer << " buffers:" << std::endl; + printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); + } _mille->mille(SvtxAlignmentState::NLOC, lcl_derivative, SvtxAlignmentState::NGL, glbl_derivative, glbl_label, residual(i), clus_sigma(i)); } @@ -420,15 +416,33 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve void MakeMilleFiles::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) { - std::cout << " float buffer: " << " residual " << " " << residual(index); - for (int il=0;il 2) - { - std::cout << "Beginning alignment state creation for track " - << track->get_id() << std::endl; - } + if (m_verbosity > 2) + { + std::cout << "Beginning alignment state creation for track " + << track->get_id() << std::endl; + } - std::vector indices {Acts::eBoundLoc0, Acts::eBoundLoc1, Acts::eBoundPhi, Acts::eBoundTheta, Acts::eBoundQOverP, Acts::eBoundTime}; + std::vector indices{Acts::eBoundLoc0, Acts::eBoundLoc1, Acts::eBoundPhi, Acts::eBoundTheta, Acts::eBoundQOverP, Acts::eBoundTime}; mj.visitBackwards(trackTip, [&](const auto& state) { /// Collect only track states which were used in smoothing of KF and are measurements @@ -192,55 +192,54 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, return; } -SvtxAlignmentState::GlobalMatrix -ActsAlignmentStates::makeGlobalDerivatives(const Acts::Vector3& OM, - const std::pair& projxy) +SvtxAlignmentState::GlobalMatrix +ActsAlignmentStates::makeGlobalDerivatives(const Acts::Vector3& OM, + const std::pair& projxy) { SvtxAlignmentState::GlobalMatrix globalder = SvtxAlignmentState::GlobalMatrix::Zero(); Acts::SymMatrix3 unit = Acts::SymMatrix3::Identity(); //! x residual rotations - globalder(0,0) = ((unit.col(0)).cross(OM)).dot(projxy.first); - globalder(0,1) = ((unit.col(1)).cross(OM)).dot(projxy.first); - globalder(0,2) = ((unit.col(2)).cross(OM)).dot(projxy.first); + globalder(0, 0) = ((unit.col(0)).cross(OM)).dot(projxy.first); + globalder(0, 1) = ((unit.col(1)).cross(OM)).dot(projxy.first); + globalder(0, 2) = ((unit.col(2)).cross(OM)).dot(projxy.first); //! x residual translations - globalder(0,3) = unit.col(0).dot(projxy.first); - globalder(0,4) = unit.col(1).dot(projxy.first); - globalder(0,5) = unit.col(2).dot(projxy.first); - + globalder(0, 3) = unit.col(0).dot(projxy.first); + globalder(0, 4) = unit.col(1).dot(projxy.first); + globalder(0, 5) = unit.col(2).dot(projxy.first); + //! y residual rotations - globalder(1,0) = ((unit.col(0)).cross(OM)).dot(projxy.second); - globalder(1,1) = ((unit.col(1)).cross(OM)).dot(projxy.second); - globalder(1,2) = ((unit.col(2)).cross(OM)).dot(projxy.second); + globalder(1, 0) = ((unit.col(0)).cross(OM)).dot(projxy.second); + globalder(1, 1) = ((unit.col(1)).cross(OM)).dot(projxy.second); + globalder(1, 2) = ((unit.col(2)).cross(OM)).dot(projxy.second); //! y residual translations - globalder(1,3) = unit.col(0).dot(projxy.second); - globalder(1,4) = unit.col(1).dot(projxy.second); - globalder(1,5) = unit.col(2).dot(projxy.second); - - return globalder; + globalder(1, 3) = unit.col(0).dot(projxy.second); + globalder(1, 4) = unit.col(1).dot(projxy.second); + globalder(1, 5) = unit.col(2).dot(projxy.second); + return globalder; } std::pair ActsAlignmentStates::get_projectionXY(const Acts::Surface& surface, const Acts::Vector3& tangent) { Acts::Vector3 projx = Acts::Vector3::Zero(); Acts::Vector3 projy = Acts::Vector3::Zero(); - + // get the plane of the surface - Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); + Acts::Vector3 sensorCenter = surface.center(m_tGeometry->geometry().getGeoContext()); // sensorNormal is the Z vector Acts::Vector3 Z = -surface.normal(m_tGeometry->geometry().getGeoContext()); - + // get surface X and Y unit vectors in global frame // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 - Acts::Vector3 xloc(1.0,0.0,0.0); - Acts::Vector3 xglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * xloc; + Acts::Vector3 xloc(1.0, 0.0, 0.0); + Acts::Vector3 xglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * xloc; - Acts::Vector3 yloc(0.0,1.0,0.0); - Acts::Vector3 yglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * yloc; + Acts::Vector3 yloc(0.0, 1.0, 0.0); + Acts::Vector3 yglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * yloc; - Acts::Vector3 X = (xglob-sensorCenter) / (xglob-sensorCenter).norm(); - Acts::Vector3 Y = (yglob-sensorCenter) / (yglob-sensorCenter).norm(); + Acts::Vector3 X = (xglob - sensorCenter) / (xglob - sensorCenter).norm(); + Acts::Vector3 Y = (yglob - sensorCenter) / (yglob - sensorCenter).norm(); projx = X - (tangent.dot(X) / tangent.dot(Z)) * Z; projy = Y - (tangent.dot(Y) / tangent.dot(Z)) * Z; @@ -248,23 +247,6 @@ std::pair ActsAlignmentStates::get_projectionXY(co return std::make_pair(projx, projy); } -void ActsAlignmentStates::getGlobalDerivatives(std::vector& anglederivs, SvtxAlignmentState::GlobalMatrix& analytic) -{ - analytic(0,0) = 1; - analytic(1,1) = 1; - analytic(2,2) = 1; - - for(int res = 0; res < SvtxAlignmentState::NRES; ++res) - { - for(int gl = 3; gl < SvtxAlignmentState::NGL; ++gl) - { - // this is not backwards - the angle derivs is transposed - analytic(res,gl) = anglederivs.at(gl-3)(res) * Acts::UnitConstants::cm; - } - } - -} - void ActsAlignmentStates::makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global) { // make all corrections to global position of TPC cluster @@ -286,133 +268,3 @@ void ActsAlignmentStates::makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key global = m_distortionCorrection.get_corrected_position(global, m_dcc_fluctuation); } } - -std::vector ActsAlignmentStates::getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing) -{ - // The value of global is from the geocontext transformation - // we add to that transformation a small rotation around the relevant axis in the surface frame - - std::vector derivs_vector; - - // get the transformation from the geocontext - Acts::Transform3 transform = surface->transform(m_tGeometry->geometry().getGeoContext()); - - // Make an additional transform that applies a small rotation angle in the surface frame - for (unsigned int iangle = 0; iangle < 3; ++iangle) - { - // creates transform that adds a perturbation rotation around one axis, uses it to estimate derivative wrt perturbation rotation - - unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key); - unsigned int layer = TrkrDefs::getLayer(cluster_key); - - Acts::Vector3 derivs(0, 0, 0); - Eigen::Vector3d theseAngles(0, 0, 0); - theseAngles[iangle] = sensorAngles[iangle]; // set the one we want to be non-zero - - Acts::Vector3 keeper(0, 0, 0); - for (int ip = 0; ip < 2; ++ip) - { - if (ip == 1) - { - theseAngles[iangle] *= -1; - } // test both sides of zero - - if (m_verbosity > 1) - { - std::cout << " trkrId " << trkrId << " layer " << layer << " cluster_key " << cluster_key - << " sensorAngles " << theseAngles[0] << " " << theseAngles[1] << " " << theseAngles[2] << std::endl; - } - - Acts::Transform3 perturbationTransformation = makePerturbationTransformation(theseAngles); - Acts::Transform3 overallTransformation = transform * perturbationTransformation; - - // transform the cluster local position to global coords with this additional rotation added - auto x = cluster->getLocalX() * 10; // mm - auto y = cluster->getLocalY() * 10; - if (trkrId == TrkrDefs::tpcId) - { - y = convertTimeToZ(cluster_key, cluster); - } - - Eigen::Vector3d clusterLocalPosition(x, y, 0); // follows the convention for the acts transform of local = (x,z,y) - Eigen::Vector3d finalCoords = overallTransformation * clusterLocalPosition / 10.0; // convert mm back to cm - - // have to add corrections for TPC clusters after transformation to global - if (trkrId == TrkrDefs::tpcId) - { - makeTpcGlobalCorrections(cluster_key, crossing, global); - } - - if (ip == 0) - { - keeper(0) = (finalCoords(0) - global(0)); - keeper(1) = (finalCoords(1) - global(1)); - keeper(2) = (finalCoords(2) - global(2)); - } - else - { - keeper(0) -= (finalCoords(0) - global(0)); - keeper(1) -= (finalCoords(1) - global(1)); - keeper(2) -= (finalCoords(2) - global(2)); - } - - if (m_verbosity > 1) - { - std::cout << " finalCoords(0) " << finalCoords(0) << " global(0) " << global(0) << " finalCoords(1) " << finalCoords(1) - << " global(1) " << global(1) << " finalCoords(2) " << finalCoords(2) << " global(2) " << global(2) << std::endl; - std::cout << " keeper now: keeper(0) " << keeper(0) << " keeper(1) " << keeper(1) << " keeper(2) " << keeper(2) << std::endl; - } - } - - // derivs vector contains: - // (dx/dalpha, dy/dalpha, dz/dalpha) (for iangle = 0) - // (dx/dbeta, dy/dbeta, dz/dbeta) (for iangle = 1) - // (dx/dgamma, dy/dgamma, dz/dgamma) (for iangle = 2) - - // Average the changes to get the estimate of the derivative - // Check what the sign of this should be !!!! - derivs(0) = keeper(0) / (2.0 * fabs(theseAngles[iangle])); - derivs(1) = keeper(1) / (2.0 * fabs(theseAngles[iangle])); - derivs(2) = keeper(2) / (2.0 * fabs(theseAngles[iangle])); - derivs_vector.push_back(derivs); - - if (m_verbosity > 1) - { - std::cout << " derivs(0) " << derivs(0) << " derivs(1) " << derivs(1) << " derivs(2) " << derivs(2) << std::endl; - } - } - - return derivs_vector; -} - -Acts::Transform3 ActsAlignmentStates::makePerturbationTransformation(Acts::Vector3 angles) -{ - // Note: Here beta is apllied to the z axis and gamma is applied to the y axis because the geocontext transform - // will flip those axes when transforming to global coordinates - Eigen::AngleAxisd alpha(angles(0), Eigen::Vector3d::UnitX()); - Eigen::AngleAxisd beta(angles(2), Eigen::Vector3d::UnitY()); - Eigen::AngleAxisd gamma(angles(1), Eigen::Vector3d::UnitZ()); - Eigen::Quaternion q = gamma * beta * alpha; - Eigen::Matrix3d perturbationRotation = q.matrix(); - - // combine rotation and translation into an affine matrix - Eigen::Vector3d nullTranslation(0, 0, 0); - Acts::Transform3 perturbationTransformation; - perturbationTransformation.linear() = perturbationRotation; - perturbationTransformation.translation() = nullTranslation; - - return perturbationTransformation; -} -float ActsAlignmentStates::convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) -{ - // must convert local Y from cluster average time of arival to local cluster z position - double drift_velocity = m_tGeometry->get_drift_velocity(); - double zdriftlength = cluster->getLocalY() * drift_velocity; - double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is - double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north - unsigned int side = TpcDefs::getSide(cluster_key); - if (side == 0) zloc = -zloc; - float z = zloc * 10.0; - - return z; -} diff --git a/offline/packages/trackreco/ActsAlignmentStates.h b/offline/packages/trackreco/ActsAlignmentStates.h index 2504903f31..81d232649e 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.h +++ b/offline/packages/trackreco/ActsAlignmentStates.h @@ -12,9 +12,9 @@ #include #include +#include #include #include -#include class PHCompositeNode; class SvtxTrack; @@ -35,9 +35,8 @@ class ActsAlignmentStates void clusterVersion(const int v) { m_clusterVersion = v; } void fillAlignmentStateMap(const Trajectory& traj, SvtxTrack* track, - const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); void verbosity(const int verb) { m_verbosity = verb; } - void analyticGlobalDer(bool a) { m_analytic = a; } void distortionContainers(TpcDistortionCorrectionContainer* stat, TpcDistortionCorrectionContainer* average, TpcDistortionCorrectionContainer* fluc) @@ -49,17 +48,13 @@ class ActsAlignmentStates void actsGeometry(ActsGeometry* geom) { m_tGeometry = geom; } void clusters(TrkrClusterContainer* clus) { m_clusterMap = clus; } void stateMap(SvtxAlignmentStateMap* map) { m_alignmentStateMap = map; } - + private: void makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global); - std::vector getDerivativesAlignmentAngles(Acts::Vector3& global, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster, Surface surface, int crossing); - void getGlobalDerivatives(std::vector& anglederivs, SvtxAlignmentState::GlobalMatrix& analytic); - Acts::Transform3 makePerturbationTransformation(Acts::Vector3 angles); - float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); + std::pair get_projectionXY(const Acts::Surface& surface, const Acts::Vector3& tangent); SvtxAlignmentState::GlobalMatrix makeGlobalDerivatives(const Acts::Vector3& OM, const std::pair& projxy); - - bool m_analytic = true; + int m_verbosity = 0; int m_clusterVersion = 4; From b05884ffab154484f282c8168ca2a247683988c2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 26 Apr 2023 19:03:25 -0400 Subject: [PATCH 292/468] install TowerInfoDefs online --- offline/packages/CaloBase/Makefile.am | 22 ++++++++++++++-------- offline/packages/CaloBase/TowerInfoDefs.cc | 11 ++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 9ac2dfdc90..698a87c1ac 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -4,11 +4,6 @@ AUTOMAKE_OPTIONS = foreign # List of shared libraries to produce -if USE_ONLINE -pkginclude_HEADERS = \ - TowerInfoDefs.h - -else lib_LTLIBRARIES = \ libcalo_io.la @@ -16,14 +11,25 @@ libcalo_io_la_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib -libcalo_io_la_LIBADD = \ - -lphool - AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include +# List of shared libraries to produce +if USE_ONLINE +pkginclude_HEADERS = \ + RawTowerDefs.h \ + TowerInfoDefs.h + +libcalo_io_la_SOURCES = \ + TowerInfoDefs.cc + +else + +libcalo_io_la_LIBADD = \ + -lphool + pkginclude_HEADERS = \ RawClusterUtility.h \ RawCluster.h \ diff --git a/offline/packages/CaloBase/TowerInfoDefs.cc b/offline/packages/CaloBase/TowerInfoDefs.cc index 1aa6e235c5..a5bbba15a9 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.cc +++ b/offline/packages/CaloBase/TowerInfoDefs.cc @@ -1,8 +1,8 @@ #include "TowerInfoDefs.h" #include "RawTowerDefs.h" -#include -#include + #include +#include #include #include #include @@ -271,8 +271,8 @@ unsigned int TowerInfoDefs::encode_epd (const unsigned int arm, const unsigned i { if (rbin == 0 && phibin > 11) { - std::cout << PHWHERE << " encode_epd invalid phibin value: " << phibin << " where max valid phibin is 11"<< std::endl; - gSystem->Exit(1); + std::cout << __PRETTY_FUNCTION__ << " encode_epd invalid phibin value: " << phibin << " where max valid phibin is 11"<< std::endl; + exit(1); } unsigned int sector = phibin/2; @@ -391,7 +391,7 @@ unsigned int TowerInfoDefs::encode_zdc(const unsigned int towerIndex) unsigned int Xneg[2] = {15,23}; unsigned int Yneg[2] = {22,29}; unsigned int xyBit = 0; - unsigned int fingerIndex; + unsigned int fingerIndex = UINT_MAX; unsigned int sideBit = 0; if (towerIndex >= Xpos[0] && towerIndex <= Xpos[1] ) { @@ -418,6 +418,7 @@ unsigned int TowerInfoDefs::encode_zdc(const unsigned int towerIndex) sideBit = 0; } unsigned int key = (sideBit << 4) + (xyBit << 3) + fingerIndex; +// key += (sideBit << 4) + (xyBit << 3) + fingerIndex; return key; } From 8ff3ffa8c92b0acb8592887fffe56db4438c6c48 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 24 Apr 2023 11:01:49 -0400 Subject: [PATCH 293/468] raw data calibration update --- offline/packages/micromegas/MicromegasRawDataCalibration.cc | 6 +++--- offline/packages/micromegas/MicromegasRawDataCalibration.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 90dcb787b1..5e14f6cee2 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -75,7 +75,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) * To be fixed at a later stage. * check with Martin Purschke */ - auto packet = event->getPacket(4001); + auto packet = event->getPacket(5001); if( !packet ) { // no data @@ -85,7 +85,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) // get number of datasets (also call waveforms) const auto n_waveforms = packet->iValue(0, "NR_WF" ); - if( Verbosity() ) + // if( Verbosity() ) { std::cout << "MicromegasRawDataCalibration::process_event - n_waveforms: " << n_waveforms << std::endl; } for( int i=0; iiValue( i, "CHANNEL" ); int fee = packet->iValue(i, "FEE" ); int samples = packet->iValue( i, "SAMPLES" ); - if( Verbosity() ) + // if( Verbosity() ) { std::cout << "MicromegasRawDataCalibration::process_event -" diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.h b/offline/packages/micromegas/MicromegasRawDataCalibration.h index 46b620d6ef..02e5597da6 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.h +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.h @@ -5,6 +5,7 @@ * \file MicromegasRawDataCalibration.h * \author Hugo Pereira Da Costa */ +#include "MicromegasMapping.h" #include From 372a3eed3794c16cf4ec589cabe5fdaa8aef9e38 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 26 Apr 2023 14:48:45 -0400 Subject: [PATCH 294/468] removed unused include --- offline/packages/micromegas/MicromegasRawDataCalibration.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.h b/offline/packages/micromegas/MicromegasRawDataCalibration.h index 02e5597da6..d65f3e9c4f 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.h +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.h @@ -5,8 +5,6 @@ * \file MicromegasRawDataCalibration.h * \author Hugo Pereira Da Costa */ -#include "MicromegasMapping.h" - #include #include From 1abd67347fcb0aba0d12af920be016dd4f4cb0d5 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 26 Apr 2023 14:49:05 -0400 Subject: [PATCH 295/468] map all 16 detectors in histogram output --- .../MicromegasRawDataCalibration.cc | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 5e14f6cee2..7b9dc69bea 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -6,6 +6,7 @@ #include "MicromegasRawDataCalibration.h" #include "MicromegasCalibrationData.h" #include "MicromegasDefs.h" +#include "MicromegasMapping.h" #include #include @@ -33,6 +34,8 @@ MicromegasRawDataCalibration::MicromegasRawDataCalibration( const std::string& n int MicromegasRawDataCalibration::Init(PHCompositeNode* /*topNode*/ ) { + MicromegasMapping(); + // histogram evaluation if( m_savehistograms ) create_histograms(); return Fun4AllReturnCodes::EVENT_OK; @@ -45,19 +48,28 @@ int MicromegasRawDataCalibration::InitRun(PHCompositeNode* /*topNode*/) //___________________________________________________________________________ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) { - + // map fee id to detector index in histogram using fee_map_t = std::map; fee_map_t fee_map = { - {2, 0}, - {1, 1}, - {3, 2}, - {4, 3}, - {8, 4}, - {9, 5}, - {7, 6}, - {5, 7} - }; + {5, 0}, // SEIP + {7, 1}, // SEIZ + {6, 2}, // SCOP + {8, 3}, // SCOZ + {9, 4}, // SCIP + {10, 5}, // SCIZ + {24, 6}, // SWIP + {25, 7}, // SWIZ + + {11, 8}, // NEIP + {12, 9}, // NEIZ + {19, 10}, // NCOP + {18, 11}, // NCOZ + {0, 12}, // NCIP + {1, 13}, // NCIZ + {15, 14}, // NWIP + {14, 15}, // NWIZ + }; // load relevant nodes // PRDF node From 4778cacdb54b1e15562622be23c14ae5bd28fe18 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 26 Apr 2023 14:51:53 -0400 Subject: [PATCH 296/468] added method to print final mapping --- .../packages/micromegas/MicromegasMapping.cc | 98 ++++++++++++------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index 2d56a2cfe9..77df47cac7 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -55,6 +55,26 @@ namespace return lhs.m_channel_id < rhs.m_channel_id; } + // print mapping + void print_mapping( const std::string& name, const std::array& array ) + { + int count = 0; + std::cout << "int " << name << "[" << array.size() << "] = {" << std::endl << " "; + for( size_t i =0; i < array.size(); ++i ) + { + if( i > 0 ) std::cout << ", "; + if( count == 32 ) + { + std::cout << std::endl << " "; + count = 0; + } + std::cout << array[i]; + ++count; + } + + std::cout << std::endl << "};" << std::endl; + } + } //____________________________________________________________________________________________________ @@ -238,7 +258,7 @@ void MicromegasMapping::construct_channel_mapping() {1,1,44}, {1,1,43}, {1,1,42}, {1,1,41}, {1,1,40}, {1,1,39}, {1,1,38}, {1,1,37} }}; - // map mec8 channel id (1-70) to mec8 signal id on detector as defined by audrey in z views + // map mec8 channel id (1-70) to mec8 signal id on detector as defined by audrey in z views (1-64) /* sources: * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png @@ -264,7 +284,7 @@ void MicromegasMapping::construct_channel_mapping() {70,-1} }; - // map all mec8 channel id to signal id on detector as defined by audrey in z views + // map all mec8 channel id to signal id on detector as defined by audrey in z views (1-256) /* sources: * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 @@ -293,41 +313,41 @@ void MicromegasMapping::construct_channel_mapping() // source: https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79751/MappingTPOT.xlsx std::map strip_to_signal_id_mapping_all = { - {1,1}, {2,33}, {3,2}, {4,34}, {5,3}, {6,35}, {7,4}, {8,36}, - {9,5}, {10,37}, {11,6}, {12,38}, {13,7}, {14,39}, {15,8}, {16,40}, - {17,9}, {18,41}, {19,10}, {20,42}, {21,11}, {22,43}, {23,12}, {24,44}, - {25,13}, {26,45}, {27,14}, {28,46}, {29,15}, {30,47}, {31,16}, {32,48}, - {33,17}, {34,49}, {35,18}, {36,50}, {37,19}, {38,51}, {39,20}, {40,52}, - {41,21}, {42,53}, {43,22}, {44,54}, {45,23}, {46,55}, {47,24}, {48,56}, - {49,25}, {50,57}, {51,26}, {52,58}, {53,27}, {54,59}, {55,28}, {56,60}, - {57,29}, {58,61}, {59,30}, {60,62}, {61,31}, {62,63}, {63,32}, {64,64}, - - {65,65}, {66,97}, {67,66}, {68,98}, {69,67}, {70,99}, {71,68}, {72,100}, - {73,69}, {74,101}, {75,70}, {76,102}, {77,71}, {78,103}, {79,72}, {80,104}, - {81,73}, {82,105}, {83,74}, {84,106}, {85,75}, {86,107}, {87,76}, {88,108}, - {89,77}, {90,109}, {91,78}, {92,110}, {93,79}, {94,111}, {95,80}, {96,112}, - {97,81}, {98,113}, {99,82}, {100,114}, {101,83}, {102,115}, {103,84}, {104,116}, - {105,85}, {106,117}, {107,86}, {108,118}, {109,87}, {110,119}, {111,88}, {112,120}, - {113,89}, {114,121}, {115,90}, {116,122}, {117,91}, {118,123}, {119,92}, {120,124}, - {121,93}, {122,125}, {123,94}, {124,126}, {125,95}, {126,127}, {127,96}, {128,128}, - - {129,129}, {130,161}, {131,130}, {132,162}, {133,131}, {134,163}, {135,132}, {136,164}, - {137,133}, {138,165}, {139,134}, {140,166}, {141,135}, {142,167}, {143,136}, {144,168}, - {145,137}, {146,169}, {147,138}, {148,170}, {149,139}, {150,171}, {151,140}, {152,172}, - {153,141}, {154,173}, {155,142}, {156,174}, {157,143}, {158,175}, {159,144}, {160,176}, - {161,145}, {162,177}, {163,146}, {164,178}, {165,147}, {166,179}, {167,148}, {168,180}, - {169,149}, {170,181}, {171,150}, {172,182}, {173,151}, {174,183}, {175,152}, {176,184}, - {177,153}, {178,185}, {179,154}, {180,186}, {181,155}, {182,187}, {183,156}, {184,188}, - {185,157}, {186,189}, {187,158}, {188,190}, {189,159}, {190,191}, {191,160}, {192,192}, - - {193,193}, {194,225}, {195,194}, {196,226}, {197,195}, {198,227}, {199,196}, {200,228}, - {201,197}, {202,229}, {203,198}, {204,230}, {205,199}, {206,231}, {207,200}, {208,232}, - {209,201}, {210,233}, {211,202}, {212,234}, {213,203}, {214,235}, {215,204}, {216,236}, - {217,205}, {218,237}, {219,206}, {220,238}, {221,207}, {222,239}, {223,208}, {224,240}, - {225,209}, {226,241}, {227,210}, {228,242}, {229,211}, {230,243}, {231,212}, {232,244}, - {233,213}, {234,245}, {235,214}, {236,246}, {237,215}, {238,247}, {239,216}, {240,248}, - {241,217}, {242,249}, {243,218}, {244,250}, {245,219}, {246,251}, {247,220}, {248,252}, - {249,221}, {250,253}, {251,222}, {252,254}, {253,223}, {254,255}, {255,224}, {256,256} + {1,1}, {2,33}, {3,2}, {4,34}, {5,3}, {6,35}, {7,4}, {8,36}, + {9,5}, {10,37}, {11,6}, {12,38}, {13,7}, {14,39}, {15,8}, {16,40}, + {17,9}, {18,41}, {19,10}, {20,42}, {21,11}, {22,43}, {23,12}, {24,44}, + {25,13}, {26,45}, {27,14}, {28,46}, {29,15}, {30,47}, {31,16}, {32,48}, + {33,17}, {34,49}, {35,18}, {36,50}, {37,19}, {38,51}, {39,20}, {40,52}, + {41,21}, {42,53}, {43,22}, {44,54}, {45,23}, {46,55}, {47,24}, {48,56}, + {49,25}, {50,57}, {51,26}, {52,58}, {53,27}, {54,59}, {55,28}, {56,60}, + {57,29}, {58,61}, {59,30}, {60,62}, {61,31}, {62,63}, {63,32}, {64,64}, + + {65,65}, {66,97}, {67,66}, {68,98}, {69,67}, {70,99}, {71,68}, {72,100}, + {73,69}, {74,101}, {75,70}, {76,102}, {77,71}, {78,103}, {79,72}, {80,104}, + {81,73}, {82,105}, {83,74}, {84,106}, {85,75}, {86,107}, {87,76}, {88,108}, + {89,77}, {90,109}, {91,78}, {92,110}, {93,79}, {94,111}, {95,80}, {96,112}, + {97,81}, {98,113}, {99,82}, {100,114}, {101,83}, {102,115}, {103,84}, {104,116}, + {105,85}, {106,117}, {107,86}, {108,118}, {109,87}, {110,119}, {111,88}, {112,120}, + {113,89}, {114,121}, {115,90}, {116,122}, {117,91}, {118,123}, {119,92}, {120,124}, + {121,93}, {122,125}, {123,94}, {124,126}, {125,95}, {126,127}, {127,96}, {128,128}, + + {129,129}, {130,161}, {131,130}, {132,162}, {133,131}, {134,163}, {135,132}, {136,164}, + {137,133}, {138,165}, {139,134}, {140,166}, {141,135}, {142,167}, {143,136}, {144,168}, + {145,137}, {146,169}, {147,138}, {148,170}, {149,139}, {150,171}, {151,140}, {152,172}, + {153,141}, {154,173}, {155,142}, {156,174}, {157,143}, {158,175}, {159,144}, {160,176}, + {161,145}, {162,177}, {163,146}, {164,178}, {165,147}, {166,179}, {167,148}, {168,180}, + {169,149}, {170,181}, {171,150}, {172,182}, {173,151}, {174,183}, {175,152}, {176,184}, + {177,153}, {178,185}, {179,154}, {180,186}, {181,155}, {182,187}, {183,156}, {184,188}, + {185,157}, {186,189}, {187,158}, {188,190}, {189,159}, {190,191}, {191,160}, {192,192}, + + {193,193}, {194,225}, {195,194}, {196,226}, {197,195}, {198,227}, {199,196}, {200,228}, + {201,197}, {202,229}, {203,198}, {204,230}, {205,199}, {206,231}, {207,200}, {208,232}, + {209,201}, {210,233}, {211,202}, {212,234}, {213,203}, {214,235}, {215,204}, {216,236}, + {217,205}, {218,237}, {219,206}, {220,238}, {221,207}, {222,239}, {223,208}, {224,240}, + {225,209}, {226,241}, {227,210}, {228,242}, {229,211}, {230,243}, {231,212}, {232,244}, + {233,213}, {234,245}, {235,214}, {236,246}, {237,215}, {238,247}, {239,216}, {240,248}, + {241,217}, {242,249}, {243,218}, {244,250}, {245,219}, {246,251}, {247,220}, {248,252}, + {249,221}, {250,253}, {251,222}, {252,254}, {253,223}, {254,255}, {255,224}, {256,256} }; // add mapping from strip number as defined by Audrey and geant convention @@ -366,6 +386,8 @@ void MicromegasMapping::construct_channel_mapping() m_fee_to_strip_mapping_z[channel_id] = strip_geant; } + // print_mapping( "m_fee_to_strip_mapping_z", m_fee_to_strip_mapping_z ); + // map mec8 channel id (1-70) to mec8 signal id on detector as defined by audrey in phi views /* sources: * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png @@ -452,5 +474,7 @@ void MicromegasMapping::construct_channel_mapping() // store in array m_fee_to_strip_mapping_phi[channel_id] = strip_geant; } + + // print_mapping( "m_fee_to_strip_mapping_phi", m_fee_to_strip_mapping_phi ); } From 774073923384fa30882f142d316073923ab050ca Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 27 Apr 2023 12:16:39 -0400 Subject: [PATCH 297/468] fixed phi mapping --- .../packages/micromegas/MicromegasMapping.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index 77df47cac7..d50803ae46 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -56,7 +56,7 @@ namespace } // print mapping - void print_mapping( const std::string& name, const std::array& array ) + [[maybe_unused]] void print_mapping( const std::string& name, const std::array& array ) { int count = 0; std::cout << "int " << name << "[" << array.size() << "] = {" << std::endl << " "; @@ -398,19 +398,19 @@ void MicromegasMapping::construct_channel_mapping() std::map mec8_to_signal_mapping_phi = { /* bottom row on mec8 (female) connector corresponds to top row on detector as defined by Audrey */ {1,-1}, - {3,33}, {5,34}, {7,35}, {9,36}, {11,37}, {13,38}, {15,39}, {17,40}, - {19,41}, {21,42}, {23,43}, {25,44}, {27,45}, {29,46}, {31,47}, {33,48}, + {3,64}, {5,63}, {7,62}, {9,61}, {11,60}, {13,59}, {15,58}, {17,57}, + {19,56}, {21,55}, {23,54}, {25,53}, {27,52}, {29,51}, {31,50}, {33,49}, {35,-1}, - {37,49}, {39,50}, {41,51}, {43,52}, {45,53}, {47,54}, {49,55}, {51,56}, - {53,57}, {55,58}, {57,59}, {59,60}, {61,61}, {63,62}, {65,63}, {67,64}, + {37,48}, {39,47}, {41,46}, {43,45}, {45,44}, {47,43}, {49,42}, {51,41}, + {53,40}, {55,39}, {57,38}, {59,37}, {61,36}, {63,35}, {65,34}, {67,33}, {69,-1}, /* top row on mec8 (female) connector corresponds to bottom row on detector as defined by Audrey */ {2,-1}, - {4,1}, {6,2}, {8,3}, {10,4}, {12,5}, {14,6}, {16,7}, {18,8}, - {20,9}, {22,10}, {24,11}, {26,12}, {28,13}, {30,14}, {32,15}, {34,16}, + {4,32}, {6,31}, {8,30}, {10,29}, {12,28}, {14,27}, {16,26}, {18,25}, + {20,24}, {22,23}, {24,22}, {26,21}, {28,20}, {30,19}, {32,18}, {34,17}, {36,-1}, - {38,17}, {40,18}, {42,19}, {44,20}, {46,21}, {48,22}, {50,23}, {52,24}, - {54,25}, {56,26}, {58,27}, {60,28}, {62,29}, {64,30}, {66,31}, {68,32}, + {38,16}, {40,15}, {42,14}, {44,13}, {46,12}, {48,11}, {50,10}, {52,9}, + {54,8}, {56,7}, {58,6}, {60,5}, {62,4}, {64,3}, {66,2}, {68,1}, {70,-1} }; From 7276dff7b5b86dae7f99152cf88b6556fb0cbd6e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 27 Apr 2023 12:21:40 -0400 Subject: [PATCH 298/468] updated links --- offline/packages/micromegas/MicromegasMapping.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index d50803ae46..e0efddbfc9 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -206,6 +206,7 @@ std::string MicromegasMapping::get_detname_sphenix_from_hitsetkey( TrkrDefs::hit //____________________________________________________________________________________________________ void MicromegasMapping::construct_channel_mapping() { + // procedure details: https://indico.bnl.gov/event/19349/contributions/75908/attachments/47219/80098/talk.pdf /* * map channel id on FEE board (0-255) to mec8 connector and channel @@ -310,7 +311,7 @@ void MicromegasMapping::construct_channel_mapping() } // map phisical strips in the detector to MEC8 signal id on detector as defined by Audrey - // source: https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79751/MappingTPOT.xlsx + // source: https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79824/MappingTPOT.xlsx std::map strip_to_signal_id_mapping_all = { {1,1}, {2,33}, {3,2}, {4,34}, {5,3}, {6,35}, {7,4}, {8,36}, @@ -392,7 +393,7 @@ void MicromegasMapping::construct_channel_mapping() /* sources: * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225938-XX.PNG.png * https://wiki.sphenix.bnl.gov/index.php/File:HDR-225940-XX.PNG.png - * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79823/MappingGerber.pdf * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 */ std::map mec8_to_signal_mapping_phi = { @@ -416,7 +417,7 @@ void MicromegasMapping::construct_channel_mapping() // map all mec8 channel id to signal id on detector as defined by audrey in phi views /* sources: - * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79750/MappingGerber.pdf + * https://indico.bnl.gov/event/19038/contributions/75495/attachments/47029/79823/MappingGerber.pdf * https://indico.bnl.gov/event/17391/contributions/68961/attachments/47061/79816/TpotProgress.pdf, slide 2 */ std::map mec8_to_signal_mapping_phi_all; From a093b1b2e9c54e9b248a4bea855816313f5e3c6e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 27 Apr 2023 12:24:01 -0400 Subject: [PATCH 299/468] comment printout --- offline/packages/micromegas/MicromegasRawDataCalibration.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 7b9dc69bea..060129e3bf 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -97,7 +97,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) // get number of datasets (also call waveforms) const auto n_waveforms = packet->iValue(0, "NR_WF" ); - // if( Verbosity() ) + if( Verbosity() ) { std::cout << "MicromegasRawDataCalibration::process_event - n_waveforms: " << n_waveforms << std::endl; } for( int i=0; iiValue( i, "CHANNEL" ); int fee = packet->iValue(i, "FEE" ); int samples = packet->iValue( i, "SAMPLES" ); - // if( Verbosity() ) + if( Verbosity() ) { std::cout << "MicromegasRawDataCalibration::process_event -" From f5c56e32fa7b6566e3537c80f2da7214969b2fdf Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 27 Apr 2023 12:28:34 -0400 Subject: [PATCH 300/468] moved packet id to MicromegasDefs --- offline/packages/micromegas/MicromegasDefs.h | 3 +++ offline/packages/micromegas/MicromegasRawDataCalibration.cc | 2 +- offline/packages/micromegas/MicromegasRawDataDecoder.cc | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index 65f76d6a9f..6440c7222a 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -91,6 +91,9 @@ namespace MicromegasDefs s*/ uint8_t getTileId(TrkrDefs::cluskey); + //! TPOT packet id + static constexpr unsigned int m_packet_id = 5001; + //! number of channels per fee board static constexpr int m_nchannels_fee = 256; diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 060129e3bf..f0aef020ec 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -87,7 +87,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) * To be fixed at a later stage. * check with Martin Purschke */ - auto packet = event->getPacket(5001); + auto packet = event->getPacket(MicromegasDefs::m_packet_id); if( !packet ) { // no data diff --git a/offline/packages/micromegas/MicromegasRawDataDecoder.cc b/offline/packages/micromegas/MicromegasRawDataDecoder.cc index 8d6e2d821d..40e1360077 100644 --- a/offline/packages/micromegas/MicromegasRawDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasRawDataDecoder.cc @@ -97,7 +97,7 @@ int MicromegasRawDataDecoder::process_event(PHCompositeNode *topNode) * To be fixed at a later stage. * check with Martin Purschke */ - auto packet = event->getPacket(4001); + auto packet = event->getPacket(MicromegasDefs::m_packet_id); if( !packet ) { // no data From 704bf1a9992139d4de353b71a850c28ca500c328 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 27 Apr 2023 13:02:28 -0400 Subject: [PATCH 301/468] also invert numbering direction for z view --- offline/packages/micromegas/MicromegasMapping.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index e0efddbfc9..437e15afba 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -355,10 +355,10 @@ void MicromegasMapping::construct_channel_mapping() auto get_strip_geant_z = []( int strip_audrey ) { /* - * for z views, audrey and geant strips are numbered in the same direction + * for z views, audrey and geant strips are numbered in oposite directions * geant strips start from zero - */ - return strip_audrey-1; + */ + return MicromegasDefs::m_nchannels_fee-strip_audrey; }; // construct fee channel id to strip From c024c6ab4a810c4e71f39926e13bd2cdba2e09a2 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Fri, 28 Apr 2023 10:45:52 -0400 Subject: [PATCH 302/468] Added files for hadd-ing histos and generating dag files --- .../macros/Fun4All_FillDCMap.C | 53 +++++- .../macros/add_histos_bX.py | 65 +++++++ .../fillDigitalCurrentMaps/macros/run_DS.sh | 10 ++ .../macros/run_files_AA.sh | 2 +- .../readDigitalCurrents.cc | 88 ++++++---- .../readDigitalCurrents.h | 13 +- .../scripts/generate_files_AA.py | 4 +- .../scripts/generate_files_AA_dag.py | 161 ++++++++++++++++++ .../macros/add_histos_bX.py | 2 +- .../macros/run_files_300evts_AA_MDC2.sh | 2 +- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 1 + .../g4tpc/PHG4TpcPadPlaneReadout.h | 2 +- 12 files changed, 363 insertions(+), 40 deletions(-) create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos_bX.py create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/macros/run_DS.sh create mode 100755 calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA_dag.py diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C index 3d70fe33cb..0eb99a4709 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/Fun4All_FillDCMap.C @@ -18,6 +18,44 @@ R__LOAD_LIBRARY(libreadDigitalCurrents.so) // cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libg4dst.so) +std::vector readBeamXings(); + +std::vector readBeamXings(){ + //cout << "fillSpaceChargeMaps::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << endl; + std::vector bXs; + string line; + string txt_file = "./data/timestamps_50kHz_1M.txt"; + ifstream InputFile (txt_file); + //std::map timestamps; + if (InputFile.is_open()){ + int n_line=0; + while ( getline (InputFile,line) ) + { + n_line++; + //cout << line << '\n'; + if(n_line>3){ + std::istringstream is( line ); + double n[2] = {0,0}; + int i = 0; + while( is >> n[i] ) { + i++; + } + //_timestamps[n[0]]=n[1]; + bXs.push_back(int(n[0])); + } + } + InputFile.close(); + } + return bXs; +} + +int closest(std::vector const& vec, int value) { + auto const it = std::lower_bound(vec.begin(), vec.end(), value); + if (it == vec.end()) { return -1; } + + return *it; +} + void Fun4All_FillDCMap( const int nEvents = 1000, const int eventsInFileStart = 0, const int eventsBeamCrossing = 1508071, const string &fname = "/sphenix/user/shulga/Work/IBF/macros/detectors/sPHENIX/Files/DST_G4Hits_sHijing_0-12fm_005000_006000.root", const string &foutputname = "./Files/hists_G4Hits_sHijing_0-12fm_000000_001000.root" )//DST_G4sPHENIX_1000evt.root")//G4sPHENIX.root" ) { // /sphenix/user/frawley/new_macros_april27/macros/detectors/sPHENIX/Reconstructed_DST_Hijing_50kHz_00000.root @@ -25,6 +63,18 @@ void Fun4All_FillDCMap( const int nEvents = 1000, const int eventsInFileStart = /////////////////////////////////////////// // Make the Server ////////////////////////////////////////// + std::vector bXs = readBeamXings(); + std::vector bXs_sel; + + std::vector::iterator it = std::find(bXs.begin(), bXs.end(), eventsBeamCrossing); + int index=0; + index = std::distance(bXs.begin(), it); + cout<<"Index="<registerSubsystem(dist_calc); dist_calc->SetEvtStart(eventsInFileStart); - dist_calc->SetBeamXing(eventsBeamCrossing); // Set beam crosssing bias + dist_calc->SetBeamXing(bXs_sel);// Set beam crosssing bias + //dist_calc->SetBeamXing(eventsBeamCrossing); // Set beam crosssing bias dist_calc->SetCollSyst(0); //setting pp with = 1 dist_calc->SetIBF(0.004); dist_calc->SetCCGC(1);//to use PHG4CylinderCellGeom diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos_bX.py b/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos_bX.py new file mode 100755 index 0000000000..8bda346671 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/add_histos_bX.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +from ROOT import TCanvas, TFile, TH1F,TH2F,TH3F, TF1, TGraph, gROOT +import os +import re +import glob +import sys + +gROOT.SetBatch(True) + +dirName = '/sphenix/user/shulga/Work/TpcPadPlane_phi_coresoftware/coresoftware/calibrations/tpc/fillDigitalCurrentMaps/Files/' +#bXs = [1508071, 3016509, 4524020, 6032112, 7540028, 9048092, 10556072, 12064371, 13572143, 15080178, 16588072, 18096105] +#bXs = [18096105] +h_names = []#'_h_hits','_h_R','_h_DC_E'] +for i in range(30): + h_names.append('_h_SC_ibf_{}'.format(i)) + + + +#sys.argv[0] +ib = sys.argv[1] +bX = sys.argv[2] + + +print(bX) +name = 'hist_G4Hits_sHijing_0-12fm_bX{}*'.format(bX) +outputName = './Files/Summary_hist_mdc2_UseFieldMaps_AA_event_{}_bX{}_new.root'.format(ib,bX) + +filePattern = dirName+name +files = sorted(glob.glob(filePattern)) +#print(files) +#n=0 +histos = [] +for n,file in enumerate(files): + #h=0 + f = TFile.Open(file) + print(file) + for h,h_name in enumerate(h_names): + newName=h_name+'_{}'.format(n) + if n==0: + newName=h_name + #print(h_name) + hist = f.Get(h_name).Clone(newName) + if n==0: + histos.append(hist) + if n>0: + histos[h].Add(hist) + hist.SetDirectory(0) + #h+=1 + #n+=1 + +outfile = TFile(outputName, "RECREATE") +for hist in histos: + hist.Sumw2(False) + hist.Write() +outfile.Write() +outfile.Close() + + +# Remove all the used files +for file in files : + if os.path.exists(file): + os.remove(file) + else: + print("Can not delete the file as it doesn't exist:{}",file) + diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/run_DS.sh b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_DS.sh new file mode 100755 index 0000000000..6269c3afb2 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_DS.sh @@ -0,0 +1,10 @@ +#!/usr/bin/bash +#IN_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/G4sPHENIX_NewTestGeo_NewRLimits_1evt.root" +#OUT_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/DC_G4sPHENIX_NewTestGeo_NewRLimits_1evt.root" +#IN_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/G4sPHENIX_NewTestGeo_1evt.root" +#OUT_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/DC_G4sPHENIX_NewTestGeo_1evt.root" +#IN_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/G4sPHENIX_Default_1evts.root" +#OUT_FILE="/sphenix/user/shulga/Work/TpcPadPlane_v3_coresoftware/macros/detectors/sPHENIX/Files/DC_G4sPHENIX_Default_1evt.root" +IN_FILE="DST_TRKR_HIT_sHijing_0_20fm-0000000006-000001.root" +OUT_FILE="/sphenix/user/shulga/Work/IBF/readDigitalCurrents/Files/DC_G4sPHENIX_Default_1evt.root" +root -l -b -q ./macros/Fun4All_FillDCMap.C\(1000,0,1508071,\"$IN_FILE\",\"$OUT_FILE\"\) \ No newline at end of file diff --git a/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh index 930fc3fc8b..92fefe9a81 100755 --- a/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh +++ b/calibrations/tpc/fillDigitalCurrentMaps/macros/run_files_AA.sh @@ -20,7 +20,7 @@ do foutputname="./Files/hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A"_"$B".root" ; echo $fname ; echo $foutputname ; - root -l -b -q ./macros/Fun4All_FillDCMap.C\(10,$Xstart,$bX,\"$fname\",\"$foutputname\"\) + root -l -b -q ./macros/Fun4All_FillDCMap.C\(100,$Xstart,$bX,\"$fname\",\"$foutputname\"\) done echo all done diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc index 511f5e4d77..9b51a66d9a 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.cc @@ -36,7 +36,6 @@ #include #include -double pi = 2 * acos(0.0); using namespace std; @@ -74,7 +73,7 @@ bool IsOverFrame(double r, double phi){ //find the two spokes we're between: - float sectorangle=(pi/6); + float sectorangle=(M_PI/6); float nsectors=phi/sectorangle; int nsec=floor(nsectors); float reduced_phi=phi-nsec*sectorangle; //between zero and sixty degrees. @@ -131,7 +130,7 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) 411.53, 421.70, 431.90, 442.11, 452.32, 462.52, 472.73, 482.94, 493.14, 503.35, 513.56, 523.76, 533.97, 544.18, 554.39, 564.59, 574.76, 583.67, 594.59, 605.57, 616.54, 627.51, 638.48, 649.45, 660.42, 671.39, 682.36, 693.33, 704.30, 715.27, 726.24, 737.21, 748.18, 759.11}; const int nphi = 205; - double phi_bins[nphi + 1] = { 0., 6.3083-2 * pi, 6.3401-2 * pi, 6.372-2 * pi, 6.4039-2 * pi, 6.4358-2 * pi, 6.4676-2 * pi, 6.4995-2 * pi, 6.5314-2 * pi, + double phi_bins[nphi + 1] = { 0., 6.3083-2 * M_PI, 6.3401-2 * M_PI, 6.372-2 * M_PI, 6.4039-2 * M_PI, 6.4358-2 * M_PI, 6.4676-2 * M_PI, 6.4995-2 * M_PI, 6.5314-2 * M_PI, 0.2618, 0.2937, 0.3256, 0.3574, 0.3893, 0.4212, 0.453, 0.4849, 0.5168, 0.5487, 0.5805, 0.6124, 0.6443, 0.6762, 0.7081, 0.7399, 0.7718, 0.7854, 0.8173, 0.8491, 0.881, 0.9129, 0.9448, 0.9767, 1.0085, 1.0404, 1.0723, 1.1041, 1.136, 1.1679, 1.1998, 1.2317, 1.2635, 1.2954, 1.309, 1.3409, 1.3727, 1.4046, 1.4365, 1.4684, 1.5002, 1.5321, 1.564, 1.5959, 1.6277, @@ -145,7 +144,7 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) 4.8968, 4.9287, 4.9606, 4.9742, 5.0061, 5.0379, 5.0698, 5.1017, 5.1336, 5.1654, 5.1973, 5.2292, 5.2611, 5.2929, 5.3248, 5.3567, 5.3886, 5.4204, 5.4523, 5.4842, 5.4978, 5.5297, 5.5615, 5.5934, 5.6253, 5.6572, 5.689, 5.7209, 5.7528, 5.7847, 5.8165, 5.8484, 5.8803, 5.9122, 5.944, 5.9759, 6.0078, 6.0214, 6.0533, 6.0851, 6.117, 6.1489, 6.1808, 6.2127, 6.2445, - 6.2764, 2 * pi}; + 6.2764, 2 * M_PI}; @@ -176,17 +175,29 @@ int readDigitalCurrents::Init(PHCompositeNode *topNode) _h_hits = new TH1F("_h_hits" ,"_h_hits;N, [hit]" ,1e5,0-0.5,1e5-0.5); _h_hit_XY = new TH2F("_h_hit_XY" ,"_h_hit_XY;X, [m];Y, [m]" ,4*nr,-1*rmax,rmax,4*nr,-1*rmax,rmax); - _h_SC_ibf = new TH3F("_h_SC_ibf" ,"_h_SC_ibf;#phi, [rad];R, [mm];Z, [mm]" ,nphi,phi_bins,r_bins_N ,r_bins,2*nz,z_bins); + //_h_SC_ibf = new TH3F("_h_SC_ibf" ,"_h_SC_ibf;#phi, [rad];R, [mm];Z, [mm]" ,nphi,phi_bins,r_bins_N ,r_bins,2*nz,z_bins); _h_DC_SC = new TH3F("_h_DC_SC" ,"_h_DC_SC;#phi, [rad];R, [mm];Z, [mm]" ,nphi,phi_bins,r_bins_N ,r_bins,2*nz,z_bins); _h_DC_SC_XY = new TH2F("_h_DC_SC_XY" ,"_h_DC_SC_XY;X, [mm];Y, [mm];ADC;" ,4*nr,-1*rmax,rmax,4*nr,-1*rmax,rmax); _h_DC_E = new TH2F("_h_DC_E" ,"_h_DC_E;ADC;E" ,200,-100,2e3-100,500,-100,5e3-100); + + char name[100]; + char name_ax[100]; + for (int iz = 0; iz < nFrames; iz++) + { + sprintf(name, "_h_SC_ibf_%d", iz); + sprintf(name_ax, "_h_SC_ibf_%d;#phi, [rad];R, [mm];Z, [mm]", iz); + _h_SC_ibf[iz] = new TH3F(name, name_ax, nphi, phi_bins, r_bins_N, r_bins, 2 * nz, z_bins); + + hm->registerHisto(_h_SC_ibf[iz]); + } + hm->registerHisto(_h_R ); hm->registerHisto(_h_hits ); hm->registerHisto(_h_DC_SC ); hm->registerHisto(_h_DC_SC_XY ); hm->registerHisto(_h_hit_XY ); hm->registerHisto(_h_DC_E ); - hm->registerHisto(_h_SC_ibf ); + _event_timestamp = 0; if(_fillCSVFile){ @@ -255,7 +266,7 @@ int readDigitalCurrents::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int readDigitalCurrents::process_event(PHCompositeNode *topNode) { - double bX = _beamxing; + //double bX = _beamxing; //float bX = 1508071; //double z_bias_avg = 0; //if (_fAvg==1){ @@ -340,7 +351,8 @@ int readDigitalCurrents::process_event(PHCompositeNode *topNode) int min_phiBin=1e5; int max_phiBin=-1; for(TrkrHitSet::ConstIterator hit_iter = range.first; hit_iter != range.second; ++hit_iter){ - int f_fill_ibf=0; + //int f_fill_ibf=0; + int f_fill_ibf[30] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned short phibin = TpcDefs::getPad(hit_iter->first); @@ -352,8 +364,8 @@ int readDigitalCurrents::process_event(PHCompositeNode *topNode) }else{ phi_center = layergeom_cgc->get_phicenter(phibin); } - if (phi_center<0) phi_center+=2*pi; - if(phi_centerpi/2-pi/12){ + if (phi_center<0) phi_center+=2*M_PI; + if(phi_centerM_PI/2-M_PI/12){ if(min_phiBin>phibin)min_phiBin=phibin; if(max_phiBingetEnergy(); //double z = 0; //double z_prim = -1*1e10; - double z_ibf = -1*1e10; + //double z_ibf = -1*1e10; + double z_ibf[30] = {-1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, + -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, + -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10, -1 * 1e10}; int RBin=_h_R->GetXaxis()->FindBin(radius); if((RBin>33 && RBin<50) && z>0){ @@ -392,28 +407,35 @@ int readDigitalCurrents::process_event(PHCompositeNode *topNode) } //if(!IsOverFrame(radius/mm,phi_center)){ + for (int iz = 0; iz < nFrames; iz++) + { + double bX = _beamxing[iz]; + if (_event_bunchXing <= bX) + { + if(z>=0 && z<1.055*m){ + z_ibf[iz] = 1.055 * m - (bX - _event_bunchXing) * 106 * vIon * ns; + if( z_ibf[iz]>0 && z_ibf[iz]<1.055*m){ + f_fill_ibf[iz]=1; + } + } + if(z<0 && z>-1.055*m){ + z_ibf[iz] = -1.055*m+(bX-_event_bunchXing)*106*vIon*ns; + if( z_ibf[iz]<0 && z_ibf[iz]>-1.055*m){ + f_fill_ibf[iz]=1; + } + } + } - + } if(z>=0 && z<1.055*m){ if(adc>=0)n_hits++; if(adc>=0)_h_DC_E->Fill(adc,E); - //z_prim = z-(bX-_event_bunchXing)*106*vIon*ns; - z_ibf = 1.055*m-(bX-_event_bunchXing)*106*vIon*ns; - //if(n_hits%100==0)cout<<"z_ibf = "<0 && z_ibf<1.055*m){ - f_fill_ibf=1; - } } if(z<0 && z>-1.055*m){ if(adc>=0)n_hits++; if(adc>=0)_h_DC_E->Fill(adc,E); - //z_prim = z+(bX-_event_bunchXing)*106*vIon*ns; - z_ibf = -1.055*m+(bX-_event_bunchXing)*106*vIon*ns; - if( z_ibf<0 && z_ibf>-1.055*m){ - f_fill_ibf=1; - } } //Reading IBF and Gain weights according to X-Y position @@ -429,10 +451,14 @@ int readDigitalCurrents::process_event(PHCompositeNode *topNode) float w_adc = adc*w_ibf; _h_DC_SC->Fill(phi_center,radius,z,w_adc); _h_DC_SC_XY->Fill(x,y,w_adc); - if(f_fill_ibf==1){ - _h_SC_ibf ->Fill(phi_center,radius,z_ibf,w_adc); + if(f_fill_ibf[0]==1){ + _h_R->Fill(radius); } + for (int iz = 0; iz < nFrames; iz++) + { + if (f_fill_ibf[iz] == 1)_h_SC_ibf[iz] ->Fill(phi_center,radius,z_ibf[iz],w_adc); + } //} //if(n_hits%100==0) std::cout<Sumw2( false ); _h_hit_XY ->Sumw2( false ); _h_DC_SC_XY ->Sumw2( false ); - _h_SC_ibf ->Sumw2( false ); + for (int iz = 0; iz < nFrames; iz++) + { + _h_SC_ibf[iz]->Sumw2(false); + } hm->dumpHistos(_filename, "RECREATE"); if(_fillCSVFile)myCSVFile.close(); return Fun4AllReturnCodes::EVENT_OK; @@ -499,10 +528,11 @@ void readDigitalCurrents::FillCSV(int fillCSVFile){ cout<<"Fill CSV file is set to: "< &beamXs) +{ + _beamxing = beamXs; + std::cout << "Initial BeamXing is set to: " << _beamxing[0] << std::endl; } void readDigitalCurrents::SetCollSyst(int coll_syst){ _collSyst = coll_syst; diff --git a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h index 88b7801629..e4c2b3db06 100644 --- a/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h +++ b/calibrations/tpc/fillDigitalCurrentMaps/readDigitalCurrents.h @@ -10,6 +10,8 @@ #include #include +#include // for sin, asin, cos, floor, M_PI + class Fun4AllHistoManager; class PHCompositeNode; @@ -62,7 +64,7 @@ class readDigitalCurrents : public SubsysReco void Print(const std::string &what = "ALL") const override; - void SetBeamXing(int newBeamXing); + void SetBeamXing(const std::vector &beamXs); void SetEvtStart(int newEvtStart); void FillCSV(int fillCSVFile); void SetCollSyst(int coll_syst=0); @@ -82,8 +84,8 @@ class readDigitalCurrents : public SubsysReco std::ofstream myCSVFile; private: - int _beamxing = 0; - int _evtstart = 0; + std::vector _beamxing; + int _evtstart = 0; int _fillCSVFile = 0; @@ -97,7 +99,10 @@ class readDigitalCurrents : public SubsysReco TH2* _h_DC_SC_XY = nullptr; TH2* _h_hit_XY = nullptr; TH2* _h_DC_E = nullptr; - TH3* _h_SC_ibf = nullptr; + //TH3* _h_SC_ibf = nullptr; + static const int nFrames = 30; + TH3 *_h_SC_ibf[nFrames] = {nullptr}; + float _event_timestamp = 0; float _event_bunchXing = 0; diff --git a/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py index 85f8c7782c..757dce73d0 100755 --- a/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py +++ b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA.py @@ -54,8 +54,8 @@ ff.write("#!/usr/bin/bash"+"\n"), #evt_start = [0,8,16,23,31,39,47,55,63,71,79,87] #evt_end = [9,17,24,32,40,48,56,64,72,80,88,96] -evt_start = [0,80,160,230,310,390,470,550,630,710,790,870] -evt_end = [90,170,240,320,400,480,560,640,720,800,880,960] +evt_start = [0, 75, 155, 233, 312, 392, 471, 551, 630, 712, 793, 873, 953, 1033, 1113, 1194, 1272, 1352, 1432, 1511, 1592, 1670, 1750, 1830, 1910, 1990, 2069, 2149, 2230, 2310, 2391, 2470, 2550, 2631, 2711, 2792, 2871, 2952, 3032, 3113, 3193, 3273, 3352, 3433, 3514, 3595, 3676, 3755, 3834, 3915, 3995, 4076, 4156, 4235, 4315, 4396, 4476, 4557, 4636, 4718, 4798, 4877, 4957, 5037, 5118, 5200, 5278, 5359, 5439, 5518, 5598, 5680, 5760, 5841, 5922, 6002, 6081, 6162, 6241, 6321, 6400, 6481, 6561, 6641, 6722, 6804, 6884, 6964, 7045, 7126, 7206, 7286, 7366, 7447, 7527, 7606, 7687, 7767, 7847, 7928, 8008, 8087, 8167, 8248, 8328, 8408, 8489, 8566, 8646, 8727, 8809, 8890, 8970, 9049, 9129, 9209, 9288, 9368, 9449, 9529, 9608, 9688, 9769, 9849] +evt_end = [ 170, 248, 327, 407, 486, 566, 645, 727, 808, 888, 968, 1048, 1128, 1209, 1287, 1367, 1447, 1526, 1607, 1685, 1765, 1845, 1925, 2005, 2084, 2164, 2245, 2325, 2406, 2485, 2565, 2646, 2726, 2807, 2886, 2967, 3047, 3128, 3208, 3288, 3367, 3448, 3529, 3610, 3691, 3770, 3849, 3930, 4010, 4091, 4171, 4250, 4330, 4411, 4491, 4572, 4651, 4733, 4813, 4892, 4972, 5052, 5133, 5215, 5293, 5374, 5454, 5533, 5613, 5695, 5775, 5856, 5937, 6017, 6096, 6177, 6256, 6336, 6415, 6496, 6576, 6656, 6737, 6819, 6899, 6979, 7060, 7141, 7221, 7301, 7381, 7462, 7542, 7621, 7702, 7782, 7862, 7943, 8023, 8102, 8182, 8263, 8343, 8423, 8504, 8581, 8661, 8742, 8824, 8905, 8985, 9064, 9144, 9224, 9303, 9383, 9464, 9544, 9623, 9703, 9784, 9864, 9943, 10000] evt_bX = [1508071.0, 3016509.0, 4524020.0, 6032112.0, 7540028.0, 9048092.0, 10556072.0, 12064371.0, 13572143.0, 15080178.0, 16588072.0, 18096105.0] for j, (start,end) in enumerate(zip(evt_start,evt_end)): for i in range(start,end): diff --git a/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA_dag.py b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA_dag.py new file mode 100755 index 0000000000..52c9affce2 --- /dev/null +++ b/calibrations/tpc/fillDigitalCurrentMaps/scripts/generate_files_AA_dag.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +# coding=utf-8 + +from pathlib import Path +import stat + +def chmod_px(name): + f = Path(name) + f.chmod(f.stat().st_mode | stat.S_IEXEC) + return 0 + +work_dir = "/sphenix/user/shulga/Work/TpcPadPlane_phi_coresoftware/coresoftware/calibrations/tpc/fillDigitalCurrentMaps/" +init_str = "Initialdir = "+work_dir + +introduction = [ + "# All local jobs are part of the vanilla universe.", + "Universe = vanilla", + "", + "# The requirement line specifies which machines we want to", + "# run this job on. Any arbitrary classad expression can", + "# be used.", + "#Requirements = (CPU_Speed >= 1)", + "", + "# Rank is an expression that states how to rank machines which ", + "# have already met the requirements expression. Essentially, ", + "# rank expresses preference. A higher numeric value equals better ", + "# rank. Condor will give the job the machine with the highest rank.", + "# Rank = CPU_Speed", + "", + "# Jobs by default get 1.4Gb of RAM allocated, ask for more if needed", + "# but if a job needs more than 2Gb it will not be able to run on the", + "# older nodes", + "request_memory = 7.1GB", + "", + "# If you need multiple cores you can ask for them, but the scheduling", + "# may take longer the \"larger\" a job you ask for", + "request_cpus = 1", + "", + "# This flag is used to order only one's own submitted jobs ", + "# The jobs with the highest numbers get considered for ", + "# scheduling first.", + "#Priority = 4", + "", + "# Copy all of the user's current shell environment variables ", + "# at the time of job submission.", + "#GetEnv = True", + "", + "# Used to give jobs a directory with respect to file input ", + "# and output.", + init_str, + "", + "# Input file given to the job.", + "#Input = /dev/null", + "", + "", + "# This should be the last command and tells condor to queue the", + "# job. If a number is placed after the command (i.e. Queue 15)", + "# then the job will be submitted N times. Use the $(Process)", + "# macro to make your input/output and log files unique.", + "Queue" +] + +ff= open("./run_all_AA_jobs.sh","w+") +ff.write("#!/usr/bin/bash"+"\n") +ff_all_dag= open("./run_all_AA_jobs_dag.sh","w+") +ff_all_dag.write("#!/usr/bin/bash"+"\n") +evt_start = [0, 75, 155, 233, 312, 392, 471, 551, 630, 712, 793, 873, 953, 1033, 1113, 1194, 1272, 1352, 1432, 1511, 1592, 1670, 1750, 1830, 1910, 1990, 2069, 2149, 2230, 2310, 2391, 2470, 2550, 2631, 2711, 2792, 2871, 2952, 3032, 3113, 3193, 3273, 3352, 3433, 3514, 3595, 3676, 3755, 3834, 3915, 3995, 4076, 4156, 4235, 4315, 4396, 4476, 4557, 4636, 4718, 4798, 4877, 4957, 5037, 5118, 5200, 5278, 5359, 5439, 5518, 5598, 5680, 5760, 5841, 5922, 6002, 6081, 6162, 6241, 6321, 6400, 6481, 6561, 6641, 6722, 6804, 6884, 6964, 7045, 7126, 7206, 7286, 7366, 7447, 7527, 7606, 7687, 7767, 7847, 7928, 8008, 8087, 8167, 8248, 8328, 8408, 8489, 8566, 8646, 8727, 8809, 8890, 8970, 9049, 9129, 9209, 9288, 9368, 9449, 9529, 9608, 9688, 9769, 9849] +evt_end = [ 170, 248, 327, 407, 486, 566, 645, 727, 808, 888, 968, 1048, 1128, 1209, 1287, 1367, 1447, 1526, 1607, 1685, 1765, 1845, 1925, 2005, 2084, 2164, 2245, 2325, 2406, 2485, 2565, 2646, 2726, 2807, 2886, 2967, 3047, 3128, 3208, 3288, 3367, 3448, 3529, 3610, 3691, 3770, 3849, 3930, 4010, 4091, 4171, 4250, 4330, 4411, 4491, 4572, 4651, 4733, 4813, 4892, 4972, 5052, 5133, 5215, 5293, 5374, 5454, 5533, 5613, 5695, 5775, 5856, 5937, 6017, 6096, 6177, 6256, 6336, 6415, 6496, 6576, 6656, 6737, 6819, 6899, 6979, 7060, 7141, 7221, 7301, 7381, 7462, 7542, 7621, 7702, 7782, 7862, 7943, 8023, 8102, 8182, 8263, 8343, 8423, 8504, 8581, 8661, 8742, 8824, 8905, 8985, 9064, 9144, 9224, 9303, 9383, 9464, 9544, 9623, 9703, 9784, 9864, 9943, 10000] +evt_bX = [1508071.0, 3016509.0, 4524020.0, 6032112.0, 7540028.0, 9048092.0, 10556072.0, 12064371.0, 13572143.0, 15080178.0, 16588072.0, 18096105.0, 19604092.0, 21112166.0, 22620146.0, 24128151.0, 25636093.0, 27144133.0, 28652094.0, 30160125.0, 31668120.0, 33176312.0, 34684455.0, 36192201.0, 37700299.0, 39208338.0, 40716228.0, 42224205.0, 43732346.0, 45240219.0, 46748391.0, 48256211.0, 49764321.0, 51272217.0, 52780276.0, 54288364.0, 55796155.0, 57304180.0, 58812172.0, 60320612.0, 61828166.0, 63336720.0, 64844207.0, 66352327.0, 67860452.0, 69368220.0, 70876499.0, 72384379.0, 73892278.0, 75400246.0, 76908483.0, 78416343.0, 79924240.0, 81432250.0, 82940306.0, 84449218.0, 85956368.0, 87464432.0, 88972282.0, 90480292.0, 91988279.0, 93496320.0, 95004286.0, 96512289.0, 98020429.0, 99528306.0, 101036272.0, 102544367.0, 104052284.0, 105560289.0, 107068427.0, 108576408.0, 110084415.0, 111592686.0, 113100369.0, 114608368.0, 116116420.0, 117624429.0, 119132375.0, 120640371.0, 122148359.0, 123656423.0, 125164763.0, 126673264.0, 128180360.0, 129688558.0, 131196596.0, 132704683.0, 134212939.0, 135720446.0, 137228683.0, 138736381.0, 140244545.0, 141752581.0, 143260466.0, 144768499.0, 146276523.0, 147784726.0, 149292502.0, 150800480.0, 152308621.0, 153816539.0, 155324424.0, 156832627.0, 158340668.0, 159848664.0, 161356504.0, 162864630.0, 164372489.0, 165880652.0, 167388456.0, 168896455.0, 170404493.0, 171912555.0, 173421358.0, 174928568.0, 176436571.0, 177945044.0, 179452976.0, 180961051.0, 182468742.0, 183976536.0, 185484542.0, 186992509.0] + +for j, (start,end) in enumerate(zip(evt_start,evt_end)): + filename_bx = "./condor_macros/run_all_AA_jobs_{}.sh".format(int(evt_bX[j])) + filename_dag = "./condor_macros/run_all_AA_jobs_{}.dag".format(int(evt_bX[j])) + ff_bx= open(filename_bx,"w+") + ff_dag= open(filename_dag,"w+") + ff_bx.write("#!/usr/bin/bash"+"\n") + ff.write("source {}\n".format(filename_bx)) + ff_all_dag.write("condor_submit_dag {}\n".format(filename_dag)) + parent_str = "PARENT" + for i in range(start,end+10): + filename = "./condor_macros/run_files_AA_{}_{}.sh".format(j,i) + f= open(filename,"w+") + f.write("#!/usr/bin/bash"+"\n") + f.write("source macros/run_files_AA.sh {} {} {}".format(i,i+1,evt_bX[j])+"\n") + f.close + chmod_px(filename) + filename_job = "./condor_macros/condor_run_files_AA_{}_{}.job".format(j,i) + ff_bx.write("condor_submit {}".format(filename_job)+"\n") + ff_dag.write("JOB A_{} {}\n".format(i,filename_job )) + parent_str += " A_{}".format(i) + f_job= open(filename_job,"w+") + n_line = 0 + for lines in introduction: + f_job.write(lines+"\n") + if n_line==3: + f_job.write("# The executable we want to run."+"\n") + f_job.write("Executable = condor_macros/run_files_AA_{}_{}.sh".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write(""+"\n") + f_job.write("# The argument to pass to the executable."+"\n") + f_job.write("Arguments = \"run job 300 evts AA {} {}\"".format(j,i)+"\n") + if n_line==38: + f_job.write("# The job's stdout is sent to this file."+"\n") + f_job.write("Output = " + work_dir + "Out/myjob_300evts_AA_{}_{}.out".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write("# The job's stderr is sent to this file."+"\n") + f_job.write("Error = " + work_dir + "Out/myjob_300evts_AA_{}_{}.err".format(j,i)+"\n") + f_job.write(""+"\n") + f_job.write("# The condor log file for this job, useful when debugging."+"\n") + f_job.write("Log = " + work_dir + "Out/condor_300evts_AA_{}_{}.log".format(j,i)+"\n") + f_job.write(""+"\n") + + n_line+=1 + + f_job.close + ff_bx.close + chmod_px(filename_bx) + + #chmod_px(filename) + filename_B = "./condor_macros/add_hist_{}.job".format(int(evt_bX[j])) + ff_dag.write("JOB B {}\n".format(filename_B )) + ff_dag.write(parent_str + " CHILD B") + ff_dag.close + chmod_px(filename_dag) + + # files for adding histos + # - .sh: + filename_B_sh = "./condor_macros/add_hist_{}.sh".format(int(evt_bX[j])) + ff_B_sh = open(filename_B_sh,"w+") + + ff_B_sh.write("#!/usr/bin/bash"+"\n") + ff_B_sh.write("source /opt/sphenix/core/bin/sphenix_setup.sh -n new"+"\n") + ff_B_sh.write("./macros/add_histos_bX.py {} {} \n".format(j,int(evt_bX[j]))) + + ff_B_sh.close + chmod_px(filename_B_sh) + + # - .job: + add_file_content = [ + "Universe = vanilla", + "Executable = {}".format(filename_B_sh), + "Arguments = \"run job add histos AA {}\"".format(int(evt_bX[j])), + "request_memory = 7.1GB", + init_str, + "# The job's stdout is sent to this file.", + "Output = ./Out/myjob_add_histos_AA_{}.out".format(int(evt_bX[j])), + "# The job's stderr is sent to this file.", + "Error = ./Out/myjob_add_histos_AA_{}.err".format(int(evt_bX[j])), + "# The condor log file for this job, useful when debugging.", + "Log = ./Out/condor_add_histos_AA_{}.log".format(int(evt_bX[j])), + "Queue" + ] + ff_B = open(filename_B,"w+") + for line in add_file_content: + ff_B.write(line+"\n") + ff_B.close + + +ff.close +ff_all_dag.close diff --git a/calibrations/tpc/fillSpaceChargeMaps/macros/add_histos_bX.py b/calibrations/tpc/fillSpaceChargeMaps/macros/add_histos_bX.py index 1334717d53..1bb7db003e 100755 --- a/calibrations/tpc/fillSpaceChargeMaps/macros/add_histos_bX.py +++ b/calibrations/tpc/fillSpaceChargeMaps/macros/add_histos_bX.py @@ -23,7 +23,7 @@ print(bX) name = 'mdc2_ADCBins_UseFieldMaps_hist_G4Hits_sHijing_0-12fm_bX{}*'.format(bX) -outputName = './Files/Summary_hist_mdc2_UseFieldMaps_AA_event_{}_bX{}.root'.format(ib,bX) +outputName = './Files/Summary_hist_mdc2_UseFieldMaps_AA_event_{}_bX{}_new.root'.format(ib,bX) filePattern = dirName+name files = sorted(glob.glob(filePattern)) diff --git a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh index b0ccd770ae..e0225eff56 100755 --- a/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh +++ b/calibrations/tpc/fillSpaceChargeMaps/macros/run_files_300evts_AA_MDC2.sh @@ -17,7 +17,7 @@ do #foutputname="./Files/mdc2_ADCBins_NoFieldMaps_hist_G4Hits_sHijing_0-12fm_bX"$bX"_"$A".root" ; echo $fname ; echo $foutputname ; - root -l -b -q ./macros/Fun4All_FillChargesMap_300evts_MDC2.C\(1,$XevtStart,$bX,\"$fname\",\"$foutputname\"\) + root -l -b -q ./macros/Fun4All_FillChargesMap_300evts_MDC2.C\(100,$XevtStart,$bX,\"$fname\",\"$foutputname\"\) done echo all done diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 2790e82600..a7686c7a33 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -289,6 +289,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( double gain_weight = 1.0; if(m_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm nelec = nelec*gain_weight; + std::cout<<"PHG4TpcPadPlaneReadout::MapToPadPlane gain_weight = "< SectorPhi; int m_NHits = 0; // Using Gain maps is turned off by default - int m_flagToUseGain = 0; + int m_flagToUseGain = 1; // gaussian sampling static constexpr double _nsigmas = 5; From e4166e5cfd12f270e2a5086381635b391c7fb704 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 11:18:46 -0400 Subject: [PATCH 303/468] add many layer fixed function --- .../packages/TrackerMillepedeAlignment/MakeMilleFiles.cc | 9 ++++++++- .../packages/TrackerMillepedeAlignment/MakeMilleFiles.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index cafd1668c3..7c21f9276b 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -453,7 +453,14 @@ bool MakeMilleFiles::is_layer_fixed(unsigned int layer) return ret; } - +void MakeMilleFiles::set_layers_fixed(unsigned int minlayer, + unsigned int maxlayer) +{ + for(unsigned int i=minlayer; i Date: Mon, 1 May 2023 12:14:07 -0400 Subject: [PATCH 304/468] Move bbcvertex and associated map to reco package area --- offline/packages/NodeDump/DumpBbcVertexMap.cc | 4 ++-- .../packages/bbc}/BbcVertex.h | 0 .../packages/bbc}/BbcVertexLinkDef.h | 0 .../packages/bbc}/BbcVertexMap.cc | 0 .../packages/bbc}/BbcVertexMap.h | 0 .../packages/bbc}/BbcVertexMapLinkDef.h | 0 .../packages/bbc}/BbcVertexMapv1.cc | 0 .../packages/bbc}/BbcVertexMapv1.h | 0 .../packages/bbc}/BbcVertexMapv1LinkDef.h | 0 .../packages/bbc}/BbcVertexv1.cc | 0 .../packages/bbc}/BbcVertexv1.h | 0 .../packages/bbc}/BbcVertexv1LinkDef.h | 0 offline/packages/bbc/Makefile.am | 23 +++++++++++++++---- .../g4bbc/BbcVertexFastSimReco.cc | 8 +++---- simulation/g4simulation/g4bbc/Makefile.am | 21 +---------------- .../g4simulation/g4vertex/GlobalVertexReco.cc | 4 ++-- 16 files changed, 28 insertions(+), 32 deletions(-) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertex.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexLinkDef.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMap.cc (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMap.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMapLinkDef.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMapv1.cc (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMapv1.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexMapv1LinkDef.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexv1.cc (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexv1.h (100%) rename {simulation/g4simulation/g4bbc => offline/packages/bbc}/BbcVertexv1LinkDef.h (100%) diff --git a/offline/packages/NodeDump/DumpBbcVertexMap.cc b/offline/packages/NodeDump/DumpBbcVertexMap.cc index e511e209cb..32d59e7a7c 100644 --- a/offline/packages/NodeDump/DumpBbcVertexMap.cc +++ b/offline/packages/NodeDump/DumpBbcVertexMap.cc @@ -1,7 +1,7 @@ #include "DumpBbcVertexMap.h" -#include -#include +#include +#include #include diff --git a/simulation/g4simulation/g4bbc/BbcVertex.h b/offline/packages/bbc/BbcVertex.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertex.h rename to offline/packages/bbc/BbcVertex.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexLinkDef.h b/offline/packages/bbc/BbcVertexLinkDef.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexLinkDef.h rename to offline/packages/bbc/BbcVertexLinkDef.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexMap.cc b/offline/packages/bbc/BbcVertexMap.cc similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMap.cc rename to offline/packages/bbc/BbcVertexMap.cc diff --git a/simulation/g4simulation/g4bbc/BbcVertexMap.h b/offline/packages/bbc/BbcVertexMap.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMap.h rename to offline/packages/bbc/BbcVertexMap.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexMapLinkDef.h b/offline/packages/bbc/BbcVertexMapLinkDef.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMapLinkDef.h rename to offline/packages/bbc/BbcVertexMapLinkDef.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexMapv1.cc b/offline/packages/bbc/BbcVertexMapv1.cc similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMapv1.cc rename to offline/packages/bbc/BbcVertexMapv1.cc diff --git a/simulation/g4simulation/g4bbc/BbcVertexMapv1.h b/offline/packages/bbc/BbcVertexMapv1.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMapv1.h rename to offline/packages/bbc/BbcVertexMapv1.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexMapv1LinkDef.h b/offline/packages/bbc/BbcVertexMapv1LinkDef.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexMapv1LinkDef.h rename to offline/packages/bbc/BbcVertexMapv1LinkDef.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexv1.cc b/offline/packages/bbc/BbcVertexv1.cc similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexv1.cc rename to offline/packages/bbc/BbcVertexv1.cc diff --git a/simulation/g4simulation/g4bbc/BbcVertexv1.h b/offline/packages/bbc/BbcVertexv1.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexv1.h rename to offline/packages/bbc/BbcVertexv1.h diff --git a/simulation/g4simulation/g4bbc/BbcVertexv1LinkDef.h b/offline/packages/bbc/BbcVertexv1LinkDef.h similarity index 100% rename from simulation/g4simulation/g4bbc/BbcVertexv1LinkDef.h rename to offline/packages/bbc/BbcVertexv1LinkDef.h diff --git a/offline/packages/bbc/Makefile.am b/offline/packages/bbc/Makefile.am index 847fbdf158..5c56bdec02 100644 --- a/offline/packages/bbc/Makefile.am +++ b/offline/packages/bbc/Makefile.am @@ -27,7 +27,11 @@ pkginclude_HEADERS = \ BbcPmtContainerV1.h \ BbcPmtHit.h \ BbcPmtHitV1.h \ - BbcReturnCodes.h + BbcReturnCodes.h \ + BbcVertex.h \ + BbcVertexv1.h \ + BbcVertexMap.h \ + BbcVertexMapv1.h ROOTDICTS = \ BbcOut_Dict.cc \ @@ -37,7 +41,11 @@ ROOTDICTS = \ BbcPmtHit_Dict.cc \ BbcPmtHitV1_Dict.cc \ BbcPmtContainer_Dict.cc \ - BbcPmtContainerV1_Dict.cc + BbcPmtContainerV1_Dict.cc \ + BbcVertex_Dict.cc \ + BbcVertexv1_Dict.cc \ + BbcVertexMap_Dict.cc \ + BbcVertexMapv1_Dict.cc pcmdir = $(libdir) @@ -49,7 +57,11 @@ nobase_dist_pcm_DATA = \ BbcPmtHit_Dict_rdict.pcm \ BbcPmtHitV1_Dict_rdict.pcm \ BbcPmtContainer_Dict_rdict.pcm \ - BbcPmtContainerV1_Dict_rdict.pcm + BbcPmtContainerV1_Dict_rdict.pcm \ + BbcVertex_Dict_rdict.pcm \ + BbcVertexv1_Dict_rdict.pcm \ + BbcVertexMap_Dict_rdict.pcm \ + BbcVertexMapv1_Dict_rdict.pcm libbbc_io_la_SOURCES = \ @@ -61,7 +73,10 @@ libbbc_io_la_SOURCES = \ BbcPmtHit.cc \ BbcPmtHitV1.cc \ BbcPmtContainer.cc \ - BbcPmtContainerV1.cc + BbcPmtContainerV1.cc \ + BbcVertexv1.cc \ + BbcVertexMap.cc \ + BbcVertexMapv1.cc libbbc_io_la_LIBADD = \ -lphool diff --git a/simulation/g4simulation/g4bbc/BbcVertexFastSimReco.cc b/simulation/g4simulation/g4bbc/BbcVertexFastSimReco.cc index cc30dacfa9..7bae66fe87 100644 --- a/simulation/g4simulation/g4bbc/BbcVertexFastSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcVertexFastSimReco.cc @@ -1,10 +1,10 @@ #include "BbcVertexFastSimReco.h" -#include "BbcVertex.h" // for BbcVertex -#include "BbcVertexMap.h" // for BbcVertexMap -#include "BbcVertexMapv1.h" -#include "BbcVertexv1.h" +#include // for BbcVertex +#include // for BbcVertexMap +#include +#include #include #include diff --git a/simulation/g4simulation/g4bbc/Makefile.am b/simulation/g4simulation/g4bbc/Makefile.am index 2071b720b5..4b399cd005 100644 --- a/simulation/g4simulation/g4bbc/Makefile.am +++ b/simulation/g4simulation/g4bbc/Makefile.am @@ -23,31 +23,12 @@ libg4bbc_la_LIBADD = \ -lSubsysReco pkginclude_HEADERS = \ - BbcVertex.h \ - BbcVertexv1.h \ - BbcVertexMap.h \ - BbcVertexMapv1.h \ BbcSimReco.h \ BbcVertexFastSimReco.h -ROOTDICTS = \ - BbcVertex_Dict.cc \ - BbcVertexv1_Dict.cc \ - BbcVertexMap_Dict.cc \ - BbcVertexMapv1_Dict.cc - -pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - BbcVertex_Dict_rdict.pcm \ - BbcVertexv1_Dict_rdict.pcm \ - BbcVertexMap_Dict_rdict.pcm \ - BbcVertexMapv1_Dict_rdict.pcm libg4bbc_io_la_SOURCES = \ - $(ROOTDICTS) \ - BbcVertexv1.cc \ - BbcVertexMap.cc \ - BbcVertexMapv1.cc + $(ROOTDICTS) libg4bbc_la_SOURCES = \ BbcSimReco.cc \ diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc index 322e26074f..85324f9fff 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexReco.cc @@ -5,8 +5,8 @@ #include "GlobalVertexMapv1.h" #include "GlobalVertexv1.h" -#include -#include +#include +#include #include From c76eb621fe3cd8ebfb6dd1dd44d65f5ee7bf047a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 12:20:00 -0400 Subject: [PATCH 305/468] Rename to bbc digitization --- .../g4bbc/{BbcSimReco.cc => BbcDigitization.cc} | 16 ++++++++-------- .../g4bbc/{BbcSimReco.h => BbcDigitization.h} | 12 ++++++------ simulation/g4simulation/g4bbc/Makefile.am | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) rename simulation/g4simulation/g4bbc/{BbcSimReco.cc => BbcDigitization.cc} (96%) rename simulation/g4simulation/g4bbc/{BbcSimReco.h => BbcDigitization.h} (90%) diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.cc b/simulation/g4simulation/g4bbc/BbcDigitization.cc similarity index 96% rename from simulation/g4simulation/g4bbc/BbcSimReco.cc rename to simulation/g4simulation/g4bbc/BbcDigitization.cc index 5cc090c1c7..855075c406 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.cc +++ b/simulation/g4simulation/g4bbc/BbcDigitization.cc @@ -1,4 +1,4 @@ -#include "BbcSimReco.h" +#include "BbcDigitization.h" #include #include @@ -119,7 +119,7 @@ namespace BBCINFO } // namespace BBCINFO //____________________________________ -BbcSimReco::BbcSimReco(const std::string &name) +BbcDigitization::BbcDigitization(const std::string &name) : SubsysReco(name) , _tres(0.05) { @@ -137,14 +137,14 @@ BbcSimReco::BbcSimReco(const std::string &name) gsl_rng_set(m_RandomGenerator, m_Seed); } -BbcSimReco::~BbcSimReco() +BbcDigitization::~BbcDigitization() { gsl_rng_free(m_RandomGenerator); return; } //___________________________________ -int BbcSimReco::Init(PHCompositeNode *topNode) +int BbcDigitization::Init(PHCompositeNode *topNode) { // std::cout << PHWHERE << std::endl; CreateNodes(topNode); @@ -170,7 +170,7 @@ int BbcSimReco::Init(PHCompositeNode *topNode) } //___________________________________ -int BbcSimReco::InitRun(PHCompositeNode *topNode) +int BbcDigitization::InitRun(PHCompositeNode *topNode) { GetNodes(topNode); @@ -179,7 +179,7 @@ int BbcSimReco::InitRun(PHCompositeNode *topNode) //__________________________________ // Call user instructions for every event -int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) +int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) { //**** Initialize Variables @@ -392,7 +392,7 @@ int BbcSimReco::process_event(PHCompositeNode * /*topNode*/) return 0; } -void BbcSimReco::CreateNodes(PHCompositeNode *topNode) +void BbcDigitization::CreateNodes(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); @@ -430,7 +430,7 @@ void BbcSimReco::CreateNodes(PHCompositeNode *topNode) } //___________________________________ -void BbcSimReco::GetNodes(PHCompositeNode *topNode) +void BbcDigitization::GetNodes(PHCompositeNode *topNode) { // Get the DST objects diff --git a/simulation/g4simulation/g4bbc/BbcSimReco.h b/simulation/g4simulation/g4bbc/BbcDigitization.h similarity index 90% rename from simulation/g4simulation/g4bbc/BbcSimReco.h rename to simulation/g4simulation/g4bbc/BbcDigitization.h index 471c787fc9..48858f1fe8 100644 --- a/simulation/g4simulation/g4bbc/BbcSimReco.h +++ b/simulation/g4simulation/g4bbc/BbcDigitization.h @@ -1,5 +1,5 @@ -#ifndef G4BBC_BBCSIMRECO_H -#define G4BBC_BBCSIMRECO_H +#ifndef G4BBC_BBCDIGITIZATION_H +#define G4BBC_BBCDIGITIZATION_H #include @@ -24,13 +24,13 @@ class TH1; class TH2; class TF1; -class BbcSimReco : public SubsysReco +class BbcDigitization : public SubsysReco { public: // Default constructor - BbcSimReco(const std::string &name = "BbcSimReco"); + BbcDigitization(const std::string &name = "BbcDigitization"); - ~BbcSimReco() override; + ~BbcDigitization() override; //! Initialization, called for at overall initialization int Init(PHCompositeNode *) override; @@ -88,4 +88,4 @@ class BbcSimReco : public SubsysReco BbcPmtContainer *_bbcpmts = nullptr; }; -#endif //* __BBCSIMRECO_H__ *// +#endif //* __BBCDIGITIZATION_H__ *// diff --git a/simulation/g4simulation/g4bbc/Makefile.am b/simulation/g4simulation/g4bbc/Makefile.am index 4b399cd005..9a8f221bfc 100644 --- a/simulation/g4simulation/g4bbc/Makefile.am +++ b/simulation/g4simulation/g4bbc/Makefile.am @@ -23,7 +23,7 @@ libg4bbc_la_LIBADD = \ -lSubsysReco pkginclude_HEADERS = \ - BbcSimReco.h \ + BbcDigitization.h \ BbcVertexFastSimReco.h @@ -31,7 +31,7 @@ libg4bbc_io_la_SOURCES = \ $(ROOTDICTS) libg4bbc_la_SOURCES = \ - BbcSimReco.cc \ + BbcDigitization.cc \ BbcVertexFastSimReco.cc # Rule for generating table CINT dictionaries. From 6ef5cbec0bd46907d5f87a4297c0a5f85751b858 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 13:43:56 -0400 Subject: [PATCH 306/468] Separate BBC digitization and reconstruction Have reconstruction write to BbcVertexMap with new BbcVertex object that can keep track of north and south info --- offline/packages/bbc/BbcDefs.h | 93 +++++++++ offline/packages/bbc/BbcReconstruction.cc | 195 ++++++++++++++++++ offline/packages/bbc/BbcReconstruction.h | 39 ++++ offline/packages/bbc/BbcVertex.h | 5 + offline/packages/bbc/BbcVertexv2.cc | 53 +++++ offline/packages/bbc/BbcVertexv2.h | 62 ++++++ offline/packages/bbc/BbcVertexv2LinkDef.h | 5 + offline/packages/bbc/Makefile.am | 10 +- .../g4simulation/g4bbc/BbcDigitization.cc | 86 +------- 9 files changed, 464 insertions(+), 84 deletions(-) create mode 100644 offline/packages/bbc/BbcDefs.h create mode 100644 offline/packages/bbc/BbcReconstruction.cc create mode 100644 offline/packages/bbc/BbcReconstruction.h create mode 100644 offline/packages/bbc/BbcVertexv2.cc create mode 100644 offline/packages/bbc/BbcVertexv2.h create mode 100644 offline/packages/bbc/BbcVertexv2LinkDef.h diff --git a/offline/packages/bbc/BbcDefs.h b/offline/packages/bbc/BbcDefs.h new file mode 100644 index 0000000000..a0c7a046a6 --- /dev/null +++ b/offline/packages/bbc/BbcDefs.h @@ -0,0 +1,93 @@ +#ifndef BBC_BBCDEFS_H +#define BBC_BBCDEFS_H + +#include +#include + +namespace BbcDefs +{ + const Double_t index_refract = 1.4585; + const Double_t v_ckov = 1.0 / index_refract; // velocity threshold for CKOV + const Double_t C = 29.9792458; // cm/ns + + // kludge where we have the hardcoded positions of the tubes + // These are the x,y for the south BBC (in cm). + // The north inverts the x coordinate (x -> -x) + + /* unused causes compiler warning + const float TubeLoc[64][2] = { + { -12.2976, 4.26 }, + { -12.2976, 1.42 }, + { -9.83805, 8.52 }, + { -9.83805, 5.68 }, + { -9.83805, 2.84 }, + { -7.37854, 9.94 }, + { -7.37854, 7.1 }, + { -7.37854, 4.26 }, + { -7.37854, 1.42 }, + { -4.91902, 11.36 }, + { -4.91902, 8.52 }, + { -4.91902, 5.68 }, + { -2.45951, 12.78 }, + { -2.45951, 9.94 }, + { -2.45951, 7.1 }, + { 0, 11.36 }, + { 0, 8.52 }, + { 2.45951, 12.78 }, + { 2.45951, 9.94 }, + { 2.45951, 7.1 }, + { 4.91902, 11.36 }, + { 4.91902, 8.52 }, + { 4.91902, 5.68 }, + { 7.37854, 9.94 }, + { 7.37854, 7.1 }, + { 7.37854, 4.26 }, + { 7.37854, 1.42 }, + { 9.83805, 8.52 }, + { 9.83805, 5.68 }, + { 9.83805, 2.84 }, + { 12.2976, 4.26 }, + { 12.2976, 1.42 }, + { 12.2976, -4.26 }, + { 12.2976, -1.42 }, + { 9.83805, -8.52 }, + { 9.83805, -5.68 }, + { 9.83805, -2.84 }, + { 7.37854, -9.94 }, + { 7.37854, -7.1 }, + { 7.37854, -4.26 }, + { 7.37854, -1.42 }, + { 4.91902, -11.36 }, + { 4.91902, -8.52 }, + { 4.91902, -5.68 }, + { 2.45951, -12.78 }, + { 2.45951, -9.94 }, + { 2.45951, -7.1 }, + { 0, -11.36 }, + { 0, -8.52 }, + { -2.45951, -12.78 }, + { -2.45951, -9.94 }, + { -2.45951, -7.1 }, + { -4.91902, -11.36 }, + { -4.91902, -8.52 }, + { -4.91902, -5.68 }, + { -7.37854, -9.94 }, + { -7.37854, -7.1 }, + { -7.37854, -4.26 }, + { -7.37854, -1.42 }, + { -9.83805, -8.52 }, + { -9.83805, -5.68 }, + { -9.83805, -2.84 }, + { -12.2976, -4.26 }, + { -12.2976, -1.42 } + }; + */ + + +} + + + + + +#endif diff --git a/offline/packages/bbc/BbcReconstruction.cc b/offline/packages/bbc/BbcReconstruction.cc new file mode 100644 index 0000000000..19cfe075f3 --- /dev/null +++ b/offline/packages/bbc/BbcReconstruction.cc @@ -0,0 +1,195 @@ +#include "BbcDefs.h" +#include "BbcReturnCodes.h" +#include "BbcReconstruction.h" +#include "BbcPmtContainer.h" +#include "BbcVertexMapv1.h" +#include "BbcVertexv2.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +//____________________________________________________________________________.. +BbcReconstruction::BbcReconstruction(const std::string &name): + SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +BbcReconstruction::~BbcReconstruction() +{ +} + +//____________________________________________________________________________.. +int BbcReconstruction::Init(PHCompositeNode *) +{ + + m_gaussian = new TF1("gaussian","gaus",0,20); + m_gaussian->FixParameter(2, m_tres); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int BbcReconstruction::InitRun(PHCompositeNode *topNode) +{ + if(createNodes(topNode) == Fun4AllReturnCodes::ABORTEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + int ret = getNodes(topNode); + return ret; +} + +//____________________________________________________________________________.. +int BbcReconstruction::process_event(PHCompositeNode *) +{ + TH1 *h_evt_bbct[2]{}; + h_evt_bbct[0] = nullptr; + h_evt_bbct[1] = nullptr; + TString name, title; + for (int iarm = 0; iarm < 2; iarm++) + { + // + name = "hevt_bbct"; + name += iarm; + title = "bbc times, arm "; + title += iarm; + h_evt_bbct[iarm] = new TH1F(name, title, 200, 7.5, 11.5); + h_evt_bbct[iarm]->SetLineColor(4); + } + + std::vector hit_times[2]; + float bbcq[2] = {0}; + float bbcn[2] = {0}; + float bbct[2] = {0}; + + for(int ich = 0; ich < 128; ich++) + { + const int arm = ich / 64; + auto bbchit = m_bbcpmts->get_tdc0(ich); + if(bbchit == BbcReturnCodes::BBC_INVALID_FLOAT) + { + //! No hit in PMT, continue + continue; + } + + //! total charge + bbcq[arm] += m_bbcpmts->get_adc(ich); + + //! number of hit pmts + bbcn[arm]++; + + if(bbchit < 9999.) + { + h_evt_bbct[arm]->Fill(bbchit); + hit_times[arm].push_back(bbchit); + } + + } + + if(bbcn[0]> 0 && bbcn[1] >0) + { + for(int iarm = 0; iarm < 2; iarm++) + { + if(hit_times[iarm].empty()) + { + continue; + } + + std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); + float earliest = hit_times[iarm][0]; + m_gaussian->SetParameter(0,5); + m_gaussian->SetParameter(1, earliest); + m_gaussian->SetRange(6, earliest + 5 * m_tres); + h_evt_bbct[iarm]->Fit(m_gaussian,"BLRNQ"); + bbct[iarm] = m_gaussian->GetParameter(1); + + + } + + float bbcz = (bbct[0] - bbct[1]) * BbcDefs::C /2.; + float bbct0 = (bbct[0] + bbct[1]) / 2.; + + auto vertex = std::make_unique(); + vertex->set_t(bbct0); + vertex->set_z(bbcz); + for(int iarm=0 ; iarm<2; iarm++) + { + vertex->set_bbc_ns(iarm, bbcn[iarm], bbcq[iarm], bbct[iarm]); + } + + m_bbcvertexmap->insert(vertex.release()); + } + + + return Fun4AllReturnCodes::EVENT_OK; +} + + +//____________________________________________________________________________.. +int BbcReconstruction::End(PHCompositeNode *) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int BbcReconstruction::createNodes(PHCompositeNode* topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + PHCompositeNode *bbcNode = dynamic_cast(iter.findFirst("PHCompositeNode", "BBC")); + if (!bbcNode) + { + bbcNode = new PHCompositeNode("BBC"); + dstNode->addNode(bbcNode); + } + + + m_bbcvertexmap = findNode::getClass(bbcNode, "BbcVertexMap"); + if(!m_bbcvertexmap) + { + m_bbcvertexmap = new BbcVertexMapv1(); + PHIODataNode *VertexMapNode = new PHIODataNode(m_bbcvertexmap, "BbcVertexMap", "PHObject"); + bbcNode->addNode(VertexMapNode); + } + + return Fun4AllReturnCodes::EVENT_OK; +} +int BbcReconstruction::getNodes(PHCompositeNode* topNode) +{ + // BbcPmtContainer + m_bbcpmts = findNode::getClass(topNode, "BbcPmtContainer"); + if (!m_bbcpmts) + { + std::cout << PHWHERE << " BbcPmtContainer node not found on node tree" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_bbcvertexmap = findNode::getClass(topNode, "BbcVertexMap"); + if(!m_bbcvertexmap) + { + std::cout << PHWHERE << "BbcVertexMap node not found on node tree" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bbc/BbcReconstruction.h b/offline/packages/bbc/BbcReconstruction.h new file mode 100644 index 0000000000..d2c7b429bb --- /dev/null +++ b/offline/packages/bbc/BbcReconstruction.h @@ -0,0 +1,39 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BBCRECONSTRUCTION_H +#define BBCRECONSTRUCTION_H + +#include + +#include + +class PHCompositeNode; +class BbcPmtContainer; +class BbcVertexMap; +class TF1; + +class BbcReconstruction : public SubsysReco +{ + public: + + BbcReconstruction(const std::string &name = "BbcReconstruction"); + + ~BbcReconstruction() override; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + int End(PHCompositeNode *topNode) override; + + private: + int createNodes(PHCompositeNode *topNode); + int getNodes(PHCompositeNode *topNode); + TF1* m_gaussian = nullptr; + + float m_tres = 0.05; + + BbcVertexMap* m_bbcvertexmap = nullptr; + BbcPmtContainer *m_bbcpmts = nullptr; +}; + +#endif // BBCRECONSTRUCTION_H diff --git a/offline/packages/bbc/BbcVertex.h b/offline/packages/bbc/BbcVertex.h index 65747330d5..f7a60791fb 100644 --- a/offline/packages/bbc/BbcVertex.h +++ b/offline/packages/bbc/BbcVertex.h @@ -34,6 +34,11 @@ class BbcVertex : public PHObject virtual float get_z_err() const { return NAN; } virtual void set_z_err(float) {} + virtual void set_bbc_ns(int, int, float, float) {} + virtual int get_bbc_npmt(int) const { return std::numeric_limits::max(); } + virtual float get_bbc_q(int) const { return NAN; } + virtual float get_bbc_t(int) const { return NAN; } + protected: BbcVertex() {} diff --git a/offline/packages/bbc/BbcVertexv2.cc b/offline/packages/bbc/BbcVertexv2.cc new file mode 100644 index 0000000000..dbde9aeacb --- /dev/null +++ b/offline/packages/bbc/BbcVertexv2.cc @@ -0,0 +1,53 @@ +#include "BbcVertexv2.h" + +#include + +using namespace std; + +BbcVertexv2::BbcVertexv2() + : _id(0xFFFFFFFF) + , _t(NAN) + , _t_err(NAN) + , _z(NAN) + , _z_err(NAN) +{ +} + +BbcVertexv2::~BbcVertexv2() = default; + +void BbcVertexv2::identify(ostream& os) const +{ + os << "---BbcVertexv2--------------------------------" << endl; + os << "vertexid: " << get_id() << endl; + os << " t = " << get_t() << " +/- " << get_t_err() << endl; + os << " z = " << get_z() << " +/- " << get_z_err() << endl; + os << "-----------------------------------------------" << endl; + + return; +} + +int BbcVertexv2::isValid() const +{ + if (_id == 0xFFFFFFFF) + { + return 0; + } + if (isnan(_t)) + { + return 0; + } + if (isnan(_t_err)) + { + return 0; + } + if (isnan(_z)) + { + return 0; + } + if (isnan(_z_err)) + { + return 0; + } + + return 1; +} diff --git a/offline/packages/bbc/BbcVertexv2.h b/offline/packages/bbc/BbcVertexv2.h new file mode 100644 index 0000000000..6763283072 --- /dev/null +++ b/offline/packages/bbc/BbcVertexv2.h @@ -0,0 +1,62 @@ +#ifndef G4BBC_BBCVERTEXV2_H +#define G4BBC_BBCVERTEXV2_H + +#include "BbcVertex.h" + +#include + +class BbcVertexv2 : public BbcVertex +{ + public: + BbcVertexv2(); + ~BbcVertexv2() override; + + // PHObject virtual overloads + + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = BbcVertexv2(); } + int isValid() const override; + PHObject* CloneMe() const override { return new BbcVertexv2(*this); } + + // vertex info + + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + float get_t() const override { return _t; } + void set_t(float t) override { _t = t; } + + float get_t_err() const override { return _t_err; } + void set_t_err(float t_err) override { _t_err = t_err; } + + float get_z() const override { return _z; } + void set_z(float z) override { _z = z; } + + float get_z_err() const override { return _z_err; } + void set_z_err(float z_err) override { _z_err = z_err; } + + void set_bbc_ns(int iarm, int bbc_npmt, float bbc_q, float bbc_t) override + { + _bbc_ns_npmt[iarm] = bbc_npmt; + _bbc_ns_q[iarm] = bbc_q; + _bbc_ns_t[iarm] = bbc_t; + } + + int get_bbc_npmt(int iarm) const override { return _bbc_ns_npmt[iarm]; } + float get_bbc_q(int iarm) const override { return _bbc_ns_q[iarm]; } + float get_bbc_t(int iarm) const override { return _bbc_ns_t[iarm]; } + + private: + unsigned int _id; //< unique identifier within container + float _t; //< collision time + float _t_err; //< collision time uncertainty + float _z; //< collision position z + float _z_err; //< collision position z uncertainty + int _bbc_ns_npmt[2]; + float _bbc_ns_q[2]; + float _bbc_ns_t[2]; + + ClassDefOverride(BbcVertexv2, 1); +}; + +#endif diff --git a/offline/packages/bbc/BbcVertexv2LinkDef.h b/offline/packages/bbc/BbcVertexv2LinkDef.h new file mode 100644 index 0000000000..64673af5b8 --- /dev/null +++ b/offline/packages/bbc/BbcVertexv2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BbcVertexv2 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/bbc/Makefile.am b/offline/packages/bbc/Makefile.am index 5c56bdec02..1160ced917 100644 --- a/offline/packages/bbc/Makefile.am +++ b/offline/packages/bbc/Makefile.am @@ -19,6 +19,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 pkginclude_HEADERS = \ + BbcDefs.h \ BbcOut.h \ BbcOutV1.h \ BbcNorthSouth.h \ @@ -27,9 +28,11 @@ pkginclude_HEADERS = \ BbcPmtContainerV1.h \ BbcPmtHit.h \ BbcPmtHitV1.h \ + BbcReconstruction.h \ BbcReturnCodes.h \ BbcVertex.h \ BbcVertexv1.h \ + BbcVertexv2.h \ BbcVertexMap.h \ BbcVertexMapv1.h @@ -44,6 +47,7 @@ ROOTDICTS = \ BbcPmtContainerV1_Dict.cc \ BbcVertex_Dict.cc \ BbcVertexv1_Dict.cc \ + BbcVertexv2_Dict.cc \ BbcVertexMap_Dict.cc \ BbcVertexMapv1_Dict.cc @@ -60,6 +64,7 @@ nobase_dist_pcm_DATA = \ BbcPmtContainerV1_Dict_rdict.pcm \ BbcVertex_Dict_rdict.pcm \ BbcVertexv1_Dict_rdict.pcm \ + BbcVertexv2_Dict_rdict.pcm \ BbcVertexMap_Dict_rdict.pcm \ BbcVertexMapv1_Dict_rdict.pcm @@ -74,12 +79,15 @@ libbbc_io_la_SOURCES = \ BbcPmtHitV1.cc \ BbcPmtContainer.cc \ BbcPmtContainerV1.cc \ + BbcReconstruction.cc \ BbcVertexv1.cc \ + BbcVertexv2.cc \ BbcVertexMap.cc \ BbcVertexMapv1.cc libbbc_io_la_LIBADD = \ - -lphool + -lphool \ + -lSubsysReco # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h diff --git a/simulation/g4simulation/g4bbc/BbcDigitization.cc b/simulation/g4simulation/g4bbc/BbcDigitization.cc index 855075c406..0a207e8878 100644 --- a/simulation/g4simulation/g4bbc/BbcDigitization.cc +++ b/simulation/g4simulation/g4bbc/BbcDigitization.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -37,87 +38,6 @@ #include #include -namespace BBCINFO -{ - const Double_t index_refract = 1.4585; - const Double_t v_ckov = 1.0 / index_refract; // velocity threshold for CKOV - const Double_t C = 29.9792458; // cm/ns - - // kludge where we have the hardcoded positions of the tubes - // These are the x,y for the south BBC (in cm). - // The north inverts the x coordinate (x -> -x) - - /* unused causes compiler warning - const float TubeLoc[64][2] = { - { -12.2976, 4.26 }, - { -12.2976, 1.42 }, - { -9.83805, 8.52 }, - { -9.83805, 5.68 }, - { -9.83805, 2.84 }, - { -7.37854, 9.94 }, - { -7.37854, 7.1 }, - { -7.37854, 4.26 }, - { -7.37854, 1.42 }, - { -4.91902, 11.36 }, - { -4.91902, 8.52 }, - { -4.91902, 5.68 }, - { -2.45951, 12.78 }, - { -2.45951, 9.94 }, - { -2.45951, 7.1 }, - { 0, 11.36 }, - { 0, 8.52 }, - { 2.45951, 12.78 }, - { 2.45951, 9.94 }, - { 2.45951, 7.1 }, - { 4.91902, 11.36 }, - { 4.91902, 8.52 }, - { 4.91902, 5.68 }, - { 7.37854, 9.94 }, - { 7.37854, 7.1 }, - { 7.37854, 4.26 }, - { 7.37854, 1.42 }, - { 9.83805, 8.52 }, - { 9.83805, 5.68 }, - { 9.83805, 2.84 }, - { 12.2976, 4.26 }, - { 12.2976, 1.42 }, - { 12.2976, -4.26 }, - { 12.2976, -1.42 }, - { 9.83805, -8.52 }, - { 9.83805, -5.68 }, - { 9.83805, -2.84 }, - { 7.37854, -9.94 }, - { 7.37854, -7.1 }, - { 7.37854, -4.26 }, - { 7.37854, -1.42 }, - { 4.91902, -11.36 }, - { 4.91902, -8.52 }, - { 4.91902, -5.68 }, - { 2.45951, -12.78 }, - { 2.45951, -9.94 }, - { 2.45951, -7.1 }, - { 0, -11.36 }, - { 0, -8.52 }, - { -2.45951, -12.78 }, - { -2.45951, -9.94 }, - { -2.45951, -7.1 }, - { -4.91902, -11.36 }, - { -4.91902, -8.52 }, - { -4.91902, -5.68 }, - { -7.37854, -9.94 }, - { -7.37854, -7.1 }, - { -7.37854, -4.26 }, - { -7.37854, -1.42 }, - { -9.83805, -8.52 }, - { -9.83805, -5.68 }, - { -9.83805, -2.84 }, - { -12.2976, -4.26 }, - { -12.2976, -1.42 } - }; - */ - -} // namespace BBCINFO - //____________________________________ BbcDigitization::BbcDigitization(const std::string &name) : SubsysReco(name) @@ -277,7 +197,7 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) // get summed path length for particles that can create CKOV light // n.p.e. is determined from path length Double_t beta = v4.Beta(); - if (beta > BBCINFO::v_ckov && charge != 0.) + if (beta > BbcDefs::v_ckov && charge != 0.) { len[ch] += this_hit->get_path_length(); @@ -382,7 +302,7 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) } // Now calculate zvtx, t0 from best times - f_bbcz = (f_bbct[0] - f_bbct[1]) * BBCINFO::C / 2.0; + f_bbcz = (f_bbct[0] - f_bbct[1]) * BbcDefs::C / 2.0; f_bbct0 = (f_bbct[0] + f_bbct[1]) / 2.0; _bbcout->set_Vertex(f_bbcz, 0.6); From 90ce686b7e009f09a4c05b463e3e03f984a3a046 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 15:16:00 -0400 Subject: [PATCH 307/468] reproduces current bbc reco --- offline/packages/bbc/BbcReconstruction.cc | 45 +++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/offline/packages/bbc/BbcReconstruction.cc b/offline/packages/bbc/BbcReconstruction.cc index 19cfe075f3..613f047d6f 100644 --- a/offline/packages/bbc/BbcReconstruction.cc +++ b/offline/packages/bbc/BbcReconstruction.cc @@ -79,26 +79,37 @@ int BbcReconstruction::process_event(PHCompositeNode *) for(int ich = 0; ich < 128; ich++) { - const int arm = ich / 64; + + const auto pmt = m_bbcpmts->get_pmt(ich); + const int arm = pmt / 64; auto bbchit = m_bbcpmts->get_tdc0(ich); - if(bbchit == BbcReturnCodes::BBC_INVALID_FLOAT) + + if(std::isnan(m_bbcpmts->get_adc(ich))) { - //! No hit in PMT, continue + //! PMT with no ADC, skip it continue; } - //! total charge - bbcq[arm] += m_bbcpmts->get_adc(ich); - - //! number of hit pmts - bbcn[arm]++; - if(bbchit < 9999.) { + //! total charge + bbcq[arm] += m_bbcpmts->get_adc(ich); + + //! number of hit pmts + bbcn[arm]++; + h_evt_bbct[arm]->Fill(bbchit); hit_times[arm].push_back(bbchit); } - + if(Verbosity() > 0) + { + std::cout << "Channel " << ich << " with pmt " << pmt << " in arm " << arm << " has " << m_bbcpmts->get_adc(ich) << std::endl; + } + } + + if(Verbosity() > 0) + { + std::cout << "nbbc arm 1,2: " << bbcn[0] << ", " << bbcn[1] << std::endl; } if(bbcn[0]> 0 && bbcn[1] >0) @@ -127,14 +138,24 @@ int BbcReconstruction::process_event(PHCompositeNode *) auto vertex = std::make_unique(); vertex->set_t(bbct0); vertex->set_z(bbcz); + vertex->set_z_err(0.6); + vertex->set_t_err(m_tres); + for(int iarm=0 ; iarm<2; iarm++) { vertex->set_bbc_ns(iarm, bbcn[iarm], bbcq[iarm], bbct[iarm]); } + if(Verbosity() > 0) + { + std::cout << "bbc vertex z and t0 " << bbcz << ", " + << bbct0 << std::endl; + } + m_bbcvertexmap->insert(vertex.release()); - } - + + } + return Fun4AllReturnCodes::EVENT_OK; } From 745e238b90d2f115400063b0092a15e573801010 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 15:28:37 -0400 Subject: [PATCH 308/468] Remove code now put into bbc reconstruction --- .../g4simulation/g4bbc/BbcDigitization.cc | 121 +----------------- .../g4simulation/g4bbc/BbcDigitization.h | 11 +- 2 files changed, 5 insertions(+), 127 deletions(-) diff --git a/simulation/g4simulation/g4bbc/BbcDigitization.cc b/simulation/g4simulation/g4bbc/BbcDigitization.cc index 0a207e8878..39e50fd614 100644 --- a/simulation/g4simulation/g4bbc/BbcDigitization.cc +++ b/simulation/g4simulation/g4bbc/BbcDigitization.cc @@ -1,6 +1,5 @@ #include "BbcDigitization.h" -#include #include #include @@ -46,12 +45,6 @@ BbcDigitization::BbcDigitization(const std::string &name) std::fill(std::begin(f_pmtq), std::end(f_pmtq), std::numeric_limits::quiet_NaN()); std::fill(std::begin(f_pmtt0), std::end(f_pmtt0), std::numeric_limits::quiet_NaN()); std::fill(std::begin(f_pmtt1), std::end(f_pmtt1), std::numeric_limits::quiet_NaN()); - std::fill(std::begin(f_bbcn), std::end(f_bbcn), 0); - std::fill(std::begin(f_bbcq), std::end(f_bbcq), std::numeric_limits::quiet_NaN()); - std::fill(std::begin(f_bbct), std::end(f_bbct), std::numeric_limits::quiet_NaN()); - std::fill(std::begin(f_bbcte), std::end(f_bbcte), std::numeric_limits::quiet_NaN()); - hevt_bbct[0] = nullptr; - hevt_bbct[1] = nullptr; m_RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); m_Seed = PHRandomSeed(); // fixed seed is handled in this funtcion gsl_rng_set(m_RandomGenerator, m_Seed); @@ -71,18 +64,6 @@ int BbcDigitization::Init(PHCompositeNode *topNode) _pdg = new TDatabasePDG(); // database of PDG info on particles - TString name, title; - for (int iarm = 0; iarm < 2; iarm++) - { - // - name = "hevt_bbct"; - name += iarm; - title = "bbc times, arm "; - title += iarm; - hevt_bbct[iarm] = new TH1F(name, title, 200, 7.5, 11.5); - hevt_bbct[iarm]->SetLineColor(4); - } - gaussian = new TF1("gaussian", "gaus", 0, 20); gaussian->FixParameter(2, _tres); // set sigma to timing resolution @@ -103,20 +84,6 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) { //**** Initialize Variables - // Arm Data - f_bbcn[0] = 0; - f_bbcn[1] = 0; - f_bbcq[0] = 0.; - f_bbcq[1] = 0.; - f_bbct[0] = -9999.; - f_bbct[1] = -9999.; - f_bbcte[0] = -9999.; - f_bbcte[1] = -9999.; - f_bbcz = std::numeric_limits::quiet_NaN(); - f_bbct0 = std::numeric_limits::quiet_NaN(); - hevt_bbct[0]->Reset(); - hevt_bbct[1]->Reset(); - // PMT data float len[128] = {0.}; float edep[128] = {0.}; @@ -207,18 +174,8 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) nhits++; } - // process the data from each channel - for (float &iarm : f_bbct) - { - iarm = 0.; - } - - std::vector hit_times[2]; // times of the hits in each [arm] - for (int ich = 0; ich < 128; ich++) { - int arm = ich / 64; // ch 0-63 = south, ch 64-127 = north - // Fill charge and time info if (len[ich] > 0.) { @@ -232,20 +189,11 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) float dnpe = gsl_ran_gaussian(m_RandomGenerator, std::sqrt(npe)); // get fluctuation in npe npe += dnpe; // apply the fluctuations in npe - - f_bbcq[arm] += npe; f_pmtq[ich] = npe; // Now time if (first_time[ich] < 9999.) { - // Fill evt histogram - hevt_bbct[arm]->Fill(first_time[ich]); - hit_times[arm].push_back(first_time[ich]); - - f_bbct[arm] += first_time[ich]; - // std::cout << "XXX " << ich << "\t" << f_bbct[arm] << "\t" << first_time[ich] << std::endl; - f_pmtt0[ich] = first_time[ich]; f_pmtt1[ich] = first_time[ich]; } @@ -257,58 +205,14 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) } } - // int ipmt = f_bbcn[0] + f_bbcn[1]; // number of hit pmt _bbcpmts->AddBbcPmt(ich, f_pmtq[ich], f_pmtt0[ich], f_pmtt1[ich]); - - // threshold should be > 0. - ++f_bbcn[arm]; + if(Verbosity() > 0) + { + std::cout << "Adding " << ich << ", " << f_pmtq[ich] << ", " << f_pmtt0[ich] <<" , " << f_pmtt1[ich] << std::endl; + } } } - // Get best t - if (f_bbcn[0] > 0 && f_bbcn[1] > 0) - { - for (int iarm = 0; iarm < 2; iarm++) - { - if (!hit_times[iarm].empty()) - { - std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); - float earliest = hit_times[iarm][0]; - - gaussian->SetParameter(0, 5); - gaussian->SetParameter(1, earliest); - gaussian->SetRange(6, earliest + 5 * 0.05); - // gaussian->SetParameter(1,hevt_bbct[iarm]->GetMean()); - // gaussian->SetRange(6,hevt_bbct[iarm]->GetMean()+0.125); - - hevt_bbct[iarm]->Fit(gaussian, "BLRNQ"); - if (f_bbcn[iarm] > 0) - { - // f_bbct[iarm] = f_bbct[iarm] / f_bbcn[iarm]; - f_bbct[iarm] = gaussian->GetParameter(1); - f_bbcte[iarm] = earliest; - - _bbcout->AddBbcNS(iarm, f_bbcn[iarm], f_bbcq[iarm], f_bbct[iarm]); - } - else - { - _bbcout->AddBbcNS(iarm, 0, -99999., -99999.); - } - } - else - { - _bbcout->AddBbcNS(iarm, 0, -99999., -99999.); - } - } - - // Now calculate zvtx, t0 from best times - f_bbcz = (f_bbct[0] - f_bbct[1]) * BbcDefs::C / 2.0; - f_bbct0 = (f_bbct[0] + f_bbct[1]) / 2.0; - - _bbcout->set_Vertex(f_bbcz, 0.6); - _bbcout->set_TimeZero(f_bbct0, 0.05); - } - return 0; } @@ -330,15 +234,6 @@ void BbcDigitization::CreateNodes(PHCompositeNode *topNode) dstNode->addNode(bbcNode); } - //-* contains final physics products (nmips, t0, etc) - _bbcout = findNode::getClass(bbcNode, "BbcOut"); - if (!_bbcout) - { - _bbcout = new BbcOutV1(); - PHIODataNode *BbcOutNode = new PHIODataNode(_bbcout, "BbcOut", "PHObject"); - bbcNode->addNode(BbcOutNode); - } - //-* contains info for each pmt (nmips, time, etc) _bbcpmts = findNode::getClass(bbcNode, "BbcPmtContainer"); if (!_bbcpmts) @@ -372,14 +267,6 @@ void BbcDigitization::GetNodes(PHCompositeNode *topNode) /** DST Objects **/ - // BbcOut data - _bbcout = findNode::getClass(topNode, "BbcOut"); - if (!_bbcout) - { - std::cout << PHWHERE << " BbcOut node not found on node tree" << std::endl; - gSystem->Exit(1); - } - // BbcPmtContainer _bbcpmts = findNode::getClass(topNode, "BbcPmtContainer"); if (!_bbcpmts) diff --git a/simulation/g4simulation/g4bbc/BbcDigitization.h b/simulation/g4simulation/g4bbc/BbcDigitization.h index 48858f1fe8..4d264e4968 100644 --- a/simulation/g4simulation/g4bbc/BbcDigitization.h +++ b/simulation/g4simulation/g4bbc/BbcDigitization.h @@ -16,7 +16,6 @@ class PHCompositeNode; class PHG4HitContainer; class PHG4TruthInfoContainer; class EventHeader; -class BbcOut; class BbcPmtContainer; class TDatabasePDG; class TRandom3; @@ -61,14 +60,7 @@ class BbcDigitization : public SubsysReco Float_t f_pmtq[128]{}; // npe in each arm Float_t f_pmtt0[128]{}; // time in each arm Float_t f_pmtt1[128]{}; // time in each arm - Short_t f_bbcn[2]{}; // num hits for each arm (north and south) - Float_t f_bbcq[2]{}; // total charge (currently npe) in each arm - Float_t f_bbct[2]{}; // time in arm - Float_t f_bbcte[2]{}; // earliest hit time in arm - Float_t f_bbcz = NAN; // z-vertex - Float_t f_bbct0 = NAN; // start time - - TH1 *hevt_bbct[2]{}; // time in each bbc, per event + TF1 *gaussian = nullptr; // @@ -84,7 +76,6 @@ class BbcDigitization : public SubsysReco PHG4HitContainer *_bbchits = nullptr; // Output to DST - BbcOut *_bbcout = nullptr; BbcPmtContainer *_bbcpmts = nullptr; }; From 5f277febba0dc936d140afbd1081836f9bb843de Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 15:50:59 -0400 Subject: [PATCH 309/468] clang-format --- offline/packages/bbc/BbcDefs.h | 9 +- offline/packages/bbc/BbcReconstruction.cc | 184 +++++++++--------- offline/packages/bbc/BbcReconstruction.h | 7 +- offline/packages/bbc/BbcVertexv2.h | 6 +- .../g4simulation/g4bbc/BbcDigitization.cc | 10 +- 5 files changed, 101 insertions(+), 115 deletions(-) diff --git a/offline/packages/bbc/BbcDefs.h b/offline/packages/bbc/BbcDefs.h index a0c7a046a6..d8ae92001d 100644 --- a/offline/packages/bbc/BbcDefs.h +++ b/offline/packages/bbc/BbcDefs.h @@ -1,8 +1,8 @@ #ifndef BBC_BBCDEFS_H #define BBC_BBCDEFS_H -#include #include +#include namespace BbcDefs { @@ -83,11 +83,6 @@ namespace BbcDefs }; */ - -} - - - - +} // namespace BbcDefs #endif diff --git a/offline/packages/bbc/BbcReconstruction.cc b/offline/packages/bbc/BbcReconstruction.cc index 613f047d6f..8b269dfd2c 100644 --- a/offline/packages/bbc/BbcReconstruction.cc +++ b/offline/packages/bbc/BbcReconstruction.cc @@ -1,7 +1,7 @@ -#include "BbcDefs.h" -#include "BbcReturnCodes.h" #include "BbcReconstruction.h" +#include "BbcDefs.h" #include "BbcPmtContainer.h" +#include "BbcReturnCodes.h" #include "BbcVertexMapv1.h" #include "BbcVertexv2.h" @@ -22,8 +22,8 @@ #include //____________________________________________________________________________.. -BbcReconstruction::BbcReconstruction(const std::string &name): - SubsysReco(name) +BbcReconstruction::BbcReconstruction(const std::string &name) + : SubsysReco(name) { } @@ -35,8 +35,7 @@ BbcReconstruction::~BbcReconstruction() //____________________________________________________________________________.. int BbcReconstruction::Init(PHCompositeNode *) { - - m_gaussian = new TF1("gaussian","gaus",0,20); + m_gaussian = new TF1("gaussian", "gaus", 0, 20); m_gaussian->FixParameter(2, m_tres); return Fun4AllReturnCodes::EVENT_OK; @@ -45,10 +44,10 @@ int BbcReconstruction::Init(PHCompositeNode *) //____________________________________________________________________________.. int BbcReconstruction::InitRun(PHCompositeNode *topNode) { - if(createNodes(topNode) == Fun4AllReturnCodes::ABORTEVENT) - { - return Fun4AllReturnCodes::ABORTEVENT; - } + if (createNodes(topNode) == Fun4AllReturnCodes::ABORTEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } int ret = getNodes(topNode); return ret; @@ -77,97 +76,91 @@ int BbcReconstruction::process_event(PHCompositeNode *) float bbcn[2] = {0}; float bbct[2] = {0}; - for(int ich = 0; ich < 128; ich++) + for (int ich = 0; ich < 128; ich++) + { + const auto pmt = m_bbcpmts->get_pmt(ich); + const int arm = pmt / 64; + auto bbchit = m_bbcpmts->get_tdc0(ich); + + if (std::isnan(m_bbcpmts->get_adc(ich))) { + //! PMT with no ADC, skip it + continue; + } + + if (bbchit < 9999.) + { + //! total charge + bbcq[arm] += m_bbcpmts->get_adc(ich); + + //! number of hit pmts + bbcn[arm]++; + + h_evt_bbct[arm]->Fill(bbchit); + hit_times[arm].push_back(bbchit); + } + if (Verbosity() > 0) + { + std::cout << "Channel " << ich << " with pmt " << pmt << " in arm " << arm << " has " << m_bbcpmts->get_adc(ich) << std::endl; + } + } + + if (Verbosity() > 0) + { + std::cout << "nbbc arm 1,2: " << bbcn[0] << ", " << bbcn[1] << std::endl; + } - const auto pmt = m_bbcpmts->get_pmt(ich); - const int arm = pmt / 64; - auto bbchit = m_bbcpmts->get_tdc0(ich); - - if(std::isnan(m_bbcpmts->get_adc(ich))) - { - //! PMT with no ADC, skip it - continue; - } - - if(bbchit < 9999.) - { - //! total charge - bbcq[arm] += m_bbcpmts->get_adc(ich); - - //! number of hit pmts - bbcn[arm]++; - - h_evt_bbct[arm]->Fill(bbchit); - hit_times[arm].push_back(bbchit); - } - if(Verbosity() > 0) - { - std::cout << "Channel " << ich << " with pmt " << pmt << " in arm " << arm << " has " << m_bbcpmts->get_adc(ich) << std::endl; - } + if (bbcn[0] > 0 && bbcn[1] > 0) + { + for (int iarm = 0; iarm < 2; iarm++) + { + if (hit_times[iarm].empty()) + { + continue; + } + + std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); + float earliest = hit_times[iarm][0]; + m_gaussian->SetParameter(0, 5); + m_gaussian->SetParameter(1, earliest); + m_gaussian->SetRange(6, earliest + 5 * m_tres); + h_evt_bbct[iarm]->Fit(m_gaussian, "BLRNQ"); + bbct[iarm] = m_gaussian->GetParameter(1); } - - if(Verbosity() > 0) + + float bbcz = (bbct[0] - bbct[1]) * BbcDefs::C / 2.; + float bbct0 = (bbct[0] + bbct[1]) / 2.; + + auto vertex = std::make_unique(); + vertex->set_t(bbct0); + vertex->set_z(bbcz); + vertex->set_z_err(0.6); + vertex->set_t_err(m_tres); + + for (int iarm = 0; iarm < 2; iarm++) { - std::cout << "nbbc arm 1,2: " << bbcn[0] << ", " << bbcn[1] << std::endl; + vertex->set_bbc_ns(iarm, bbcn[iarm], bbcq[iarm], bbct[iarm]); } - if(bbcn[0]> 0 && bbcn[1] >0) + if (Verbosity() > 0) { - for(int iarm = 0; iarm < 2; iarm++) - { - if(hit_times[iarm].empty()) - { - continue; - } - - std::sort(hit_times[iarm].begin(), hit_times[iarm].end()); - float earliest = hit_times[iarm][0]; - m_gaussian->SetParameter(0,5); - m_gaussian->SetParameter(1, earliest); - m_gaussian->SetRange(6, earliest + 5 * m_tres); - h_evt_bbct[iarm]->Fit(m_gaussian,"BLRNQ"); - bbct[iarm] = m_gaussian->GetParameter(1); - - - } - - float bbcz = (bbct[0] - bbct[1]) * BbcDefs::C /2.; - float bbct0 = (bbct[0] + bbct[1]) / 2.; - - auto vertex = std::make_unique(); - vertex->set_t(bbct0); - vertex->set_z(bbcz); - vertex->set_z_err(0.6); - vertex->set_t_err(m_tres); - - for(int iarm=0 ; iarm<2; iarm++) - { - vertex->set_bbc_ns(iarm, bbcn[iarm], bbcq[iarm], bbct[iarm]); - } - - if(Verbosity() > 0) - { - std::cout << "bbc vertex z and t0 " << bbcz << ", " - << bbct0 << std::endl; - } - - m_bbcvertexmap->insert(vertex.release()); - - } - + std::cout << "bbc vertex z and t0 " << bbcz << ", " + << bbct0 << std::endl; + } + + m_bbcvertexmap->insert(vertex.release()); + } return Fun4AllReturnCodes::EVENT_OK; } - //____________________________________________________________________________.. int BbcReconstruction::End(PHCompositeNode *) { return Fun4AllReturnCodes::EVENT_OK; } -int BbcReconstruction::createNodes(PHCompositeNode* topNode) +int BbcReconstruction::createNodes(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); @@ -184,18 +177,17 @@ int BbcReconstruction::createNodes(PHCompositeNode* topNode) dstNode->addNode(bbcNode); } - m_bbcvertexmap = findNode::getClass(bbcNode, "BbcVertexMap"); - if(!m_bbcvertexmap) - { - m_bbcvertexmap = new BbcVertexMapv1(); - PHIODataNode *VertexMapNode = new PHIODataNode(m_bbcvertexmap, "BbcVertexMap", "PHObject"); + if (!m_bbcvertexmap) + { + m_bbcvertexmap = new BbcVertexMapv1(); + PHIODataNode *VertexMapNode = new PHIODataNode(m_bbcvertexmap, "BbcVertexMap", "PHObject"); bbcNode->addNode(VertexMapNode); - } + } return Fun4AllReturnCodes::EVENT_OK; } -int BbcReconstruction::getNodes(PHCompositeNode* topNode) +int BbcReconstruction::getNodes(PHCompositeNode *topNode) { // BbcPmtContainer m_bbcpmts = findNode::getClass(topNode, "BbcPmtContainer"); @@ -206,11 +198,11 @@ int BbcReconstruction::getNodes(PHCompositeNode* topNode) } m_bbcvertexmap = findNode::getClass(topNode, "BbcVertexMap"); - if(!m_bbcvertexmap) - { - std::cout << PHWHERE << "BbcVertexMap node not found on node tree" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } + if (!m_bbcvertexmap) + { + std::cout << PHWHERE << "BbcVertexMap node not found on node tree" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/bbc/BbcReconstruction.h b/offline/packages/bbc/BbcReconstruction.h index d2c7b429bb..7c1dcb64d4 100644 --- a/offline/packages/bbc/BbcReconstruction.h +++ b/offline/packages/bbc/BbcReconstruction.h @@ -15,7 +15,6 @@ class TF1; class BbcReconstruction : public SubsysReco { public: - BbcReconstruction(const std::string &name = "BbcReconstruction"); ~BbcReconstruction() override; @@ -28,12 +27,12 @@ class BbcReconstruction : public SubsysReco private: int createNodes(PHCompositeNode *topNode); int getNodes(PHCompositeNode *topNode); - TF1* m_gaussian = nullptr; + TF1 *m_gaussian = nullptr; float m_tres = 0.05; - BbcVertexMap* m_bbcvertexmap = nullptr; + BbcVertexMap *m_bbcvertexmap = nullptr; BbcPmtContainer *m_bbcpmts = nullptr; }; -#endif // BBCRECONSTRUCTION_H +#endif // BBCRECONSTRUCTION_H diff --git a/offline/packages/bbc/BbcVertexv2.h b/offline/packages/bbc/BbcVertexv2.h index 6763283072..09591e3dca 100644 --- a/offline/packages/bbc/BbcVertexv2.h +++ b/offline/packages/bbc/BbcVertexv2.h @@ -36,15 +36,15 @@ class BbcVertexv2 : public BbcVertex void set_z_err(float z_err) override { _z_err = z_err; } void set_bbc_ns(int iarm, int bbc_npmt, float bbc_q, float bbc_t) override - { + { _bbc_ns_npmt[iarm] = bbc_npmt; _bbc_ns_q[iarm] = bbc_q; _bbc_ns_t[iarm] = bbc_t; } - + int get_bbc_npmt(int iarm) const override { return _bbc_ns_npmt[iarm]; } float get_bbc_q(int iarm) const override { return _bbc_ns_q[iarm]; } - float get_bbc_t(int iarm) const override { return _bbc_ns_t[iarm]; } + float get_bbc_t(int iarm) const override { return _bbc_ns_t[iarm]; } private: unsigned int _id; //< unique identifier within container diff --git a/simulation/g4simulation/g4bbc/BbcDigitization.cc b/simulation/g4simulation/g4bbc/BbcDigitization.cc index 39e50fd614..e52ea226fd 100644 --- a/simulation/g4simulation/g4bbc/BbcDigitization.cc +++ b/simulation/g4simulation/g4bbc/BbcDigitization.cc @@ -1,7 +1,7 @@ #include "BbcDigitization.h" -#include #include +#include #include #include @@ -206,10 +206,10 @@ int BbcDigitization::process_event(PHCompositeNode * /*topNode*/) } _bbcpmts->AddBbcPmt(ich, f_pmtq[ich], f_pmtt0[ich], f_pmtt1[ich]); - if(Verbosity() > 0) - { - std::cout << "Adding " << ich << ", " << f_pmtq[ich] << ", " << f_pmtt0[ich] <<" , " << f_pmtt1[ich] << std::endl; - } + if (Verbosity() > 0) + { + std::cout << "Adding " << ich << ", " << f_pmtq[ich] << ", " << f_pmtt0[ich] << " , " << f_pmtt1[ich] << std::endl; + } } } From c8a89d4577a5f025c0536b98685f204071b8e97c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 May 2023 16:00:09 -0400 Subject: [PATCH 310/468] cppcheck --- offline/packages/bbc/BbcReconstruction.cc | 6 ++---- offline/packages/bbc/BbcReconstruction.h | 3 ++- offline/packages/bbc/BbcVertexv2.cc | 6 ++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/offline/packages/bbc/BbcReconstruction.cc b/offline/packages/bbc/BbcReconstruction.cc index 8b269dfd2c..f8fff262a9 100644 --- a/offline/packages/bbc/BbcReconstruction.cc +++ b/offline/packages/bbc/BbcReconstruction.cc @@ -19,8 +19,6 @@ #include #include -#include - //____________________________________________________________________________.. BbcReconstruction::BbcReconstruction(const std::string &name) : SubsysReco(name) @@ -35,7 +33,7 @@ BbcReconstruction::~BbcReconstruction() //____________________________________________________________________________.. int BbcReconstruction::Init(PHCompositeNode *) { - m_gaussian = new TF1("gaussian", "gaus", 0, 20); + m_gaussian = std::make_unique("gaussian", "gaus", 0, 20); m_gaussian->FixParameter(2, m_tres); return Fun4AllReturnCodes::EVENT_OK; @@ -124,7 +122,7 @@ int BbcReconstruction::process_event(PHCompositeNode *) m_gaussian->SetParameter(0, 5); m_gaussian->SetParameter(1, earliest); m_gaussian->SetRange(6, earliest + 5 * m_tres); - h_evt_bbct[iarm]->Fit(m_gaussian, "BLRNQ"); + h_evt_bbct[iarm]->Fit(m_gaussian.get(), "BLRNQ"); bbct[iarm] = m_gaussian->GetParameter(1); } diff --git a/offline/packages/bbc/BbcReconstruction.h b/offline/packages/bbc/BbcReconstruction.h index 7c1dcb64d4..0da97c43f7 100644 --- a/offline/packages/bbc/BbcReconstruction.h +++ b/offline/packages/bbc/BbcReconstruction.h @@ -5,6 +5,7 @@ #include +#include #include class PHCompositeNode; @@ -27,7 +28,7 @@ class BbcReconstruction : public SubsysReco private: int createNodes(PHCompositeNode *topNode); int getNodes(PHCompositeNode *topNode); - TF1 *m_gaussian = nullptr; + std::unique_ptr m_gaussian = nullptr; float m_tres = 0.05; diff --git a/offline/packages/bbc/BbcVertexv2.cc b/offline/packages/bbc/BbcVertexv2.cc index dbde9aeacb..98f9d03d08 100644 --- a/offline/packages/bbc/BbcVertexv2.cc +++ b/offline/packages/bbc/BbcVertexv2.cc @@ -11,6 +11,12 @@ BbcVertexv2::BbcVertexv2() , _z(NAN) , _z_err(NAN) { + for (int i = 0; i < 2; i++) + { + _bbc_ns_npmt[i] = 0; + _bbc_ns_q[i] = NAN; + _bbc_ns_t[i] = NAN; + } } BbcVertexv2::~BbcVertexv2() = default; From c0b869ca21d0b44b241f9595bc4cd19ad016c976 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 08:48:11 -0400 Subject: [PATCH 311/468] Separate truth vertex smearing from DST global vertex objects --- .../packages/globalvertex}/GlobalVertex.cc | 0 .../packages/globalvertex}/GlobalVertex.h | 0 .../globalvertex}/GlobalVertexLinkDef.h | 0 .../packages/globalvertex}/GlobalVertexMap.cc | 0 .../packages/globalvertex}/GlobalVertexMap.h | 0 .../globalvertex}/GlobalVertexMapLinkDef.h | 0 .../globalvertex}/GlobalVertexMapv1.cc | 0 .../globalvertex}/GlobalVertexMapv1.h | 0 .../globalvertex}/GlobalVertexMapv1LinkDef.h | 0 .../globalvertex}/GlobalVertexReco.cc | 0 .../packages/globalvertex}/GlobalVertexReco.h | 0 .../packages/globalvertex}/GlobalVertexv1.cc | 0 .../packages/globalvertex}/GlobalVertexv1.h | 0 .../globalvertex}/GlobalVertexv1LinkDef.h | 0 offline/packages/globalvertex/Makefile.am | 89 +++++++++++++++++++ offline/packages/globalvertex/autogen.sh | 9 ++ offline/packages/globalvertex/configure.ac | 25 ++++++ .../g4vertex/GlobalVertexFastSimReco.cc | 8 +- simulation/g4simulation/g4vertex/Makefile.am | 39 ++------ 19 files changed, 133 insertions(+), 37 deletions(-) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertex.cc (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertex.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexLinkDef.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMap.cc (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMap.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMapLinkDef.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMapv1.cc (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMapv1.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexMapv1LinkDef.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexReco.cc (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexReco.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexv1.cc (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexv1.h (100%) rename {simulation/g4simulation/g4vertex => offline/packages/globalvertex}/GlobalVertexv1LinkDef.h (100%) create mode 100644 offline/packages/globalvertex/Makefile.am create mode 100755 offline/packages/globalvertex/autogen.sh create mode 100644 offline/packages/globalvertex/configure.ac diff --git a/simulation/g4simulation/g4vertex/GlobalVertex.cc b/offline/packages/globalvertex/GlobalVertex.cc similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertex.cc rename to offline/packages/globalvertex/GlobalVertex.cc diff --git a/simulation/g4simulation/g4vertex/GlobalVertex.h b/offline/packages/globalvertex/GlobalVertex.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertex.h rename to offline/packages/globalvertex/GlobalVertex.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexLinkDef.h b/offline/packages/globalvertex/GlobalVertexLinkDef.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexLinkDef.h rename to offline/packages/globalvertex/GlobalVertexLinkDef.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMap.cc b/offline/packages/globalvertex/GlobalVertexMap.cc similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMap.cc rename to offline/packages/globalvertex/GlobalVertexMap.cc diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMap.h b/offline/packages/globalvertex/GlobalVertexMap.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMap.h rename to offline/packages/globalvertex/GlobalVertexMap.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapLinkDef.h b/offline/packages/globalvertex/GlobalVertexMapLinkDef.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMapLinkDef.h rename to offline/packages/globalvertex/GlobalVertexMapLinkDef.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc b/offline/packages/globalvertex/GlobalVertexMapv1.cc similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMapv1.cc rename to offline/packages/globalvertex/GlobalVertexMapv1.cc diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1.h b/offline/packages/globalvertex/GlobalVertexMapv1.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMapv1.h rename to offline/packages/globalvertex/GlobalVertexMapv1.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexMapv1LinkDef.h b/offline/packages/globalvertex/GlobalVertexMapv1LinkDef.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexMapv1LinkDef.h rename to offline/packages/globalvertex/GlobalVertexMapv1LinkDef.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexReco.cc rename to offline/packages/globalvertex/GlobalVertexReco.cc diff --git a/simulation/g4simulation/g4vertex/GlobalVertexReco.h b/offline/packages/globalvertex/GlobalVertexReco.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexReco.h rename to offline/packages/globalvertex/GlobalVertexReco.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.cc b/offline/packages/globalvertex/GlobalVertexv1.cc similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexv1.cc rename to offline/packages/globalvertex/GlobalVertexv1.cc diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1.h b/offline/packages/globalvertex/GlobalVertexv1.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexv1.h rename to offline/packages/globalvertex/GlobalVertexv1.h diff --git a/simulation/g4simulation/g4vertex/GlobalVertexv1LinkDef.h b/offline/packages/globalvertex/GlobalVertexv1LinkDef.h similarity index 100% rename from simulation/g4simulation/g4vertex/GlobalVertexv1LinkDef.h rename to offline/packages/globalvertex/GlobalVertexv1LinkDef.h diff --git a/offline/packages/globalvertex/Makefile.am b/offline/packages/globalvertex/Makefile.am new file mode 100644 index 0000000000..1416a12718 --- /dev/null +++ b/offline/packages/globalvertex/Makefile.am @@ -0,0 +1,89 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -I`root-config --incdir` + +lib_LTLIBRARIES = \ + libglobalvertex_io.la \ + libglobalvertex.la + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib + +libglobalvertex_io_la_LIBADD = \ + -lphool \ + -ltrackbase_historic_io + +libglobalvertex_la_LIBADD = \ + libglobalvertex_io.la \ + -lbbc_io \ + -lg4detectors \ + -lfun4all \ + -lg4bbc_io \ + -ltrackbase_historic_io + +pkginclude_HEADERS = \ + GlobalVertex.h \ + GlobalVertexv1.h \ + GlobalVertexMap.h \ + GlobalVertexMapv1.h \ + GlobalVertexReco.h + +ROOTDICTS = \ + GlobalVertex_Dict.cc \ + GlobalVertexv1_Dict.cc \ + GlobalVertexMap_Dict.cc \ + GlobalVertexMapv1_Dict.cc + +pcmdir = $(libdir) +nobase_dist_pcm_DATA = \ + GlobalVertex_Dict_rdict.pcm \ + GlobalVertexv1_Dict_rdict.pcm \ + GlobalVertexMap_Dict_rdict.pcm \ + GlobalVertexMapv1_Dict_rdict.pcm + +libglobalvertex_io_la_SOURCES = \ + $(ROOTDICTS) \ + GlobalVertex.cc \ + GlobalVertexv1.cc \ + GlobalVertexMap.cc \ + GlobalVertexMapv1.cc + +libglobalvertex_la_SOURCES = \ + GlobalVertexReco.cc + +# Rule for generating table CINT dictionaries. +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + +################################################ +# linking tests + +noinst_PROGRAMS = \ + testexternals_globalvertex_io \ + testexternals_globalvertex + +BUILT_SOURCES = \ + testexternals.cc + +testexternals_globalvertex_io_SOURCES = testexternals.cc +testexternals_globalvertex_io_LDADD = libglobalvertex_io.la + +testexternals_globalvertex_SOURCES = testexternals.cc +testexternals_globalvertex_LDADD = libglobalvertex.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f *Dict* $(BUILT_SOURCES) *.pcm diff --git a/offline/packages/globalvertex/autogen.sh b/offline/packages/globalvertex/autogen.sh new file mode 100755 index 0000000000..333dd3b499 --- /dev/null +++ b/offline/packages/globalvertex/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" + diff --git a/offline/packages/globalvertex/configure.ac b/offline/packages/globalvertex/configure.ac new file mode 100644 index 0000000000..8d3b54a55b --- /dev/null +++ b/offline/packages/globalvertex/configure.ac @@ -0,0 +1,25 @@ +AC_INIT(globalvertex, [1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +AC_PROG_CXX(CC g++) +LT_INIT([disable-static]) + +dnl leaving this here in case we want to play with different compiler +dnl specific flags +case $CXX in + clang++) + CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra" + ;; + *g++) + CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra" + ;; +esac + + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc index c7a3ba2034..513e2737cc 100644 --- a/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc +++ b/simulation/g4simulation/g4vertex/GlobalVertexFastSimReco.cc @@ -1,9 +1,9 @@ #include "GlobalVertexFastSimReco.h" -#include "GlobalVertex.h" // for GlobalVertex -#include "GlobalVertexMap.h" // for GlobalVertexMap -#include "GlobalVertexMapv1.h" -#include "GlobalVertexv1.h" +#include // for GlobalVertex +#include // for GlobalVertexMap +#include +#include #include #include diff --git a/simulation/g4simulation/g4vertex/Makefile.am b/simulation/g4simulation/g4vertex/Makefile.am index 8cb8fe78c4..d38ae39a89 100644 --- a/simulation/g4simulation/g4vertex/Makefile.am +++ b/simulation/g4simulation/g4vertex/Makefile.am @@ -6,7 +6,6 @@ AM_CPPFLAGS = \ -I`root-config --incdir` lib_LTLIBRARIES = \ - libg4vertex_io.la \ libg4vertex.la AM_LDFLAGS = \ @@ -15,47 +14,22 @@ AM_LDFLAGS = \ libg4vertex_io_la_LIBADD = \ -lphool \ - -ltrackbase_historic_io + -ltrackbase_historic_io \ + -lglobalvertex_io libg4vertex_la_LIBADD = \ - libg4vertex_io.la \ -lbbc_io \ -lg4detectors \ -lfun4all \ -lg4bbc_io \ - -ltrackbase_historic_io + -ltrackbase_historic_io \ + -lglobalvertex_io pkginclude_HEADERS = \ - GlobalVertex.h \ - GlobalVertexv1.h \ - GlobalVertexFastSimReco.h \ - GlobalVertexMap.h \ - GlobalVertexMapv1.h \ - GlobalVertexReco.h - -ROOTDICTS = \ - GlobalVertex_Dict.cc \ - GlobalVertexv1_Dict.cc \ - GlobalVertexMap_Dict.cc \ - GlobalVertexMapv1_Dict.cc - -pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - GlobalVertex_Dict_rdict.pcm \ - GlobalVertexv1_Dict_rdict.pcm \ - GlobalVertexMap_Dict_rdict.pcm \ - GlobalVertexMapv1_Dict_rdict.pcm - -libg4vertex_io_la_SOURCES = \ - $(ROOTDICTS) \ - GlobalVertex.cc \ - GlobalVertexv1.cc \ - GlobalVertexMap.cc \ - GlobalVertexMapv1.cc + GlobalVertexFastSimReco.h libg4vertex_la_SOURCES = \ - GlobalVertexFastSimReco.cc \ - GlobalVertexReco.cc + GlobalVertexFastSimReco.cc # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h @@ -75,7 +49,6 @@ BUILT_SOURCES = \ testexternals.cc testexternals_g4vertex_io_SOURCES = testexternals.cc -testexternals_g4vertex_io_LDADD = libg4vertex_io.la testexternals_g4vertex_SOURCES = testexternals.cc testexternals_g4vertex_LDADD = libg4vertex.la From 0b973a26b8372b885962f060fa470509e67635d2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 09:01:55 -0400 Subject: [PATCH 312/468] update other packages --- .../calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc | 5 ++--- calibrations/calorimeter/calo_emc_pi0_tbt/Makefile.am | 2 +- offline/packages/CaloReco/Makefile.am | 2 +- offline/packages/CaloReco/RawClusterBuilderTemplate.cc | 4 ++-- offline/packages/ClusterIso/ClusterIso.cc | 4 ++-- offline/packages/ClusterIso/Makefile.am | 2 +- .../packages/ResonanceJetTagging/ResonanceJetTagging.cc | 4 ++-- offline/packages/particleflow/Makefile.am | 2 +- offline/packages/particleflow/ParticleFlowReco.cc | 4 ++-- simulation/g4simulation/g4eval/CaloEvaluator.cc | 4 ++-- simulation/g4simulation/g4eval/EventEvaluator.cc | 4 ++-- simulation/g4simulation/g4eval/Makefile.am | 2 +- simulation/g4simulation/g4jets/ClusterJetInput.cc | 4 ++-- simulation/g4simulation/g4jets/Makefile.am | 2 +- simulation/g4simulation/g4jets/TowerJetInput.cc | 7 ++----- 15 files changed, 24 insertions(+), 28 deletions(-) diff --git a/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc b/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc index 67ff72257a..5a729a8851 100644 --- a/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc +++ b/calibrations/calorimeter/calo_emc_pi0_tbt/CaloCalibEmc_Pi0.cc @@ -10,9 +10,8 @@ #include #include - -#include -#include +#include +#include #include #include diff --git a/calibrations/calorimeter/calo_emc_pi0_tbt/Makefile.am b/calibrations/calorimeter/calo_emc_pi0_tbt/Makefile.am index dde5a0691c..1de55f90c7 100644 --- a/calibrations/calorimeter/calo_emc_pi0_tbt/Makefile.am +++ b/calibrations/calorimeter/calo_emc_pi0_tbt/Makefile.am @@ -13,7 +13,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 \ -lHepMC \ -lCLHEP \ - -lg4vertex_io \ + -lglobalvertex_io \ -lcalo_io \ -lSubsysReco diff --git a/offline/packages/CaloReco/Makefile.am b/offline/packages/CaloReco/Makefile.am index 53f6136721..c06761e0ee 100644 --- a/offline/packages/CaloReco/Makefile.am +++ b/offline/packages/CaloReco/Makefile.am @@ -24,7 +24,7 @@ libcalo_reco_la_LIBADD = \ -lffamodules \ -lgsl \ -lgslcblas \ - -lg4vertex_io \ + -lglobalvertex_io \ -lsph_onnx \ -lsphenixnpc \ -lphparameter \ diff --git a/offline/packages/CaloReco/RawClusterBuilderTemplate.cc b/offline/packages/CaloReco/RawClusterBuilderTemplate.cc index a301574793..127027c387 100644 --- a/offline/packages/CaloReco/RawClusterBuilderTemplate.cc +++ b/offline/packages/CaloReco/RawClusterBuilderTemplate.cc @@ -6,8 +6,8 @@ #include "BEmcRecEEMC.h" #include "BEmcRecFEMC.h" -#include -#include +#include +#include #include #include diff --git a/offline/packages/ClusterIso/ClusterIso.cc b/offline/packages/ClusterIso/ClusterIso.cc index 4945b0d3f3..e7a5127820 100644 --- a/offline/packages/ClusterIso/ClusterIso.cc +++ b/offline/packages/ClusterIso/ClusterIso.cc @@ -17,8 +17,8 @@ #include #include -#include -#include +#include +#include #include // for Fun4AllBase::VERBOSITY_MORE #include diff --git a/offline/packages/ClusterIso/Makefile.am b/offline/packages/ClusterIso/Makefile.am index b4800ea48d..68b1670569 100644 --- a/offline/packages/ClusterIso/Makefile.am +++ b/offline/packages/ClusterIso/Makefile.am @@ -21,7 +21,7 @@ libclusteriso_la_SOURCES = \ libclusteriso_la_LIBADD = \ -lcalo_io \ - -lg4vertex_io \ + -lglobalvertex_io \ -lSubsysReco \ -lCLHEP diff --git a/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc b/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc index 8cbde974d0..b094ab9bb5 100644 --- a/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc +++ b/offline/packages/ResonanceJetTagging/ResonanceJetTagging.cc @@ -11,8 +11,8 @@ #include /// Tracking includes -#include -#include +#include +#include #include #include diff --git a/offline/packages/particleflow/Makefile.am b/offline/packages/particleflow/Makefile.am index de276784b0..5858fe3d03 100644 --- a/offline/packages/particleflow/Makefile.am +++ b/offline/packages/particleflow/Makefile.am @@ -53,7 +53,7 @@ libparticleflow_la_LIBADD = \ -lg4jets_io \ -ltrackbase_historic_io \ -lCLHEP \ - -lg4vertex_io \ + -lglobalvertex_io \ -lSubsysReco %_Dict.cc: %.h %LinkDef.h diff --git a/offline/packages/particleflow/ParticleFlowReco.cc b/offline/packages/particleflow/ParticleFlowReco.cc index e79933f212..4cf38fd7ba 100644 --- a/offline/packages/particleflow/ParticleFlowReco.cc +++ b/offline/packages/particleflow/ParticleFlowReco.cc @@ -3,8 +3,8 @@ #include "ParticleFlowElementContainer.h" #include "ParticleFlowElementv1.h" -#include -#include +#include +#include #include #include diff --git a/simulation/g4simulation/g4eval/CaloEvaluator.cc b/simulation/g4simulation/g4eval/CaloEvaluator.cc index e68fb1aa6c..a3b60139cb 100644 --- a/simulation/g4simulation/g4eval/CaloEvaluator.cc +++ b/simulation/g4simulation/g4eval/CaloEvaluator.cc @@ -10,8 +10,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/simulation/g4simulation/g4eval/EventEvaluator.cc b/simulation/g4simulation/g4eval/EventEvaluator.cc index 0ffdc93ee3..99dd1e3fb7 100644 --- a/simulation/g4simulation/g4eval/EventEvaluator.cc +++ b/simulation/g4simulation/g4eval/EventEvaluator.cc @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/simulation/g4simulation/g4eval/Makefile.am b/simulation/g4simulation/g4eval/Makefile.am index a13431069a..d22fc6c3c2 100644 --- a/simulation/g4simulation/g4eval/Makefile.am +++ b/simulation/g4simulation/g4eval/Makefile.am @@ -26,7 +26,7 @@ libg4eval_la_LIBADD = \ -lfun4all \ -lg4detectors_io \ -lg4jets_io \ - -lg4vertex_io \ + -lglobalvertex_io \ -lg4tracking_io \ -ltrackbase_historic_io \ -ltrack_io \ diff --git a/simulation/g4simulation/g4jets/ClusterJetInput.cc b/simulation/g4simulation/g4jets/ClusterJetInput.cc index 59e2508700..d8025bb46c 100644 --- a/simulation/g4simulation/g4jets/ClusterJetInput.cc +++ b/simulation/g4simulation/g4jets/ClusterJetInput.cc @@ -10,8 +10,8 @@ #include #include -#include -#include +#include +#include #include // for Hep3Vector diff --git a/simulation/g4simulation/g4jets/Makefile.am b/simulation/g4simulation/g4jets/Makefile.am index 4001f7d99d..fdf0134ed3 100644 --- a/simulation/g4simulation/g4jets/Makefile.am +++ b/simulation/g4simulation/g4jets/Makefile.am @@ -29,7 +29,7 @@ libg4jets_la_LIBADD = \ -lfun4all \ -lphg4hit \ -lcalo_io \ - -lg4vertex_io \ + -lglobalvertex_io \ -lRecursiveTools \ -lphhepmc_io \ -ltrackbase_historic_io diff --git a/simulation/g4simulation/g4jets/TowerJetInput.cc b/simulation/g4simulation/g4jets/TowerJetInput.cc index 88c6c714b8..06b37b7db7 100644 --- a/simulation/g4simulation/g4jets/TowerJetInput.cc +++ b/simulation/g4simulation/g4jets/TowerJetInput.cc @@ -6,18 +6,15 @@ #include #include - #include #include - - #include // for encode_towerid #include #include -#include -#include +#include +#include #include From a375359e9231e6365d5d19080e8c6de4794007ed Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 09:18:03 -0400 Subject: [PATCH 313/468] Clean up bbcout remnants --- .../packages/globalvertex/GlobalVertexReco.cc | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 85324f9fff..36fdb2637a 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -8,8 +8,6 @@ #include #include -#include - #include #include #include @@ -67,36 +65,6 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" << endl; exit(-1); } - // just patch in the new bbc vertex - BbcOut *bbcout = findNode::getClass(topNode, "BbcOut"); - if (bbcout) - { - GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::BBC); - - vertex->set_x(_xdefault); - vertex->set_y(_ydefault); - vertex->set_z(bbcout->get_VertexPoint()); - - vertex->set_t(bbcout->get_TimeZero()); - vertex->set_t_err(bbcout->get_dTimeZero()); - - vertex->set_error(0, 0, _xerr * _xerr); - vertex->set_error(0, 1, 0.0); - vertex->set_error(0, 2, 0.0); - - vertex->set_error(1, 1, 0.0); - vertex->set_error(1, 1, _yerr * _yerr); - vertex->set_error(1, 2, 0.0); - - vertex->set_error(2, 0, 0.0); - vertex->set_error(2, 1, 0.0); - vertex->set_error(2, 2, bbcout->get_dTimeZero() * bbcout->get_dTimeZero()); - if (Verbosity() > 1) - { - vertex->identify(); - } - globalmap->insert(vertex); - } SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); BbcVertexMap *bbcmap = findNode::getClass(topNode, "BbcVertexMap"); @@ -221,10 +189,6 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } - // default time could also come from somewhere else at some point - vertex->set_t(_tdefault); - vertex->set_t_err(_terr); - vertex->set_chisq(svtx->get_chisq()); vertex->set_ndof(svtx->get_ndof()); From f62f359aba2e3eb701609ce2ff8ee273e7322945 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 10:41:22 -0400 Subject: [PATCH 314/468] Have tracks point to global vertex object instead of SvtxVertex object --- .../packages/globalvertex/GlobalVertexReco.cc | 73 +++++++++++++------ .../g4simulation/g4eval/SvtxEvaluator.cc | 41 ++++++++--- .../g4simulation/g4eval/SvtxEvaluator.h | 3 +- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 36fdb2637a..0aa8a728aa 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -68,6 +68,13 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); BbcVertexMap *bbcmap = findNode::getClass(topNode, "BbcVertexMap"); + SvtxTrackMap *trackmap = findNode::getClass(topNode, "SvtxTrackMap"); + if(!trackmap) + { + std::cout << PHWHERE << "No track map, can't continue." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + // we will make 3 different kinds of global vertexes // (1) SVTX+BBC vertexes - we match SVTX vertex to the nearest BBC vertex within 3 sigma in zvertex // the spatial point comes from the SVTX, the timing from the BBC @@ -86,7 +93,8 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) std::set used_svtx_vtxids; std::set used_bbc_vtxids; - + int global_vertex_id = 0; + if (svtxmap && bbcmap) { if (Verbosity()) @@ -144,9 +152,20 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) used_svtx_vtxids.insert(svtx->get_id()); vertex->insert_vtxids(GlobalVertex::BBC, bbc_best->get_id()); used_bbc_vtxids.insert(bbc_best->get_id()); - + vertex->set_id(global_vertex_id); + globalmap->insert(vertex); + //! Reset track ids to the new vertex object + for(auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } + + global_vertex_id++; + if (Verbosity() > 1) { vertex->identify(); @@ -180,6 +199,9 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) // we have a standalone SVTX vertex GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX); + vertex->set_id(global_vertex_id); + global_vertex_id++; + for (unsigned int i = 0; i < 3; ++i) { vertex->set_position(i, svtx->get_position(i)); @@ -195,8 +217,16 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) vertex->insert_vtxids(GlobalVertex::SVTX, svtx->get_id()); used_svtx_vtxids.insert(svtx->get_id()); - globalmap->insert(vertex); + //! Reset track ids to the new vertex object + for(auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } + globalmap->insert(vertex); + if (Verbosity() > 1) { vertex->identify(); @@ -228,7 +258,9 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); - + vertex->set_id(global_vertex_id); + global_vertex_id++; + // nominal beam location // could be replaced with a beam spot some day vertex->set_x(_xdefault); @@ -263,36 +295,35 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } /// Associate any tracks that were not assigned a track-vertex - auto trackmap = findNode::getClass(topNode, "SvtxTrackMap"); - if (trackmap) - { - for (const auto &[tkey, track] : *trackmap) + for (const auto &[tkey, track] : *trackmap) { //! Check that the vertex hasn't already been assigned auto trackvtxid = track->get_vertex_id(); - if(svtxmap->get(trackvtxid) != nullptr) + if(globalmap->find(trackvtxid)->second != nullptr) { continue; } + float maxdz = std::numeric_limits::max(); unsigned int vtxid = std::numeric_limits::max(); for (const auto &[vkey, vertex] : *globalmap) - { - float dz = track->get_z() - vertex->get_z(); - if (fabs(dz) < maxdz) - { - maxdz = dz; - vtxid = vkey; - } - } + { + float dz = track->get_z() - vertex->get_z(); + if (fabs(dz) < maxdz) + { + maxdz = dz; + vtxid = vkey; + } + } + track->set_vertex_id(vtxid); if (Verbosity()) - { - std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; - } + { + std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; + } } - } + if (Verbosity()) { diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 1455d48438..a02fd52965 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -27,11 +27,14 @@ #include #include -#include #include +#include #include #include +#include +#include + #include #include #include @@ -976,6 +979,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) _timer->restart(); } + GlobalVertexMap* gvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); SvtxVertexMap* vertexmap = nullptr; if(_use_initial_vertex) vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); @@ -986,7 +990,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) PHG4TruthInfoContainer* truthinfo = findNode::getClass(topNode, "G4TruthInfo"); - if (vertexmap && truthinfo) + if (gvertexmap && vertexmap && truthinfo) { const auto prange = truthinfo->GetPrimaryParticleRange(); map embedvtxid_particle_count; @@ -1088,11 +1092,19 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ++ngembed; } - for (SvtxVertexMap::Iter iter = vertexmap->begin(); - iter != vertexmap->end(); + for (auto iter = gvertexmap->begin(); + iter != gvertexmap->end(); ++iter) { - SvtxVertex* vertex = iter->second; + GlobalVertex* gvertex = iter->second; + auto svtxv = gvertex->find_vtxids(GlobalVertex::SVTX); + // check that it contains a track vertex + if(svtxv == gvertex->end_vtxids()) + { continue; } + + auto svtxvertexid = svtxv->second; + auto vertex = vertexmap->find(svtxvertexid)->second; + PHG4VtxPoint* point = vertexeval->max_truth_point_by_ntracks(vertex); int vertexID = vertex->get_id(); float vx = vertex->get_x(); @@ -2516,7 +2528,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } PHG4TruthInfoContainer* truthinfo = findNode::getClass(topNode, "G4TruthInfo"); - SvtxVertexMap *vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); + GlobalVertexMap *gvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if (truthinfo) { @@ -2914,14 +2927,16 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) << endl; */ + // this is the global vertex id vertexID = track->get_vertex_id(); - SvtxVertex* vertex = vertexmap->get(vertexID); + + GlobalVertex* vertex = gvertexmap->get(vertexID); if(vertex) { vx = vertex->get_x(); vy = vertex->get_y(); vz = vertex->get_z(); - get_dca(track, vertexmap, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma); + get_dca(track, gvertexmap, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma); } px = track->get_px(); @@ -3111,7 +3126,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) // need things off of the DST... SvtxTrackMap* trackmap = findNode::getClass(topNode, _trackmapname.c_str()); - SvtxVertexMap *vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); + + GlobalVertexMap *gvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); if (trackmap) { @@ -3279,8 +3295,9 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) dca3dxysigma = NAN, dca3dzsigma = NAN; float dca2d = NAN, dca2dsigma = NAN; + /// this is the global vertex int vertexID = track->get_vertex_id(); - SvtxVertex* vertex = vertexmap->get(vertexID); + GlobalVertex* vertex = gvertexmap->get(vertexID); float vx = NAN; float vy = NAN; float vz = NAN; @@ -3289,7 +3306,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) vy = vertex->get_y(); vz = vertex->get_z(); - get_dca(track, vertexmap, dca3dxy, dca3dz, + get_dca(track, gvertexmap, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma); } float px = track->get_px(); @@ -3778,7 +3795,7 @@ TMatrixF SvtxEvaluator::calculateClusterError(TrkrCluster* c, float& clusphi) } -void SvtxEvaluator::get_dca(SvtxTrack* track, SvtxVertexMap* vertexmap, +void SvtxEvaluator::get_dca(SvtxTrack* track, GlobalVertexMap* vertexmap, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma) { diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.h b/simulation/g4simulation/g4eval/SvtxEvaluator.h index ca3b58189a..cfd4448d0e 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.h +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.h @@ -22,6 +22,7 @@ class TFile; class TNtuple; class SvtxTrack; class SvtxVertexMap; +class GlobalVertexMap; //class TrkrClusterContainer; @@ -80,7 +81,7 @@ class SvtxEvaluator : public SubsysReco SvtxEvalStack *_svtxevalstack; TMatrixF calculateClusterError(TrkrCluster* c, float& clusphi); - void get_dca(SvtxTrack* track, SvtxVertexMap* vertexmap, + void get_dca(SvtxTrack* track, GlobalVertexMap* vertexmap, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma); //TrkrClusterContainer *cluster_map{nullptr}; From 4327c032d5c0340258bba417dbb2bdfa11ebbd3f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 10:54:22 -0400 Subject: [PATCH 315/468] clang-format --- .../packages/globalvertex/GlobalVertexReco.cc | 93 +++++++++---------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 0aa8a728aa..180f4398b5 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -69,11 +69,11 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); BbcVertexMap *bbcmap = findNode::getClass(topNode, "BbcVertexMap"); SvtxTrackMap *trackmap = findNode::getClass(topNode, "SvtxTrackMap"); - if(!trackmap) - { - std::cout << PHWHERE << "No track map, can't continue." << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } + if (!trackmap) + { + std::cout << PHWHERE << "No track map, can't continue." << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } // we will make 3 different kinds of global vertexes // (1) SVTX+BBC vertexes - we match SVTX vertex to the nearest BBC vertex within 3 sigma in zvertex @@ -94,7 +94,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) std::set used_svtx_vtxids; std::set used_bbc_vtxids; int global_vertex_id = 0; - + if (svtxmap && bbcmap) { if (Verbosity()) @@ -153,16 +153,16 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) vertex->insert_vtxids(GlobalVertex::BBC, bbc_best->get_id()); used_bbc_vtxids.insert(bbc_best->get_id()); vertex->set_id(global_vertex_id); - + globalmap->insert(vertex); //! Reset track ids to the new vertex object - for(auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); - ++iter) - { - auto track = trackmap->find(*iter)->second; - track->set_vertex_id(vertex->get_id()); - } + for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } global_vertex_id++; @@ -201,7 +201,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) vertex->set_id(global_vertex_id); global_vertex_id++; - + for (unsigned int i = 0; i < 3; ++i) { vertex->set_position(i, svtx->get_position(i)); @@ -218,15 +218,15 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) used_svtx_vtxids.insert(svtx->get_id()); //! Reset track ids to the new vertex object - for(auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); - ++iter) - { - auto track = trackmap->find(*iter)->second; - track->set_vertex_id(vertex->get_id()); - } + for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } globalmap->insert(vertex); - + if (Verbosity() > 1) { vertex->identify(); @@ -260,7 +260,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); vertex->set_id(global_vertex_id); global_vertex_id++; - + // nominal beam location // could be replaced with a beam spot some day vertex->set_x(_xdefault); @@ -296,34 +296,33 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) /// Associate any tracks that were not assigned a track-vertex for (const auto &[tkey, track] : *trackmap) + { + //! Check that the vertex hasn't already been assigned + auto trackvtxid = track->get_vertex_id(); + if (globalmap->find(trackvtxid)->second != nullptr) + { + continue; + } + + float maxdz = std::numeric_limits::max(); + unsigned int vtxid = std::numeric_limits::max(); + + for (const auto &[vkey, vertex] : *globalmap) { - //! Check that the vertex hasn't already been assigned - auto trackvtxid = track->get_vertex_id(); - if(globalmap->find(trackvtxid)->second != nullptr) - { - continue; - } - - float maxdz = std::numeric_limits::max(); - unsigned int vtxid = std::numeric_limits::max(); - - for (const auto &[vkey, vertex] : *globalmap) - { - float dz = track->get_z() - vertex->get_z(); - if (fabs(dz) < maxdz) - { - maxdz = dz; - vtxid = vkey; - } - } - - track->set_vertex_id(vtxid); - if (Verbosity()) - { - std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; - } + float dz = track->get_z() - vertex->get_z(); + if (fabs(dz) < maxdz) + { + maxdz = dz; + vtxid = vkey; + } } + track->set_vertex_id(vtxid); + if (Verbosity()) + { + std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; + } + } if (Verbosity()) { From 1023a11f81403049701869cd772625ed63545001 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 May 2023 13:17:17 -0400 Subject: [PATCH 316/468] update kfparticle to use globalvertex --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 27 +++++++++++++++---- .../KFParticle_truthAndDetTools.cc | 23 ++++++++++++---- .../KFParticle_truthAndDetTools.h | 4 ++- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 1e229d1799..a6654b9e03 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -32,6 +32,9 @@ #include #include +#include +#include + #include //KFParticle stuff @@ -121,14 +124,26 @@ std::vector KFParticle_Tools::makeAllPrimaryVertices(PHCompositeNode std::vector primaryVertices; m_dst_vertexmap = findNode::getClass(topNode, vtxMN); + auto globalvertexmap = findNode::getClass(topNode,"GlobalVertexMap"); + if(!globalvertexmap) { + std::cout << "Can't continue in KFParticle_Tools::makeAllPrimaryVertices" << std::endl; + } + unsigned int vertexID = 0; - for (SvtxVertexMap::ConstIter iter = m_dst_vertexmap->begin(); iter != m_dst_vertexmap->end(); ++iter) + for (GlobalVertexMap::ConstIter iter = globalvertexmap->begin(); iter != globalvertexmap->end(); ++iter) { - m_dst_vertex = iter->second; + GlobalVertex *gvertex = iter->second; + auto svtxv = gvertex->find_vtxids(GlobalVertex::SVTX); + // check that it contains a track vertex + if(svtxv == gvertex->end_vtxids()) + { continue; } + + auto svtxvertexid = svtxv->second; + m_dst_vertex = m_dst_vertexmap->find(svtxvertexid)->second; primaryVertices.push_back(makeVertex(topNode)); - primaryVertices[vertexID].SetId(iter->first); + primaryVertices[vertexID].SetId(gvertex->get_id()); ++vertexID; } @@ -221,8 +236,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, KFParticle v SvtxVertex *associatedVertex = NULL; m_dst_vertexmap = findNode::getClass(topNode, vtxMN); - - associatedVertex = m_dst_vertexmap->find(vertex.Id())->second; + auto globalvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + GlobalVertex *associatedgvertex = globalvertexmap->find(vertex.Id())->second; + auto svtxvtx_id = associatedgvertex->find_vtxids(GlobalVertex::SVTX)->second; + associatedVertex = m_dst_vertexmap->find(svtxvtx_id)->second; return associatedVertex->size_tracks(); } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc index 81f4c966fe..c60ab315cb 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc @@ -19,6 +19,9 @@ #include // for SvtxVertex #include // for SvtxVertexMap, SvtxVer... +#include +#include + #include // for PHG4Particle #include // for PHG4TruthInfoContainer #include // for PHG4VtxPoint @@ -84,9 +87,9 @@ SvtxTrack *KFParticle_truthAndDetTools::getTrack(unsigned int track_id, SvtxTrac return matched_track; } -SvtxVertex *KFParticle_truthAndDetTools::getVertex(unsigned int vertex_id, SvtxVertexMap *vertexmap) +GlobalVertex *KFParticle_truthAndDetTools::getVertex(unsigned int vertex_id, GlobalVertexMap *vertexmap) { - SvtxVertex *matched_vertex = vertexmap->get(vertex_id); + GlobalVertex *matched_vertex = vertexmap->get(vertex_id); return matched_vertex; } @@ -197,7 +200,10 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre { std::cout << "KFParticle truth matching: " << m_vtx_map_node_name_nTuple << " does not exist" << std::endl; } - + auto globalvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if(!globalvertexmap) { + std::cout << "KFParticle truth matching: GlobalVertexMap does not exist" << std::endl; + } track = getTrack(daughter.Id(), dst_trackmap); g4particle = getTruthTrack(track, topNode); @@ -238,8 +244,15 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre if (m_constrain_to_vertex_truthMatch) { //Calculate true DCA - SvtxVertex *recoVertex = getVertex(vertex.Id(), dst_vertexmap); - PHG4VtxPoint *truePoint = vertexeval->max_truth_point_by_ntracks(recoVertex); + GlobalVertex *recoVertex = getVertex(vertex.Id(), globalvertexmap); + auto svtxv = recoVertex->find_vtxids(GlobalVertex::SVTX); + if(svtxv == recoVertex->end_vtxids()) + { + std::cout << "Have a global vertex with no track vertex... shouldn't happen in KFParticle_truthAndDetTools::fillTruthBranch..." << std::endl; + } + + SvtxVertex* svtxvertex = dst_vertexmap->find(svtxv->second)->second; + PHG4VtxPoint *truePoint = vertexeval->max_truth_point_by_ntracks(svtxvertex); KFParticle trueKFParticleVertex; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h index 2316f8e934..7022f32531 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h @@ -23,6 +23,8 @@ class SvtxVertexEval; class TrkrClusterContainer; class TTree; class KFParticle; +class GlobalVertex; +class GlobalVertexMap; namespace HepMC { @@ -37,7 +39,7 @@ class KFParticle_truthAndDetTools virtual ~KFParticle_truthAndDetTools(); //Destructor SvtxTrack *getTrack(unsigned int track_id, SvtxTrackMap *trackmap); - SvtxVertex *getVertex(unsigned int vertex_id, SvtxVertexMap *vertexmap); + GlobalVertex *getVertex(unsigned int vertex_id, GlobalVertexMap *vertexmap); PHG4Particle *getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode); void initializeTruthBranches(TTree *m_tree, int daughter_id, std::string daughter_number, bool m_constrain_to_vertex_truthMatch); From 25b2dc6921d51a51bd2f1209c606235ed85fefae Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Tue, 2 May 2023 13:17:51 -0400 Subject: [PATCH 317/468] Major updates to the track matching --- .../g4eval/FillTruthRecoMatchTree.cc | 516 ++++++++---------- .../g4eval/FillTruthRecoMatchTree.h | 187 ++++--- simulation/g4simulation/g4eval/Makefile.am | 4 +- .../g4eval/TruthRecoTrackMatching.cc | 2 +- .../g4eval/TruthRecoTrackMatching.h | 2 +- .../g4eval/{g4tools.cc => g4evaltools.cc} | 62 ++- .../g4eval/{g4tools.h => g4evaltools.h} | 35 +- .../g4simulation/g4intt/PHG4InttHitReco.cc | 49 +- .../g4simulation/g4intt/PHG4InttHitReco.h | 9 +- .../g4simulation/g4mvtx/PHG4MvtxHitReco.cc | 50 +- .../g4simulation/g4mvtx/PHG4MvtxHitReco.h | 17 +- .../g4tpc/PHG4TpcElectronDrift.cc | 67 ++- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 19 +- .../g4simulation/g4tpc/PHG4TpcPadPlane.h | 2 +- .../g4tpc/PHG4TpcPadPlaneReadout.cc | 4 +- .../g4tpc/PHG4TpcPadPlaneReadout.h | 2 +- .../g4simulation/g4tpc/TpcClusterBuilder.cc | 194 +++++-- .../g4simulation/g4tpc/TpcClusterBuilder.h | 51 +- 18 files changed, 726 insertions(+), 546 deletions(-) rename simulation/g4simulation/g4eval/{g4tools.cc => g4evaltools.cc} (89%) rename simulation/g4simulation/g4eval/{g4tools.h => g4evaltools.h} (82%) diff --git a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc index ce041e8d9b..47623a7eb9 100644 --- a/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc +++ b/simulation/g4simulation/g4eval/FillTruthRecoMatchTree.cc @@ -29,7 +29,7 @@ using std::cout; using std::endl; //____________________________________________________________________________.. FillTruthRecoMatchTree::FillTruthRecoMatchTree( - bool _fill_clusters + bool _fill_clusters , bool _fill_SvUnMatched , float _cluster_nzwidths , float _cluster_nphiwidths @@ -37,13 +37,13 @@ FillTruthRecoMatchTree::FillTruthRecoMatchTree( ) : m_cluster_comp { _cluster_nphiwidths, _cluster_nzwidths } - , m_fill_clusters { _fill_clusters } - , m_fill_SvU { _fill_SvUnMatched } - , m_outfile_name { _outfile_name } + , m_fill_clusters { _fill_clusters } + , m_fill_SvU { _fill_SvUnMatched } + , m_outfile_name { _outfile_name } { m_cluscntr.set_comparer(&m_cluster_comp); - PHTFileServer::get().open(m_outfile_name, "RECREATE"); - + PHTFileServer::get().open(m_outfile_name, "RECREATE"); + h2_G4_nPixelsPhi = new TH2D("G4_nPixelsPhi", "PHG4 Emb Tracks; cluster pixel width Phi; layer", 100, -0.5, 99.5, 56, -0.5, 55.5); h2_G4_nPixelsZ = new TH2D("G4_nPixelsZ", "PHG4 Emb Tracks; cluster pixel width Z; layer", @@ -62,91 +62,34 @@ FillTruthRecoMatchTree::FillTruthRecoMatchTree( m_ttree->Branch("nphg4", &nphg4); m_ttree->Branch("nsvtx", &nsvtx); - m_ttree->Branch("G4M_trackid", &b_G4M_trackid); - m_ttree->Branch("G4M_nclus", &b_G4M_nclus); - m_ttree->Branch("G4M_nclusmvtx", &b_G4M_nclusmvtx); - m_ttree->Branch("G4M_nclusintt", &b_G4M_nclusintt); - m_ttree->Branch("G4M_nclustpc", &b_G4M_nclustpc); - m_ttree->Branch("G4M_nclus_matchrat", &b_G4M_nclus_matchrat); - m_ttree->Branch("G4M_nclusmvtx_matchrat", &b_G4M_nclusmvtx_matchrat); - m_ttree->Branch("G4M_nclusintt_matchrat", &b_G4M_nclusintt_matchrat); - m_ttree->Branch("G4M_nclustpc_matchrat", &b_G4M_nclustpc_matchrat); - m_ttree->Branch("G4M_pt", &b_G4M_pt); - m_ttree->Branch("G4M_phi", &b_G4M_phi); - m_ttree->Branch("G4M_eta", &b_G4M_eta); - m_ttree->Branch("SvM_trackid", &b_SvM_trackid); - m_ttree->Branch("SvM_nclus", &b_SvM_nclus); - m_ttree->Branch("SvM_nclusmvtx", &b_SvM_nclusmvtx); - m_ttree->Branch("SvM_nclusintt", &b_SvM_nclusintt); - m_ttree->Branch("SvM_nclustpc", &b_SvM_nclustpc); - m_ttree->Branch("SvM_nclus_matchrat", &b_SvM_nclus_matchrat); - m_ttree->Branch("SvM_nclusmvtx_matchrat", &b_SvM_nclusmvtx_matchrat); - m_ttree->Branch("SvM_nclusintt_matchrat", &b_SvM_nclusintt_matchrat); - m_ttree->Branch("SvM_nclustpc_matchrat", &b_SvM_nclustpc_matchrat); - m_ttree->Branch("SvM_pt", &b_SvM_pt); - m_ttree->Branch("SvM_phi", &b_SvM_phi); - m_ttree->Branch("SvM_eta", &b_SvM_eta); - if (m_fill_clusters) { - m_ttree->Branch("clusM_i0", &b_clusM_i0); - m_ttree->Branch("clusM_i1", &b_clusM_i1); - m_ttree->Branch("clusM_layer", &b_clusM_layer); - m_ttree->Branch("clusM_x", &b_clusM_x); - m_ttree->Branch("clusM_y", &b_clusM_y); - m_ttree->Branch("clusM_z", &b_clusM_z); - m_ttree->Branch("clusM_r", &b_clusM_r); - m_ttree->Branch("G4M_clusU_i0", &b_G4M_clusU_i0); - m_ttree->Branch("G4M_clusU_i1", &b_G4M_clusU_i1); - m_ttree->Branch("G4M_clusU_layer", &b_G4M_clusU_layer); - m_ttree->Branch("G4M_clusU_x", &b_G4M_clusU_x); - m_ttree->Branch("G4M_clusU_y", &b_G4M_clusU_y); - m_ttree->Branch("G4M_clusU_z", &b_G4M_clusU_z); - m_ttree->Branch("G4M_clusU_r", &b_G4M_clusU_r); - m_ttree->Branch("SvM_clusU_i0", &b_SvM_clusU_i0); - m_ttree->Branch("SvM_clusU_i1", &b_SvM_clusU_i1); - m_ttree->Branch("SvM_clusU_layer", &b_SvM_clusU_layer); - m_ttree->Branch("SvM_clusU_x", &b_SvM_clusU_x); - m_ttree->Branch("SvM_clusU_y", &b_SvM_clusU_y); - m_ttree->Branch("SvM_clusU_z", &b_SvM_clusU_z); - m_ttree->Branch("SvM_clusU_r", &b_SvM_clusU_r); - } - m_ttree->Branch("G4U_trackid", &b_G4U_trackid); - m_ttree->Branch("G4U_nclus", &b_G4U_nclus); - m_ttree->Branch("G4U_nclusmvtx", &b_G4U_nclusmvtx); - m_ttree->Branch("G4U_nclusintt", &b_G4U_nclusintt); - m_ttree->Branch("G4U_nclustpc", &b_G4U_nclustpc); - m_ttree->Branch("G4U_pt", &b_G4U_pt); - m_ttree->Branch("G4U_phi", &b_G4U_phi); - m_ttree->Branch("G4U_eta", &b_G4U_eta); - if (m_fill_SvU) { - m_ttree->Branch("SvU_trackid", &b_SvU_trackid); - m_ttree->Branch("SvU_nclus", &b_SvU_nclus); - m_ttree->Branch("SvU_nclusmvtx", &b_SvU_nclusmvtx); - m_ttree->Branch("SvU_nclusintt", &b_SvU_nclusintt); - m_ttree->Branch("SvU_nclustpc", &b_SvU_nclustpc); - m_ttree->Branch("SvU_pt", &b_SvU_pt); - m_ttree->Branch("SvU_phi", &b_SvU_phi); - m_ttree->Branch("SvU_eta", &b_SvU_eta); - } - if (m_fill_clusters) { - m_ttree->Branch("G4U_clusU_i0", &b_G4U_clusU_i0); - m_ttree->Branch("G4U_clusU_i1", &b_G4U_clusU_i1); - m_ttree->Branch("G4U_clusU_layer", &b_G4U_clusU_layer); - m_ttree->Branch("G4U_clusU_x", &b_G4U_clusU_x); - m_ttree->Branch("G4U_clusU_y", &b_G4U_clusU_y); - m_ttree->Branch("G4U_clusU_z", &b_G4U_clusU_z); - m_ttree->Branch("G4U_clusU_r", &b_G4U_clusU_r); - if (m_fill_SvU) { - m_ttree->Branch("SvU_clusU_i0", &b_SvU_clusU_i0); - m_ttree->Branch("SvU_clusU_i1", &b_SvU_clusU_i1); - m_ttree->Branch("SvU_clusU_layer", &b_SvU_clusU_layer); - m_ttree->Branch("SvU_clusU_x", &b_SvU_clusU_x); - m_ttree->Branch("SvU_clusU_y", &b_SvU_clusU_y); - m_ttree->Branch("SvU_clusU_z", &b_SvU_clusU_z); - m_ttree->Branch("SvU_clusU_r", &b_SvU_clusU_r); - } - } + m_ttree ->Branch("trackid" , &b_trackid ); + m_ttree ->Branch("is_G4track" , &b_is_g4track ); + m_ttree ->Branch("is_Svtrack" , &b_is_Svtrack ); + m_ttree ->Branch("is_matched" , &b_is_matched ); + + m_ttree ->Branch("trkpt" , &b_trkpt ); + m_ttree ->Branch("trketa" , &b_trketa ); + m_ttree ->Branch("trkphi" , &b_trkphi ); + m_ttree ->Branch("nclus" , &b_nclus ); + m_ttree ->Branch("nclustpc" , &b_nclustpc ); + m_ttree ->Branch("nclusmvtx" , &b_nclusmvtx ); + m_ttree ->Branch("nclusintt" , &b_nclusintt ); + m_ttree ->Branch("matchrat" , &b_matchrat ); + m_ttree ->Branch("matchrat_intt" , &b_matchrat_intt ); + m_ttree ->Branch("matchrat_mvtx" , &b_matchrat_mvtx ); + m_ttree ->Branch("matchrat_tpc" , &b_matchrat_tpc ); + if (m_fill_clusters) { + m_ttree ->Branch("clus_match" , &b_clusmatch ); + m_ttree ->Branch("clus_x" , &b_clus_x ); + m_ttree ->Branch("clus_y" , &b_clus_y ); + m_ttree ->Branch("clus_z" , &b_clus_z ); + m_ttree ->Branch("clus_r" , &b_clus_r ); + m_ttree ->Branch("clus_layer" , &b_clus_layer ); + m_ttree ->Branch("nphibins" , &b_clus_nphibins ); + m_ttree ->Branch("nzbins" , &b_clus_ntbins ); + } } //____________________________________________________________________________.. @@ -263,9 +206,8 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) nsvtx = m_SvtxTrackMap ->size(); ntrackmatches = m_EmbRecoMatchContainer->getMatches().size(); // get centrality later... - + // fill in pixel widths on truth tracks - for (auto hitsetkey : m_cluscntr.get_PHG4_clusters()->getHitSetKeys()) { float layer = (float) TrkrDefs::getLayer(hitsetkey); auto range = m_cluscntr.get_PHG4_clusters()->getClusters(hitsetkey); @@ -287,7 +229,7 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) } nphg4_part = 0; - const auto range = m_PHG4TruthInfoContainer->GetPrimaryParticleRange(); + const auto range = m_PHG4TruthInfoContainer->GetPrimaryParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { nphg4_part++; } @@ -301,160 +243,215 @@ int FillTruthRecoMatchTree::process_event(PHCompositeNode * /*topNode*/) // (1) fill unmatched phg4 // (2) fill unmatched svtx // (3) fill matched phg4 and svtx - clear_vectors(); - int index_G4M_clusU {0}; - int index_SvM_clusU {0}; - int i_matched {0}; - int index_G4U_clusU {0}; - int index_SvU_clusU {0}; - + clear_clusvecs(" nothing "); + if (Verbosity() > 2) std::cout << " getting" << (int) m_EmbRecoMatchContainer->getMatches().size() << std::endl; for (auto& match : m_EmbRecoMatchContainer->getMatches()) { - unsigned int g4_trkid = match->idTruthTrack(); int sv_trkid = match->idRecoTrack(); auto g4trk = m_TrkrTruthTrackContainer->getTruthTrack(g4_trkid); auto svtrk = m_SvtxTrackMap->get(sv_trkid); - b_G4M_trackid .push_back(g4_trkid); - b_G4M_pt .push_back(g4trk->getPt()); - b_G4M_eta .push_back(g4trk->getPseudoRapidity()); - b_G4M_phi .push_back(g4trk->getPhi()); - - b_SvM_trackid .push_back(sv_trkid); - b_SvM_pt .push_back(svtrk->get_pt()); - b_SvM_eta .push_back(svtrk->get_eta()); - b_SvM_phi .push_back(svtrk->get_phi()); - m_cluscntr.addClusKeys( g4trk ); m_cluscntr.addClusKeys( svtrk ); m_cluscntr.find_matches(); + // <- <- <- <- G4 Matched Tracks + b_is_matched = true; + b_is_g4track = true; + b_is_Svtrack = false; + + b_trackid = g4_trkid; + b_trkpt = g4trk->getPt(); + b_trketa = g4trk->getPseudoRapidity(); + b_trkphi = g4trk->getPhi(); + auto cnt = m_cluscntr.phg4_cntclus(); - b_G4M_nclus .push_back( cnt[4] ); - b_G4M_nclusmvtx .push_back( cnt[0] ); - b_G4M_nclusintt .push_back( cnt[1] ); - b_G4M_nclustpc .push_back( cnt[2] ); auto cnt_match = m_cluscntr.phg4_cnt_matchedclus(); - b_G4M_nclus_matchrat .push_back( (float)cnt_match[4] / cnt[4] ); - b_G4M_nclusmvtx_matchrat .push_back( (float)cnt_match[0] / cnt[0] ); - b_G4M_nclusintt_matchrat .push_back( (float)cnt_match[1] / cnt[1] ); - b_G4M_nclustpc_matchrat .push_back( (float)cnt_match[2] / cnt[2] ); - cnt = m_cluscntr.svtx_cntclus(); - b_SvM_nclus .push_back( cnt[4] ); - b_SvM_nclusmvtx .push_back( cnt[0] ); - b_SvM_nclusintt .push_back( cnt[1] ); - b_SvM_nclustpc .push_back( cnt[2] ); - cnt_match = m_cluscntr.svtx_cnt_matchedclus(); - b_SvM_nclus_matchrat .push_back( (float)cnt_match[4] / cnt[4] ); - b_SvM_nclusmvtx_matchrat .push_back( (float)cnt_match[0] / cnt[0] ); - b_SvM_nclusintt_matchrat .push_back( (float)cnt_match[1] / cnt[1] ); - b_SvM_nclustpc_matchrat .push_back( (float)cnt_match[2] / cnt[2] ); + b_nclus = cnt[4] ; + b_nclusmvtx = cnt[0] ; + b_nclusintt = cnt[1] ; + b_nclustpc = cnt[2] ; + + b_matchrat = (float)cnt_match[4] / cnt[4] ; + b_matchrat_mvtx = (float)cnt_match[0] / cnt[0] ; + b_matchrat_intt = (float)cnt_match[1] / cnt[1] ; + b_matchrat_tpc = (float)cnt_match[2] / cnt[2] ; if (m_fill_clusters) { - // clusters only in G4 matched tracks (i.e. by definition, unmatched clusters) auto clusters = m_cluscntr.phg4_clusloc_unmatched(); - b_G4M_clusU_i0.push_back(index_G4M_clusU); - index_G4M_clusU += clusters.size(); - b_G4M_clusU_i1.push_back(index_G4M_clusU); for (auto& loc : clusters) { - b_G4M_clusU_layer.push_back(loc.first); - b_G4M_clusU_x.push_back(loc.second[0]); - b_G4M_clusU_y.push_back(loc.second[1]); - b_G4M_clusU_z.push_back(loc.second[2]); - b_G4M_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + b_clusmatch .push_back(false); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); } - // Svtx only (i.e. unmatched) clusters - clusters = m_cluscntr.svtx_clusloc_unmatched(); - b_SvM_clusU_i0.push_back(index_SvM_clusU); - index_SvM_clusU += clusters.size(); - b_SvM_clusU_i1.push_back(index_SvM_clusU); + clusters = m_cluscntr.clusloc_matched(); + for (auto& loc : clusters) { + b_clusmatch .push_back(true); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); + } + } + m_ttree->Fill(); + clear_clusvecs(); + /* clear_clusvecs("apple0 g4_matched"); */ + + // <- <- <- <- Svtx Matched Tracks + b_is_g4track = false; + b_is_Svtrack = true; + b_trackid = sv_trkid; + b_trkpt = svtrk->get_pt(); + b_trketa = svtrk->get_eta(); + b_trkphi = svtrk->get_phi(); + + cnt = m_cluscntr.svtx_cntclus(); + /* cout << " FIXME 0000 matched Svtx: " << sv_trkid << " " << svtrk->get_pt()<<" " << svtrk->get_eta()<<" "<< svtrk->get_phi() << " " << cnt[4] << endl; */ + b_nclus = cnt[4] ; + b_nclusmvtx = cnt[0] ; + b_nclusintt = cnt[1] ; + b_nclustpc = cnt[2] ; + + b_matchrat = (float)cnt_match[4] / cnt[4] ; + b_matchrat_mvtx = (float)cnt_match[0] / cnt[0] ; + b_matchrat_intt = (float)cnt_match[1] / cnt[1] ; + b_matchrat_tpc = (float)cnt_match[2] / cnt[2] ; + + /* int _ = 0; */ + if (m_fill_clusters) { + auto clusters = m_cluscntr.svtx_clusloc_unmatched(); for (auto& loc : clusters) { - b_SvM_clusU_layer.push_back(loc.first); - b_SvM_clusU_x.push_back(loc.second[0]); - b_SvM_clusU_y.push_back(loc.second[1]); - b_SvM_clusU_z.push_back(loc.second[2]); - b_SvM_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + b_clusmatch .push_back(false); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + /* if (_==0) cout << " apple x: " << x << " y: " << y << endl; */ + /* _ += 1; */ + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); } - // Matched clusters clusters = m_cluscntr.clusloc_matched(); - b_clusM_i0.push_back(i_matched); - i_matched += clusters.size(); - b_clusM_i1.push_back(i_matched); for (auto& loc : clusters) { - b_clusM_layer.push_back(loc.first); - b_clusM_x.push_back(loc.second[0]); - b_clusM_y.push_back(loc.second[1]); - b_clusM_z.push_back(loc.second[2]); - b_clusM_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + b_clusmatch .push_back(true); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); } } + m_ttree->Fill(); + clear_clusvecs(); + /* clear_clusvecs("apple1 s4_matched"); */ } - // fill in un-matched PHG4 tracks + // <- <- <- <- G4 un-matched Tracks + b_is_matched = false; + b_is_g4track = true; + b_is_Svtrack = false; for (auto& g4_trkid : m_EmbRecoMatchContainer->ids_TruthUnmatched()) { auto g4trk = m_TrkrTruthTrackContainer->getTruthTrack(g4_trkid); - b_G4U_trackid .push_back(g4_trkid); - b_G4U_pt .push_back(g4trk->getPt()); - b_G4U_eta .push_back(g4trk->getPseudoRapidity()); - b_G4U_phi .push_back(g4trk->getPhi()); - m_cluscntr.addClusKeys( g4trk ); + + b_trackid = g4_trkid; + b_trkpt = g4trk->getPt(); + b_trketa = g4trk->getPseudoRapidity(); + b_trkphi = g4trk->getPhi(); + auto cnt = m_cluscntr.phg4_cntclus(); - b_G4U_nclus .push_back( cnt[4] ); - b_G4U_nclusmvtx .push_back( cnt[0] ); - b_G4U_nclusintt .push_back( cnt[1] ); - b_G4U_nclustpc .push_back( cnt[2] ); + b_nclus = cnt[4]; + b_nclusmvtx = cnt[0]; + b_nclusintt = cnt[1]; + b_nclustpc = cnt[2]; + if (m_fill_clusters) { auto clusters = m_cluscntr.phg4_clusloc_all(); - b_G4U_clusU_i0.push_back(index_G4U_clusU); - index_G4U_clusU += clusters.size(); - b_G4U_clusU_i1.push_back(index_G4U_clusU); for (auto& loc : clusters) { - b_G4U_clusU_layer.push_back(loc.first); - b_G4U_clusU_x.push_back(loc.second[0]); - b_G4U_clusU_y.push_back(loc.second[1]); - b_G4U_clusU_z.push_back(loc.second[2]); - b_G4U_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + b_clusmatch .push_back(false); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); } + //this is an unmatched track, so there are no matched clusters } + m_ttree->Fill(); + clear_clusvecs(); + /* clear_clusvecs("apple2 g4_unmatched"); */ } + // <- <- <- <- Svtx un-matched Tracks + b_is_matched = false; + b_is_matched = false; + b_is_g4track = false; + b_is_Svtrack = true; + + // just put in all svtx tracks, period... if (m_fill_SvU) { for (auto sv_trkid : G4Eval::unmatchedSvtxTrkIds(m_EmbRecoMatchContainer, m_SvtxTrackMap)) { auto svtrk = m_SvtxTrackMap->get(sv_trkid); - b_SvU_trackid .push_back(sv_trkid); - b_SvU_pt .push_back(svtrk->get_pt()); - b_SvU_eta .push_back(svtrk->get_eta()); - b_SvU_phi .push_back(svtrk->get_phi()); m_cluscntr.addClusKeys( svtrk ); + b_trackid = sv_trkid; + b_trkpt = svtrk->get_pt(); + b_trketa = svtrk->get_eta(); + b_trkphi = svtrk->get_phi(); + auto cnt = m_cluscntr.svtx_cntclus(); - b_SvU_nclus .push_back( cnt[4] ); - b_SvU_nclusmvtx .push_back( cnt[0] ); - b_SvU_nclusintt .push_back( cnt[1] ); - b_SvU_nclustpc .push_back( cnt[2] ); - } - if (m_fill_clusters) { - auto clusters = m_cluscntr.svtx_clusloc_all(); - b_SvU_clusU_i0.push_back (index_SvU_clusU); - index_SvU_clusU += clusters.size(); - b_SvU_clusU_i1.push_back (index_SvU_clusU); - for (auto& loc : clusters) { - b_SvU_clusU_layer.push_back(loc.first); - b_SvU_clusU_x.push_back(loc.second[0]); - b_SvU_clusU_y.push_back(loc.second[1]); - b_SvU_clusU_z.push_back(loc.second[2]); - b_SvU_clusU_r.push_back(pow(pow(loc.second[0],2.)+pow(loc.second[1],2.),0.5)); + b_nclus = cnt[4] ; + b_nclusmvtx = cnt[0] ; + b_nclusintt = cnt[1] ; + b_nclustpc = cnt[2] ; + + if (m_fill_clusters) { + auto clusters = m_cluscntr.svtx_clusloc_all(); + for (auto& loc : clusters) { + b_clusmatch .push_back(false); + b_clus_layer .push_back(std::get<0>(loc)); + auto x = std::get<1>(loc)[0]; + auto y = std::get<1>(loc)[1]; + b_clus_x .push_back(x); + b_clus_y .push_back(y); + b_clus_z .push_back(std::get<1>(loc)[2]); + b_clus_r .push_back(pow(x*x+y*y,0.5)); + b_clus_nphibins .push_back(std::get<2>(loc)); + b_clus_ntbins .push_back(std::get<3>(loc)); + } } + m_ttree->Fill(); + clear_clusvecs(); } } - m_ttree->Fill(); - clear_vectors(); if (Verbosity()>100) print_mvtx_diagnostics(); return Fun4AllReturnCodes::EVENT_OK; } @@ -514,107 +511,34 @@ void FillTruthRecoMatchTree::print_mvtx_diagnostics() { } -int FillTruthRecoMatchTree::End(PHCompositeNode *) -{ - if (Verbosity()>2) std::cout << PHWHERE << ": ending FillTruthRecoMatchTree" << std::endl; - PHTFileServer::get().cd(m_outfile_name); - - h2_G4_nPixelsPhi ->Write(); - h2_G4_nPixelsZ ->Write(); - h2_Sv_nPixelsPhi ->Write(); - h2_Sv_nPixelsZ ->Write(); + int FillTruthRecoMatchTree::End(PHCompositeNode *) + { + if (Verbosity()>2) std::cout << PHWHERE << ": ending FillTruthRecoMatchTree" << std::endl; + PHTFileServer::get().cd(m_outfile_name); - m_ttree->Write(); - return Fun4AllReturnCodes::EVENT_OK; -} + h2_G4_nPixelsPhi ->Write(); + h2_G4_nPixelsZ ->Write(); + h2_Sv_nPixelsPhi ->Write(); + h2_Sv_nPixelsZ ->Write(); -void FillTruthRecoMatchTree::clear_vectors() { - // Tracks and clustes + m_ttree->Write(); + return Fun4AllReturnCodes::EVENT_OK; + } - b_G4M_trackid .clear(); - b_G4M_nclus .clear(); - b_G4M_nclusmvtx .clear(); - b_G4M_nclusintt .clear(); - b_G4M_nclustpc .clear(); - b_G4M_nclus_matchrat .clear(); - b_G4M_nclusmvtx_matchrat .clear(); - b_G4M_nclusintt_matchrat .clear(); - b_G4M_nclustpc_matchrat .clear(); - b_G4M_pt .clear(); - b_G4M_phi .clear(); - b_G4M_eta .clear(); - b_SvM_trackid .clear(); - b_SvM_nclus .clear(); - b_SvM_nclusmvtx .clear(); - b_SvM_nclusintt .clear(); - b_SvM_nclustpc .clear(); - b_SvM_nclus_matchrat .clear(); - b_SvM_nclusmvtx_matchrat .clear(); - b_SvM_nclusintt_matchrat .clear(); - b_SvM_nclustpc_matchrat .clear(); - b_SvM_pt .clear(); - b_SvM_phi .clear(); - b_SvM_eta .clear(); - if (m_fill_clusters) { - b_clusM_i0 .clear(); - b_clusM_i1 .clear(); - b_clusM_layer .clear(); - b_clusM_x .clear(); - b_clusM_y .clear(); - b_clusM_z .clear(); - b_clusM_r .clear(); - b_G4M_clusU_i0 .clear(); - b_G4M_clusU_i1 .clear(); - b_G4M_clusU_layer .clear(); - b_G4M_clusU_x .clear(); - b_G4M_clusU_y .clear(); - b_G4M_clusU_z .clear(); - b_G4M_clusU_r .clear(); - b_SvM_clusU_i0 .clear(); - b_SvM_clusU_i1 .clear(); - b_SvM_clusU_layer .clear(); - b_SvM_clusU_x .clear(); - b_SvM_clusU_y .clear(); - b_SvM_clusU_z .clear(); - b_SvM_clusU_r .clear(); - } - b_G4U_trackid .clear(); - b_G4U_nclus .clear(); - b_G4U_nclusmvtx .clear(); - b_G4U_nclusintt .clear(); - b_G4U_nclustpc .clear(); - b_G4U_pt .clear(); - b_G4U_phi .clear(); - b_G4U_eta .clear(); - if (m_fill_SvU) { - b_SvU_trackid .clear(); - b_SvU_nclus .clear(); - b_SvU_nclusmvtx .clear(); - b_SvU_nclusintt .clear(); - b_SvU_nclustpc .clear(); - b_SvU_pt .clear(); - b_SvU_phi .clear(); - b_SvU_eta .clear(); - } - if (m_fill_clusters) { - b_G4U_clusU_i0 .clear(); - b_G4U_clusU_i1 .clear(); - b_G4U_clusU_layer .clear(); - b_G4U_clusU_x .clear(); - b_G4U_clusU_y .clear(); - b_G4U_clusU_z .clear(); - b_G4U_clusU_r .clear(); - if (m_fill_SvU) { - b_SvU_clusU_i0 .clear(); - b_SvU_clusU_i1 .clear(); - b_SvU_clusU_layer .clear(); - b_SvU_clusU_x .clear(); - b_SvU_clusU_y .clear(); - b_SvU_clusU_z .clear(); - b_SvU_clusU_r .clear(); - } + void FillTruthRecoMatchTree::clear_clusvecs(std::string tag) { + /* cout << " banana |" << tag << "|"< #include @@ -86,7 +86,7 @@ class FillTruthRecoMatchTree : public SubsysReco int process_event(PHCompositeNode * /*topNode*/) override; int End(PHCompositeNode *topNode) override; - void clear_vectors(); + void clear_clusvecs(std::string tag=""); void print_mvtx_diagnostics(); @@ -94,7 +94,7 @@ class FillTruthRecoMatchTree : public SubsysReco int createNodes(PHCompositeNode *topNode); - G4Eval::TrkrClusterComparer m_cluster_comp; + G4Eval::TrkrClusterComparer m_cluster_comp { 1., 1.}; G4Eval::ClusCntr m_cluscntr; // contianer used to fill the other track matches @@ -136,82 +136,111 @@ class FillTruthRecoMatchTree : public SubsysReco TH2D* h2_Sv_nPixelsPhi; TH2D* h2_Sv_nPixelsZ; - // TRACKS WHICH ARE MATCHED - std::vector b_G4M_trackid {}; // g4-track-matched - std::vector b_G4M_nclus {}; - std::vector b_G4M_nclusmvtx {}; - std::vector b_G4M_nclusintt {}; - std::vector b_G4M_nclustpc {}; - std::vector b_G4M_nclus_matchrat {}; - std::vector b_G4M_nclusmvtx_matchrat {}; - std::vector b_G4M_nclusintt_matchrat {}; - std::vector b_G4M_nclustpc_matchrat {}; - std::vector b_G4M_pt {}; - std::vector b_G4M_phi {}; - std::vector b_G4M_eta {}; - std::vector b_SvM_trackid {}; // Svtx-track-matched - std::vector b_SvM_nclus {}; - std::vector b_SvM_nclusmvtx {}; - std::vector b_SvM_nclusintt {}; - std::vector b_SvM_nclustpc {}; - std::vector b_SvM_nclus_matchrat {}; - std::vector b_SvM_nclusmvtx_matchrat {}; - std::vector b_SvM_nclusintt_matchrat {}; - std::vector b_SvM_nclustpc_matchrat {}; - std::vector b_SvM_pt {}; - std::vector b_SvM_phi {}; - std::vector b_SvM_eta {}; - std::vector b_clusM_i0 {}; // if storing clusters -- matched clusters - std::vector b_clusM_i1 {}; - std::vector b_clusM_layer {}; - std::vector b_clusM_x {}; - std::vector b_clusM_y {}; - std::vector b_clusM_z {}; - std::vector b_clusM_r {}; - std::vector b_G4M_clusU_i0 {}; // matched phg4 unmatched clusters - std::vector b_G4M_clusU_i1 {}; - std::vector b_G4M_clusU_layer {}; - std::vector b_G4M_clusU_x {}; - std::vector b_G4M_clusU_y {}; - std::vector b_G4M_clusU_z {}; - std::vector b_G4M_clusU_r {}; - std::vector b_SvM_clusU_i0 {}; // matched phg4 unmatched clusters - std::vector b_SvM_clusU_i1 {}; - std::vector b_SvM_clusU_layer {}; - std::vector b_SvM_clusU_x {}; - std::vector b_SvM_clusU_y {}; - std::vector b_SvM_clusU_z {}; - std::vector b_SvM_clusU_r {}; - std::vector b_G4U_trackid {}; // unmatched tracks - std::vector b_G4U_nclus {}; - std::vector b_G4U_nclusmvtx {}; - std::vector b_G4U_nclusintt {}; - std::vector b_G4U_nclustpc {}; - std::vector b_G4U_pt {}; - std::vector b_G4U_phi {}; - std::vector b_G4U_eta {}; - std::vector b_SvU_trackid {}; // Svtx-track-matched - std::vector b_SvU_nclus {}; - std::vector b_SvU_nclusmvtx {}; - std::vector b_SvU_nclusintt {}; - std::vector b_SvU_nclustpc {}; - std::vector b_SvU_pt {}; - std::vector b_SvU_phi {}; - std::vector b_SvU_eta {}; - std::vector b_G4U_clusU_i0 {}; // unmatched phg4 unmatched clusters - std::vector b_G4U_clusU_i1 {}; - std::vector b_G4U_clusU_layer {}; - std::vector b_G4U_clusU_x {}; - std::vector b_G4U_clusU_y {}; - std::vector b_G4U_clusU_z {}; - std::vector b_G4U_clusU_r {}; - std::vector b_SvU_clusU_i0 {}; // unmatched phg4 unmatched clusters - std::vector b_SvU_clusU_i1 {}; - std::vector b_SvU_clusU_layer {}; - std::vector b_SvU_clusU_x {}; - std::vector b_SvU_clusU_y {}; - std::vector b_SvU_clusU_z {}; - std::vector b_SvU_clusU_r {}; + // Track tree + int b_trackid; + bool b_is_g4track; + bool b_is_Svtrack; + bool b_is_matched; + + float b_trkpt; + float b_trkphi; + float b_trketa; + + + int b_nclus {}; + int b_nclustpc {}; + int b_nclusmvtx {}; + int b_nclusintt {}; + + float b_matchrat {}; + float b_matchrat_intt {}; + float b_matchrat_mvtx {}; + float b_matchrat_tpc {}; + + std::vector b_clusmatch {}; + std::vector b_clus_x {}; + std::vector b_clus_y {}; + std::vector b_clus_z {}; + std::vector b_clus_r {}; + std::vector b_clus_layer {}; + std::vector b_clus_nphibins {}; + std::vector b_clus_ntbins {}; + + /* std::vector b_G4M_trackid {}; // g4-track-matched */ + /* std::vector b_G4M_nclus {}; */ + /* std::vector b_G4M_nclusmvtx {}; */ + /* std::vector b_G4M_nclusintt {}; */ + /* std::vector b_G4M_nclustpc {}; */ + /* std::vector b_G4M_nclus_matchrat {}; */ + /* std::vector b_G4M_nclusmvtx_matchrat {}; */ + /* std::vector b_G4M_nclusintt_matchrat {}; */ + /* std::vector b_G4M_nclustpc_matchrat {}; */ + /* std::vector b_G4M_pt {}; */ + /* std::vector b_G4M_phi {}; */ + /* std::vector b_G4M_eta {}; */ + /* std::vector b_SvM_trackid {}; // Svtx-track-matched */ + /* std::vector b_SvM_nclus {}; */ + /* std::vector b_SvM_nclusmvtx {}; */ + /* std::vector b_SvM_nclusintt {}; */ + /* std::vector b_SvM_nclustpc {}; */ + /* std::vector b_SvM_nclus_matchrat {}; */ + /* std::vector b_SvM_nclusmvtx_matchrat {}; */ + /* std::vector b_SvM_nclusintt_matchrat {}; */ + /* std::vector b_SvM_nclustpc_matchrat {}; */ + /* std::vector b_SvM_pt {}; */ + /* std::vector b_SvM_phi {}; */ + /* std::vector b_SvM_eta {}; */ + /* std::vector b_clusM_i0 {}; // if storing clusters -- matched clusters */ + /* std::vector b_clusM_i1 {}; */ + /* std::vector b_clusM_layer {}; */ + /* std::vector b_clusM_x {}; */ + /* std::vector b_clusM_y {}; */ + /* std::vector b_clusM_z {}; */ + /* std::vector b_clusM_r {}; */ + /* std::vector b_G4M_clusU_i0 {}; // matched phg4 unmatched clusters */ + /* std::vector b_G4M_clusU_i1 {}; */ + /* std::vector b_G4M_clusU_layer {}; */ + /* std::vector b_G4M_clusU_x {}; */ + /* std::vector b_G4M_clusU_y {}; */ + /* std::vector b_G4M_clusU_z {}; */ + /* std::vector b_G4M_clusU_r {}; */ + /* std::vector b_SvM_clusU_i0 {}; // matched phg4 unmatched clusters */ + /* std::vector b_SvM_clusU_i1 {}; */ + /* std::vector b_SvM_clusU_layer {}; */ + /* std::vector b_SvM_clusU_x {}; */ + /* std::vector b_SvM_clusU_y {}; */ + /* std::vector b_SvM_clusU_z {}; */ + /* std::vector b_SvM_clusU_r {}; */ + /* std::vector b_G4U_trackid {}; // unmatched tracks */ + /* std::vector b_G4U_nclus {}; */ + /* std::vector b_G4U_nclusmvtx {}; */ + /* std::vector b_G4U_nclusintt {}; */ + /* std::vector b_G4U_nclustpc {}; */ + /* std::vector b_G4U_pt {}; */ + /* std::vector b_G4U_phi {}; */ + /* std::vector b_G4U_eta {}; */ + /* std::vector b_SvU_trackid {}; // Svtx-track-matched */ + /* std::vector b_SvU_nclus {}; */ + /* std::vector b_SvU_nclusmvtx {}; */ + /* std::vector b_SvU_nclusintt {}; */ + /* std::vector b_SvU_nclustpc {}; */ + /* std::vector b_SvU_pt {}; */ + /* std::vector b_SvU_phi {}; */ + /* std::vector b_SvU_eta {}; */ + /* std::vector b_G4U_clusU_i0 {}; // unmatched phg4 unmatched clusters */ + /* std::vector b_G4U_clusU_i1 {}; */ + /* std::vector b_G4U_clusU_layer {}; */ + /* std::vector b_G4U_clusU_x {}; */ + /* std::vector b_G4U_clusU_y {}; */ + /* std::vector b_G4U_clusU_z {}; */ + /* std::vector b_G4U_clusU_r {}; */ + /* std::vector b_SvU_clusU_i0 {}; // unmatched phg4 unmatched clusters */ + /* std::vector b_SvU_clusU_i1 {}; */ + /* std::vector b_SvU_clusU_layer {}; */ + /* std::vector b_SvU_clusU_x {}; */ + /* std::vector b_SvU_clusU_y {}; */ + /* std::vector b_SvU_clusU_z {}; */ + /* std::vector b_SvU_clusU_r {}; */ diff --git a/simulation/g4simulation/g4eval/Makefile.am b/simulation/g4simulation/g4eval/Makefile.am index f3548b4ee8..f383542aa9 100644 --- a/simulation/g4simulation/g4eval/Makefile.am +++ b/simulation/g4simulation/g4eval/Makefile.am @@ -64,7 +64,7 @@ pkginclude_HEADERS = \ SvtxTruthEval.h \ SvtxTruthRecoTableEval.h \ SvtxVertexEval.h \ - g4tools.h \ + g4evaltools.h \ TrackEvaluation.h \ TrackEvaluationContainer.h \ TrackEvaluationContainerv1.h \ @@ -112,7 +112,7 @@ libg4eval_la_SOURCES = \ SvtxTruthEval.cc \ SvtxTruthRecoTableEval.cc \ SvtxVertexEval.cc \ - g4tools.cc \ + g4evaltools.cc \ TrackEvaluation.cc \ TrackSeedTrackMapConverter.cc \ TruthRecoTrackMatching.cc diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc index 0a4a8f42cb..dfa98496bd 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.cc @@ -1,5 +1,5 @@ #include "TruthRecoTrackMatching.h" -#include "g4tools.h" +#include "g4evaltools.h" #include #include diff --git a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h index d43274b609..e3110b6b74 100644 --- a/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h +++ b/simulation/g4simulation/g4eval/TruthRecoTrackMatching.h @@ -1,7 +1,7 @@ #ifndef TRUTHTRKMATCHER__H #define TRUTHTRKMATCHER__H -#include "g4tools.h" // has some G4Eval tools (TrkrClusterComparer) +#include "g4evaltools.h" // has some G4Eval tools (TrkrClusterComparer) #include #include diff --git a/simulation/g4simulation/g4eval/g4tools.cc b/simulation/g4simulation/g4eval/g4evaltools.cc similarity index 89% rename from simulation/g4simulation/g4eval/g4tools.cc rename to simulation/g4simulation/g4eval/g4evaltools.cc index d4d1d4eb97..13ee1a7741 100644 --- a/simulation/g4simulation/g4eval/g4tools.cc +++ b/simulation/g4simulation/g4eval/g4evaltools.cc @@ -1,4 +1,4 @@ -#include "g4tools.h" +#include "g4evaltools.h" #include #include @@ -150,9 +150,16 @@ namespace G4Eval { return Fun4AllReturnCodes::EVENT_OK; } + // ok return tuple TrkrClusterComparer::operator() - (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R) + (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R) { + // note: can use returned values, or just pull from these values layer = TrkrDefs::getLayer(key_T); if (layer > 55) { std::cout << " Error! Trying to compar cluster in layer > 55, " @@ -172,46 +179,53 @@ namespace G4Eval { phi_T = clus_T->getPosition(0); phi_R = clus_R->getPosition(0); - phisize_R = clus_R->getPhiSize() * phi_step; - phisize_T = clus_T->getPhiSize() * phi_step; // only for user to get, if they want + phisize_R = clus_R->getPhiSize()*m_nphi_widths;// * phi_step; + phisize_T = clus_T->getPhiSize()*m_nphi_widths;// * phi_step; // only for user to get, if they want z_T = clus_T->getPosition(1); z_R = clus_R->getPosition(1); if (!in_intt) { - zsize_R = clus_R->getZSize() * z_step; - zsize_T = clus_R->getZSize() * z_step; + zsize_R = clus_R->getZSize()*m_nz_widths;// * z_step; + zsize_T = clus_R->getZSize()*m_nz_widths;// * z_step; } phi_delta = fabs(phi_T-phi_R); while (phi_delta > M_PI) phi_delta = fabs(phi_delta-2*M_PI); - z_delta = fabs (z_T-z_R); + phi_delta /= phi_step; + + z_delta = fabs (z_T-z_R) / z_step; - float phi_stat = (m_nphi_widths * phisize_R ); + /* float phi_stat = (m_nphi_widths * phisize_R ); */ - bool is_match = (phi_delta < phi_stat); + float phi_stat = std::max(phisize_T, phisize_R); float fit_statistic = (phi_delta / phi_stat); + is_match = (fit_statistic <= 1.); + float z_stat = 0; if (!in_intt) { - z_stat = (m_nz_widths * zsize_R ); + z_stat = std::max(zsize_T, zsize_R); + is_match = is_match && (z_delta < z_stat); fit_statistic += z_delta / z_stat; } return { is_match, fit_statistic }; } - std::pair TrkrClusterComparer::clusloc_PHG4( + ClusLoc TrkrClusterComparer::clusloc_PHG4( std::pair input) { auto cluster = m_TruthClusters->findCluster(input.second); Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster); - return {TrkrDefs::getLayer(input.first),gloc}; + return {TrkrDefs::getLayer(input.first),gloc, + (int)cluster->getPhiSize(),(int)cluster->getZSize()}; } - std::pair TrkrClusterComparer::clusloc_SVTX( + ClusLoc TrkrClusterComparer::clusloc_SVTX( std::pair input) { auto cluster = m_RecoClusters->findCluster(input.second); Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster); - return {TrkrDefs::getLayer(input.first),gloc}; + return {TrkrDefs::getLayer(input.first),gloc, + (int)cluster->getPhiSize(),(int)cluster->getZSize()}; } // Implementation of the iterable struct to get cluster keys from @@ -410,14 +424,14 @@ namespace G4Eval { int ClusCntr::svtx_n_matched() { return std::accumulate(svtx_matches.begin(), svtx_matches.end(), 0); } - std::vector ClusCntr::phg4_clusloc_all() { - std::vector vec{}; + std::vector ClusCntr::phg4_clusloc_all() { + std::vector vec{}; for (auto& cluspair : phg4_keys) vec.push_back(comp->clusloc_PHG4(cluspair)); return vec; } - std::vector ClusCntr::phg4_clusloc_unmatched() { - std::vector vec{}; + std::vector ClusCntr::phg4_clusloc_unmatched() { + std::vector vec{}; auto cnt = phg4_keys.size(); for (unsigned int i = 0; iclusloc_PHG4(phg4_keys[i])); @@ -425,14 +439,14 @@ namespace G4Eval { return vec; } - std::vector ClusCntr::svtx_clusloc_all() { - std::vector vec{}; + std::vector ClusCntr::svtx_clusloc_all() { + std::vector vec{}; for (auto& cluspair : svtx_keys) vec.push_back(comp->clusloc_SVTX(cluspair)); return vec; } - std::vector ClusCntr::svtx_clusloc_unmatched() { - std::vector vec{}; + std::vector ClusCntr::svtx_clusloc_unmatched() { + std::vector vec{}; auto cnt = svtx_keys.size(); for (unsigned int i = 0; iclusloc_SVTX(svtx_keys[i])); @@ -440,8 +454,8 @@ namespace G4Eval { return vec; } - std::vector ClusCntr::clusloc_matched() { - std::vector vec{}; + std::vector ClusCntr::clusloc_matched() { + std::vector vec{}; auto cnt = phg4_keys.size(); for (unsigned int i = 0; iclusloc_PHG4(phg4_keys[i])); diff --git a/simulation/g4simulation/g4eval/g4tools.h b/simulation/g4simulation/g4eval/g4evaltools.h similarity index 82% rename from simulation/g4simulation/g4eval/g4tools.h rename to simulation/g4simulation/g4eval/g4evaltools.h index 44bd78069f..5e2dd2ea1f 100644 --- a/simulation/g4simulation/g4eval/g4tools.h +++ b/simulation/g4simulation/g4eval/g4evaltools.h @@ -9,6 +9,7 @@ #include #include #include +#include /* #include */ class ActsGeometry; @@ -21,6 +22,8 @@ class TrkrClusterContainer; class TrkrTruthTrack; namespace G4Eval { + // ClusLoc holds layer, location, phi size and z size + using ClusLoc = std::tuple; // Following function writes msg to the currently active TFile // if f_outname is provided, then it will write the message to a new @@ -39,20 +42,21 @@ namespace G4Eval { TrkrCluster* clus_T { nullptr }; TrkrCluster* clus_R { nullptr }; - bool status_good { false }; - int layer { INT_MAX }; - std::pair operator() // return pair(is_matched,how_good_match) - (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R); + /* std::pair is_match_b */ + std::pair operator() (TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R); // Members that are set with each set of cluster keys that // are passed to it. // z and phi locations of phg4 hit (T) and Svtx hit (R) + bool is_match { false }; + int layer { INT_MAX }; + float z_T { FLT_MAX }, z_R { FLT_MAX }; float phi_T { FLT_MAX }, phi_R { FLT_MAX }; - float phisize_R { FLT_MAX }, phisize_T { FLT_MAX }; - float zsize_R { FLT_MAX }, zsize_T { FLT_MAX }; - float phi_delta { FLT_MAX }, z_delta { FLT_MAX }; // abs(z_T-z_R) + float phisize_R { FLT_MAX }, phisize_T { FLT_MAX }; // phisize is in nbins * nwidhts + float zsize_R { FLT_MAX }, zsize_T { FLT_MAX }; // zsize is in nbins * nwdiths + float phi_delta { FLT_MAX }, z_delta { FLT_MAX }; // deltas are also in nbins bool in_tpc {false}; bool in_mvtx {false}; @@ -67,8 +71,8 @@ namespace G4Eval { void set_nz_widths(float val) { m_nz_widths = val; }; void set_nphi_widths(float val) { m_nphi_widths = val; }; - std::pair clusloc_PHG4(std::pair); - std::pair clusloc_SVTX(std::pair); + ClusLoc clusloc_PHG4(std::pair); + ClusLoc clusloc_SVTX(std::pair); TrkrClusterContainer* m_TruthClusters {nullptr}; TrkrClusterContainer* m_RecoClusters {nullptr}; @@ -104,6 +108,7 @@ namespace G4Eval { ClusKeyIter begin(); ClusKeyIter end(); + void operator++(); TrkrDefs::cluskey operator*(); bool operator!=(const ClusKeyIter& rhs); @@ -153,12 +158,12 @@ namespace G4Eval { std::array svtx_cnt_matchedclus() {return cnt_matchedclus(svtx_keys, svtx_matches); }; std::array phg4_cnt_matchedclus() {return cnt_matchedclus(phg4_keys, phg4_matches); }; - using LayerLoc = std::pair; - std::vector phg4_clusloc_all(); - std::vector phg4_clusloc_unmatched(); - std::vector svtx_clusloc_all(); - std::vector svtx_clusloc_unmatched(); - std::vector clusloc_matched(); + //I need the cluster widths for diagnostics, too + std::vector phg4_clusloc_all (); + std::vector phg4_clusloc_unmatched(); + std::vector svtx_clusloc_all (); + std::vector svtx_clusloc_unmatched (); + std::vector clusloc_matched (); void set_comparer(TrkrClusterComparer* _comp) { comp = _comp; }; diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index 7e87294931..9012e90c4d 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -48,6 +48,9 @@ #include // for pair, swap, make_... #include // for vector + +// update to make sure to clusterize clusters in loopers + PHG4InttHitReco::PHG4InttHitReco(const std::string &name) : SubsysReco(name) , PHParameterInterface(name) @@ -250,7 +253,6 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) const int sphxlayer = hiter->second->get_detid(); CylinderGeomIntt *layergeom = dynamic_cast(geo->GetLayerGeom(sphxlayer)); - truthcheck_g4hit(hiter->second, topNode); // checking ADC timing integration window cut // uses default values for now @@ -258,6 +260,8 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) if (hiter->second->get_t(0) > m_Tmax) continue; if (hiter->second->get_t(1) < m_Tmin) continue; + truthcheck_g4hit(hiter->second, topNode); + float time = (hiter->second->get_t(0) + hiter->second->get_t(1)) / 2.0; // I made this (small) diffusion up for now, we will get actual values for the Intt later @@ -489,6 +493,11 @@ int PHG4InttHitReco::process_event(PHCompositeNode *topNode) hitsetcontainer->identify(); hittruthassoc->identify(); } + + if (m_is_emb) { + cluster_truthhits(topNode); // the last track was truth -- make it's clusters + prior_g4hit = nullptr; + } end_event_truthcluster( topNode ); return Fun4AllReturnCodes::EVENT_OK; @@ -506,26 +515,45 @@ void PHG4InttHitReco::SetDefaultParameters() return; } -void PHG4InttHitReco::truthcheck_g4hit(PHG4Hit* hit, PHCompositeNode* topNode) { - int new_trkid = (hit==nullptr) ? -1 : hit->get_trkid(); +void PHG4InttHitReco::truthcheck_g4hit(PHG4Hit* g4hit, PHCompositeNode* topNode) { + int new_trkid = (g4hit==nullptr) ? -1 : g4hit->get_trkid(); bool is_new_track = (new_trkid != m_trkid); if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<get_x(0)-g4hit->get_x(0)) > max_g4hitstep + || std::abs(prior_g4hit->get_y(0)-g4hit->get_y(0)) > max_g4hitstep + ) + ) + { + // this is a looper track -- cluster hits up to this point already + cluster_truthhits(topNode); + } + prior_g4hit = g4hit; + } + return; + } + // <- STATUS: this is a new track if (Verbosity()>2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl; if (m_is_emb) { - clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + //cluster the old track + cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track m_current_track = nullptr; + prior_g4hit = nullptr; } - m_trkid = new_trkid; // although m_current_track won't catch up until update_track is called + m_trkid = new_trkid; m_is_emb = m_truthinfo->isEmbeded(m_trkid); if (m_is_emb) { m_current_track = m_truthtracks->getTruthTrack(m_trkid, m_truthinfo); + prior_g4hit = g4hit; } } void PHG4InttHitReco::end_event_truthcluster ( PHCompositeNode* topNode ) { if (m_is_emb) { - clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track m_current_track = nullptr; m_trkid = -1; m_is_emb = false; @@ -553,7 +581,7 @@ void PHG4InttHitReco::addtruthhitset( hit->addEnergy(neffelectrons); } -void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { +void PHG4InttHitReco::cluster_truthhits(PHCompositeNode* topNode) { // ----------------------------------------------- // Digitize, adapted from g4intt/PHG4InttDigitizer // ----------------------------------------------- @@ -689,7 +717,8 @@ void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes // as the SvtxTrack clusters - const double threshold = sum_energy * m_truth_pixelthreshold; + /* const double threshold = sum_energy * m_truth_pixelthreshold; */ + const double threshold = sum_energy * m_pixel_thresholdrat; //FIXME -- tune this as needed int layer = TrkrDefs::getLayer ( hitsetkey ); CylinderGeomIntt* geom = dynamic_cast(geom_container->GetLayerGeom(layer)); @@ -796,5 +825,7 @@ void PHG4InttHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { } // end loop over hitsets } + m_truth_hits->Reset(); + prior_g4hit = nullptr; return; } diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.h b/simulation/g4simulation/g4intt/PHG4InttHitReco.h index 921ba996b5..e1a9a884e1 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.h +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.h @@ -66,14 +66,17 @@ class PHG4InttHitReco : public SubsysReco, public PHParameterInterface TrkrHitSetContainer* m_truth_hits; // generate and delete a container for each truth track std::map m_hitsetkey_cnt {}; // counter for making ckeys form hitsetkeys + PHG4Hit* prior_g4hit { nullptr }; // used to check for jumps in g4hits for loopers; void truthcheck_g4hit ( PHG4Hit*, PHCompositeNode* topNode ); void addtruthhitset ( TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons ); - void clusterize_truthtrack ( PHCompositeNode* topNode ); + void cluster_truthhits ( PHCompositeNode* topNode ); void end_event_truthcluster ( PHCompositeNode* topNode ); - double m_truth_pixelthreshold { 0.01 }; + double m_pixel_thresholdrat { 0.01 }; + float max_g4hitstep { 2.0 }; public: - void set_truth_pixelthreshold (double val) { m_truth_pixelthreshold = val; }; + void set_pixel_thresholdrat (double val) { m_pixel_thresholdrat = val; }; + void set_max_g4hitstep (float _) { max_g4hitstep =_; }; }; diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc index 1367be2e1a..c09e769671 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.cc @@ -690,6 +690,11 @@ int PHG4MvtxHitReco::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << " ----- end of clusters " << std::endl; } + if (m_is_emb) { + cluster_truthhits(topNode); // the last track was truth -- cluster it + prior_g4hit = nullptr; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -761,26 +766,50 @@ PHG4MvtxHitReco::~PHG4MvtxHitReco() { delete m_truth_hits; } -void PHG4MvtxHitReco::truthcheck_g4hit(PHG4Hit* hit, PHCompositeNode* topNode) { - int new_trkid = (hit==nullptr) ? -1 : hit->get_trkid(); +void PHG4MvtxHitReco::truthcheck_g4hit(PHG4Hit* g4hit, PHCompositeNode* topNode) { + int new_trkid = (g4hit==nullptr) ? -1 : g4hit->get_trkid(); bool is_new_track = (new_trkid != m_trkid); if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<get_x(0) << " " */ + /* << g4hit->get_y(0) << " " << g4hit->get_z(0) */ + /* << " trackid("<get_trkid() << ") " << std::endl; */ + if (m_is_emb) { + /* std::cout << " FIXME Checking MVTX g4hit : " << g4hit->get_x(0) << " " */ + /* << g4hit->get_y(0) << " " << g4hit->get_z(0) */ + /* << " trackid("<get_trkid() << ") " << std::endl; */ + if (prior_g4hit!=nullptr + && ( std::abs(prior_g4hit->get_x(0)-g4hit->get_x(0)) > max_g4hitstep + || std::abs(prior_g4hit->get_y(0)-g4hit->get_y(0)) > max_g4hitstep + ) + ) + { + // this is a looper track -- cluster hits up to this point already + cluster_truthhits(topNode); + } + prior_g4hit = g4hit; + } + return; + } + // <- STATUS: this is a new track if (Verbosity()>2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl; if (m_is_emb) { - clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track m_current_track = nullptr; + prior_g4hit = nullptr; } - m_trkid = new_trkid; // although m_current_track won't catch up until update_track is called + m_trkid = new_trkid; m_is_emb = m_truthinfo->isEmbeded(m_trkid); if (m_is_emb) { m_current_track = m_truthtracks->getTruthTrack(m_trkid, m_truthinfo); + prior_g4hit = g4hit; } } void PHG4MvtxHitReco::end_event_truthcluster ( PHCompositeNode* topNode ) { if (m_is_emb) { - clusterize_truthtrack(topNode); // cluster m_truth_hits and add m_current_track + cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track m_current_track = nullptr; m_trkid = -1; m_is_emb = false; @@ -808,7 +837,7 @@ void PHG4MvtxHitReco::addtruthhitset( hit->addEnergy(neffelectrons); } -void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { +void PHG4MvtxHitReco::cluster_truthhits(PHCompositeNode* topNode) { // clusterize the mvtx hits in m_truth_hits, put them in m_truthclusters, and put the id's in m_current_track // ---------------------------------------------------------------------------------------------------- // Digitization -- simplified from g4mvtx/PHG4MvtxDigitizer -- @@ -1007,20 +1036,20 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { exit(1); - // make a tunable threshhold for energy in a given hit + // make a tunable threshold for energy in a given hit // -- percentage of someting? (total cluster energy) double sum_energy { 0. }; for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { sum_energy += ihit->second->getEnergy(); } - const double threshhold = sum_energy / 100.; //FIXME -- tune this as needed + const double threshold = sum_energy * m_pixel_thresholdrat; //FIXME -- tune this as needed /* const unsigned int npixels = std::distance( hitrangei.first, hitrangei.second ); */ // to tune this parameter: run a bunch of tracks and compare truth sizes and reco sizes, // should come out the same double npixels {0.}; for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) { - if (ihit->second->getEnergy()second->getEnergy()first); @@ -1091,5 +1120,6 @@ void PHG4MvtxHitReco::clusterize_truthtrack(PHCompositeNode* topNode) { } // loop over hitsets } m_truth_hits->Reset(); + prior_g4hit = nullptr; return; } diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h index 086d78a9a9..cf1d4aaf52 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxHitReco.h @@ -84,11 +84,18 @@ class PHG4MvtxHitReco : public SubsysReco, public PHParameterInterface const int m_cluster_version { 4 }; TrkrHitSetContainer* m_truth_hits; // generate and delete a container for each truth track std::map m_hitsetkey_cnt {}; // counter for making ckeys form hitsetkeys - - void truthcheck_g4hit ( PHG4Hit*, PHCompositeNode* topNode ); - void addtruthhitset ( TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons ); - void clusterize_truthtrack ( PHCompositeNode* topNode ); - void end_event_truthcluster ( PHCompositeNode* topNode ); + + + PHG4Hit* prior_g4hit { nullptr }; // used to check for jumps in g4hits for loopers; + void addtruthhitset ( TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons ); + void truthcheck_g4hit ( PHG4Hit*, PHCompositeNode* topNode ); + void cluster_truthhits ( PHCompositeNode* topNode ); + void end_event_truthcluster ( PHCompositeNode* topNode ); + + double m_pixel_thresholdrat { 0.01 }; + float max_g4hitstep { 3.5 }; + public: + void set_pixel_thresholdrat (double val) { m_pixel_thresholdrat = val; }; }; #endif diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index abbe1145b3..2604b651a9 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -327,6 +327,8 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) { + truth_track = nullptr; // track to which truth clusters are built + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); if(!m_tGeometry) { @@ -334,19 +336,12 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if (truth_clusterer == nullptr) { - /* if (Verbosity()) std::cout << " truth clusterer was a null pointer " << std::endl; */ - truth_clusterer = new TpcClusterBuilder(truthclustercontainer, m_tGeometry, seggeo); - } else { - if (Verbosity()) std::cout << " truth clusterer was NOT a null pointer " << std::endl; + if (truth_clusterer.needs_input_nodes) { + truth_clusterer.set_input_nodes( truthclustercontainer, m_tGeometry, seggeo); } static constexpr unsigned int print_layer = 18; - truth_clusterer->is_embedded_track = false; - std::map hitset_cnt; // needed for indexing the TrkrClusters into the TrkrClusterContainer - /* std::map> truthtrack_hits; */ - // tells m_distortionMap which event to look at if (m_distortionMap) @@ -385,6 +380,10 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) int trkid = -1; + PHG4Hit* prior_g4hit = nullptr; // used to check for jumps in g4hits; + // if there is a big jump (such as crossing into the INTT area or out of the TPC) + // then cluster the truth clusters before adding a new hit. This prevents + // clustering loopers in the same HitSetKey surfaces in multiple passes for (auto hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter) { count_g4hits++; @@ -399,24 +398,41 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) int trkid_new = hiter->second->get_trkid(); if (trkid != trkid_new) { // starting a new track - truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ false); + prior_g4hit = nullptr; + if (truth_track) truth_clusterer.cluster_hits(truth_track); trkid = trkid_new; - truth_clusterer->is_embedded_track = (truthinfo->isEmbeded(trkid)); - if (Verbosity() > 1000){ - std::cout << " New track " << trkid << " is embed? : " - << truth_clusterer->is_embedded_track << std::endl; + + if (Verbosity() > 1000) std::cout << " New track : " << trkid << " is embed? : "; + + if (truthinfo->isEmbeded(trkid)) { + truth_track = truthtracks->getTruthTrack(trkid, truthinfo); + truth_clusterer.b_collect_hits = true; + if (Verbosity() > 1000) { std::cout << " YES embedded" << std::endl; } + } else { + truth_track = nullptr; + truth_clusterer.b_collect_hits = false; + if (Verbosity() > 1000) { std::cout << " NOT embedded" << std::endl; } } - if (truth_clusterer->is_embedded_track) - { // build new TrkrTruthTrack - current_track = truthtracks->getTruthTrack(trkid, truthinfo); - truth_clusterer->set_current_track(current_track); - } } + + // see if there is a jump in x or y relative to previous PHG4Hit + if (truth_clusterer.b_collect_hits) { + if (prior_g4hit) { + // if the g4hits jump in x or y by > max_g4hit_jump, cluster the truth tracks + if ( std::abs(prior_g4hit->get_x(0)-hiter->second->get_x(0)) > max_g4hitstep + || std::abs(prior_g4hit->get_y(0)-hiter->second->get_y(0)) > max_g4hitstep + ) { + truth_clusterer.cluster_hits(truth_track); + } + } + prior_g4hit = hiter->second; + } + // for very high occupancy events, accessing the TrkrHitsets on the node tree // for every drifted electron seems to be very slow // Instead, use a temporary map to accumulate the charge from all // drifted electrons, then copy to the node tree later - + double eion = hiter->second->get_eion(); unsigned int n_electrons = gsl_ran_poisson(RandomGenerator.get(), eion * electrons_per_gev); // count_electrons += n_electrons; @@ -561,7 +577,6 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) assert(nt); nt->Fill(ihit, t_start, t_final, t_sigma, rad_final, z_start, z_final); } - // this fills the cells and updates the hits in temp_hitsetcontainer for this drifted electron hitting the GEM stack padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(), temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final, side, hiter, ntpad, nthit); @@ -672,7 +687,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } // end loop over g4hits - truth_clusterer->cluster_and_reset(/*argument is if to reset hitsetkey as well*/ true); + if (truth_track) truth_clusterer.cluster_hits(truth_track); + truth_clusterer.clear_hitsetkey_cnt(); if (Verbosity() > 20) { @@ -724,8 +740,8 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) } if (Verbosity()>800) { - truth_clusterer->print(truthtracks); - truth_clusterer->print_file(truthtracks,"drift_clusters.txt"); + truth_clusterer.print(truthtracks); + truth_clusterer.print_file(truthtracks,"drift_clusters.txt"); } return Fun4AllReturnCodes::EVENT_OK; @@ -806,9 +822,6 @@ void PHG4TpcElectronDrift::SetDefaultParameters() return; } -PHG4TpcElectronDrift::~PHG4TpcElectronDrift() { - if (truth_clusterer != nullptr) delete truth_clusterer; -} void PHG4TpcElectronDrift::setTpcDistortion(PHG4TpcDistortion *distortionMap) { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index 4d3f6ff183..e692763f2c 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -1,9 +1,10 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. - #ifndef G4TPC_PHG4TPCELECTRONDRIFT_H #define G4TPC_PHG4TPCELECTRONDRIFT_H +#include "TpcClusterBuilder.h" + #include #include #include @@ -35,7 +36,7 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface { public: PHG4TpcElectronDrift(const std::string &name = "PHG4TpcElectronDrift"); - ~PHG4TpcElectronDrift() override; + ~PHG4TpcElectronDrift() override { }; int Init(PHCompositeNode *) override; int InitRun(PHCompositeNode *) override; int process_event(PHCompositeNode *) override; @@ -64,7 +65,13 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface //! setup readout plane void registerPadPlane(PHG4TpcPadPlane *padplane); + // cluster the PHG4Tracks individually + TpcClusterBuilder truth_clusterer {}; + void set_pixel_thresholdrat (double val) { truth_clusterer.set_pixel_thresholdrat(val); }; + void set_max_g4hitstep (float _) { max_g4hitstep =_; }; + private: + float max_g4hitstep { 7. }; //! map a given x,y,z coordinates to plane hits /* TpcClusterBuilder MapToPadPlane(const double x, const double y, const */ /* double z, const unsigned int side, PHG4HitContainer::ConstIterator hiter, */ @@ -75,7 +82,7 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface TrkrHitSetContainer *hitsetcontainer = nullptr; TrkrHitTruthAssoc *hittruthassoc = nullptr; TrkrTruthTrackContainer *truthtracks = nullptr; - TrkrTruthTrack *current_track = nullptr; + TrkrTruthTrack *truth_track = nullptr; TrkrClusterContainer *truthclustercontainer = nullptr; // the TrkrClusterContainer for truth clusters std::unique_ptr temp_hitsetcontainer; std::unique_ptr single_hitsetcontainer; @@ -130,12 +137,6 @@ class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface double min_time = NAN; double max_time = NAN; - - /* std::array layer_clusterers; // Generate TrkrClusterv4's for TrkrTruthTracks */ - TpcClusterBuilder* truth_clusterer { nullptr }; - - /* void buildTruthClusters(std::map&); */ - //! rng de-allocator class Deleter { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h index ac8b7ccda3..b91156cbc0 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h @@ -33,7 +33,7 @@ class PHG4TpcPadPlane : public SubsysReco, public PHParameterInterface virtual int CreateReadoutGeometry(PHCompositeNode * /*topNode*/, PHG4TpcCylinderGeomContainer * /*seggeo*/) { return 0; } virtual void UpdateInternalParameters() { return; } // virtual void MapToPadPlane(PHG4CellContainer * /*g4cells*/, const double /*x_gem*/, const double /*y_gem*/, const double /*t_gem*/, const unsigned int /*side*/, PHG4HitContainer::ConstIterator /*hiter*/, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) {} - virtual void MapToPadPlane(TpcClusterBuilder* /*builder*/, TrkrHitSetContainer * /*single_hitsetcontainer*/, TrkrHitSetContainer * /*hitsetcontainer*/, TrkrHitTruthAssoc * /*hittruthassoc*/, const double /*x_gem*/, const double /*y_gem*/, const double /*t_gem*/, const unsigned int /*side*/, PHG4HitContainer::ConstIterator /*hiter*/, TNtuple * /*ntpad*/, TNtuple * /*nthit*/)=0;// { return {}; } + virtual void MapToPadPlane(TpcClusterBuilder& /*builder*/, TrkrHitSetContainer * /*single_hitsetcontainer*/, TrkrHitSetContainer * /*hitsetcontainer*/, TrkrHitTruthAssoc * /*hittruthassoc*/, const double /*x_gem*/, const double /*y_gem*/, const double /*t_gem*/, const unsigned int /*side*/, PHG4HitContainer::ConstIterator /*hiter*/, TNtuple * /*ntpad*/, TNtuple * /*nthit*/)=0;// { return {}; } void Detector(const std::string &name) { detector = name; } protected: diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index d0a7721330..765b855611 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -190,7 +190,7 @@ double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification() void PHG4TpcPadPlaneReadout::MapToPadPlane( - TpcClusterBuilder *tpc_truth_clusterer, + TpcClusterBuilder &tpc_truth_clusterer, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, @@ -402,7 +402,7 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( // Either way, add the energy to it -- adc values will be added at digitization hit->addEnergy(neffelectrons); - tpc_truth_clusterer->addhitset(hitsetkey, hitkey, neffelectrons); + tpc_truth_clusterer.addhitset(hitsetkey, hitkey, neffelectrons); // repeat for the single_hitsetcontainer // See if this hit already exists diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index b4380b172f..5f621916aa 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -35,7 +35,7 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane // otherwise warning of inconsistent overload since only one MapToPadPlane methow is overridden using PHG4TpcPadPlane::MapToPadPlane; - void MapToPadPlane(TpcClusterBuilder* tpc_clustbuilder, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, const double x_gem, const double y_gem, const double t_gem, const unsigned int side, PHG4HitContainer::ConstIterator hiter, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) override; + void MapToPadPlane(TpcClusterBuilder& tpc_clustbuilder, TrkrHitSetContainer *single_hitsetcontainer, TrkrHitSetContainer *hitsetcontainer, TrkrHitTruthAssoc * /*hittruthassoc*/, const double x_gem, const double y_gem, const double t_gem, const unsigned int side, PHG4HitContainer::ConstIterator hiter, TNtuple * /*ntpad*/, TNtuple * /*nthit*/) override; void SetDefaultParameters() override; void UpdateInternalParameters() override; diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index 41f41b4dba..9fd95f11b1 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -12,37 +12,26 @@ #include // for TrkrHit #include // for sqrt, cos, sin #include // for _Rb_tree_cons... +#include #include #include +#include + +#include +#include + /* class TpcClusterBuilder; */ -using std::cout, std::endl, std::string, std::ofstream; +using std::cout, std::endl, std::string, std::ofstream, std::ostream; double TpcClusterBuilder::square(double v) { return v*v; } double TpcClusterBuilder::square(float v) { return v*v; } void TpcClusterBuilder::set_verbosity(int verbosity_level) { verbosity = verbosity_level; } -TpcClusterBuilder::TpcClusterBuilder - ( TrkrClusterContainer* _truth_cluster_container - /* , TrkrTruthTrackContainer* _truth_track_container */ - , ActsGeometry* _ActsGeometry - , PHG4TpcCylinderGeomContainer* _geom_container - ): m_clusterlist { _truth_cluster_container } - , m_tGeometry { _ActsGeometry } - , geom_container { _geom_container } -{ } - -void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { - if (verbosity) if (m_hits == nullptr) cout << " m_hits == nullptr! " << endl; - - if (!is_embedded_track) { - reset(clear_hitsetkey_cnt); - return; - } - +void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { // now build the TrkrCluster TrkrHitSetContainer::ConstRange hitsetrange; hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); @@ -50,6 +39,7 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { //----------------------------------------------------- // from TpcClusterizer.cc ~line: 837 //----------------------------------------------------- + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr) @@ -90,24 +80,56 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { double radius = layergeom->get_radius(); // returns center of layer int phibinhi = -1; - int phibinlo = 666666; + int phibinlo = INT_MAX; int tbinhi = -1; - int tbinlo = 666666; + int tbinlo = INT_MAX; auto ihit_list = hitset->getHits(); + + double sum_energy { 0. }; // energy = 4 * adc at this point + for(auto ihit = ihit_list.first; ihit != ihit_list.second; ++ihit){ + int e = ihit->second->getEnergy(); + int adc = ihit->second->getAdc(); + if (adc*4 != e) { + cout << " FIXME: energy: " << ihit->second->getEnergy() << " vs adc " << ihit->second->getAdc() << endl; + } + sum_energy += ihit->second->getEnergy(); + } + const double threshold = sum_energy * m_pixel_thresholdrat; + + // FIXME -- see why the hits are so scattered + std::set v_iphi, v_it; // FIXME + std::map m_iphi, m_it; // FIXME for(auto iter = ihit_list.first; iter != ihit_list.second; ++iter){ unsigned int adc = iter->second->getAdc(); if (adc <= 0) continue; + if (iter->second->getEnergy()second->getEnergy() << " is below " << threshold << endl; */ + } + + if (iter->second->getEnergy()first) - phioffset; int it = TpcDefs::getTBin(iter->first) - toffset; + //FIXME + v_iphi.insert(iphi); + v_it.insert(it); + m_iphi.try_emplace(iphi,0); + m_it.try_emplace(it,0); + + m_iphi[iphi] += adc; + m_it[it] += adc; + if(iphi<0 || iphi>=phibins){ - //std::cout << "WARNING phibin out of range: " << phibin << " | " << phibins << std::endl; + //FIXME + std::cout << "WARNING phibin out of range: " << iphi << " | " << phibins << std::endl; continue; } if(it<0 || it>=tbins){ - //std::cout << "WARNING z bin out of range: " << tbin << " | " << tbins << std::endl; + //FIXME + std::cout << "WARNING z bin out of range: " << it << " | " << tbins << std::endl; continue; } @@ -132,6 +154,17 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { adc_sum += adc; } + + if (true) { // FIXME + int _phi_sum = 0; + for (auto _ : m_iphi) _phi_sum += _.second; + if (_phi_sum != adc_sum) cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << endl; + + int _t_sum = 0; + for (auto _ : m_it) _t_sum += _.second; + if (_t_sum != adc_sum) cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << endl; + } + // This is the global position double clusiphi = iphi_sum / adc_sum; @@ -143,12 +176,81 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { double zdriftlength = clust * m_tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC double clusz = m_tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; - if(side == 0) clusz = -clusz; - /* const double phi_cov = phi2_sum/adc_sum - square(clusphi); */ + if (side == 0) clusz = -clusz; char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; + if (tsize < 0) cout << " FIXME z4 tsize: " << ((int)tsize) << " " << tbinlo << " to " << tbinhi << endl; + + // ------------------------------------------------- + // ------------------------------------------------- + // debug here: FIXME + // + /* cout << " FIXME phisize " << ((int) phisize) << endl; */ + //FIXME + if (false) { // Printing for debugging + if ((int)phisize > 10 || (int)tsize > 8) { + int _size_phi = ((int)phisize); + int _nbins_phi = v_iphi.size(); + int _delta_phi = abs(_size_phi-_nbins_phi); + int _size_z = ((int)tsize); + int _nbins_z = v_it.size(); + int _delta_z = abs(_size_z - _nbins_z); + + TString fmt; + cout << " x|"<<_delta_phi<<"|"<<_delta_z + <<"| new node FIXME A1 layer("<< layer + <<") (nset:size) phi(" + << _nbins_phi<<":"<<_size_phi << ") z(" + <<_nbins_z<<":"<<_size_z<<") " + <<"trkId("<getTrackid()<<") trkpT("<getPt()<<")" + << endl; + if (phisize>10) { + cout << " iphi-from-("; + int _prev = -1; + double tempsum = 0.; + for (auto _ : v_iphi) { + if (_prev == -1) { + cout << _<<"): "; + } else { + int _diff = ((int)_-_prev-1); + if (_diff != 0) cout<<">"<<_diff<<">"; + } + /* cout << std::setprecision(2) << std::fixed; */ + double _rat = (float)m_iphi[_] / (float)adc_sum; + fmt.Form("%.2f",_rat); + cout << fmt <<" "; + tempsum += _rat; + _prev = _; + } + if (tempsum < 0.999) cout << " Z3 sumphirat: " << tempsum; + cout << endl; + } + if (tsize>8) { + int _prev = -1; + double tempsum = 0.; + cout << " iz-from-("; + for (auto _ : v_it) { + if (_prev == -1) { + cout << _<<"): "; + } else { + int _diff = ((int)_-_prev-1); + if (_diff != 0) cout<<">"<<_diff<<">"; + } + /* cout << std::setprecision(2) << std::fixed; */ + double _rat = (float)m_it[_] / (float)adc_sum; + fmt.Form("%.2f",_rat); + cout << fmt <<" "; + tempsum += _rat; + _prev = _; + } + if (tempsum < 0.999) cout << " Z3 sumzrat: " << tempsum; + } + cout << endl; + } + } // end debug printing + // get the global vector3 to then get the surface local phi and z Acts::Vector3 global(clusx, clusy, clusz); TrkrDefs::subsurfkey subsurfkey = 0; @@ -180,24 +282,20 @@ void TpcClusterBuilder::cluster_and_reset(bool clear_hitsetkey_cnt) { cluster->setLocalY(clust); // add the clusterkey - if (hitsetkey_cnt.find(hitsetkey)==hitsetkey_cnt.end()) { - hitsetkey_cnt[hitsetkey] = 0; - } else { - hitsetkey_cnt[hitsetkey] +=1; - } + auto empl = hitsetkey_cnt.try_emplace(hitsetkey,0); + if (!empl.second) empl.first->second += 1; TrkrDefs::cluskey cluskey = TrkrDefs::genClusKey(hitsetkey, hitsetkey_cnt[hitsetkey]); m_clusterlist->addClusterSpecifyKey(cluskey, cluster); - if (current_track != nullptr) current_track->addCluster(cluskey); + track->addCluster(cluskey); } - - reset(clear_hitsetkey_cnt); + m_hits->Reset(); } -void TpcClusterBuilder::set_current_track(TrkrTruthTrack* track) { - current_track = track; - ++ n_tracks; -} +/* void TpcClusterBuilder::set_current_track(TrkrTruthTrack* track) { */ + /* current_track = track; */ + /* ++ n_tracks; */ +/* } */ void TpcClusterBuilder::addhitset( TrkrDefs::hitsetkey hitsetkey, @@ -206,7 +304,7 @@ void TpcClusterBuilder::addhitset( { // copy of code in PHG4TpcPadPlaneReadout::MapToPadPlane, with a switch // to ignore non embedded tracks - if (!is_embedded_track) return; + if (!b_collect_hits) return; // Add the hitset to the current embedded track // Code from PHG4TpcPadPlaneReadout::MapToPadPlane (around lines {}.cc::386-401) @@ -224,15 +322,8 @@ void TpcClusterBuilder::addhitset( hit->addEnergy(neffelectrons); } -void TpcClusterBuilder::reset(bool clear_hitsetkey_cnt) { - // clear the hitsets before the next track - m_hits->Reset(); - - // if done with the event, also clear the hitsetkey_cnt - if (clear_hitsetkey_cnt) { +void TpcClusterBuilder::clear_hitsetkey_cnt() { hitsetkey_cnt.clear(); - n_tracks = 0; - } } void TpcClusterBuilder::print( @@ -299,3 +390,14 @@ void TpcClusterBuilder::print_file( fout.close(); } +void TpcClusterBuilder::set_input_nodes( + TrkrClusterContainer* _truth_cluster_container + , ActsGeometry* _ActsGeometry + , PHG4TpcCylinderGeomContainer* _geom_container +) { + m_clusterlist = _truth_cluster_container; + m_tGeometry = _ActsGeometry; + geom_container = _geom_container; + needs_input_nodes = false; +}; + diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.h b/simulation/g4simulation/g4tpc/TpcClusterBuilder.h index bc83df9d3c..6cede972f2 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.h +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.h @@ -25,13 +25,16 @@ #include #include #include +#include + +using std::ostream; -class TrkrCluster; class PHG4TpcCylinderGeom; +class PHG4TpcCylinderGeomContainer; +class TrkrCluster; class TrkrClusterContainer; class TrkrHitSetContainer; class TrkrTruthTrack; -class PHG4TpcCylinderGeomContainer; class TrkrTruthTrackContainer; // This is the basic data for each set of TrkrHits from each TrkrHitsSet @@ -40,28 +43,34 @@ class TpcClusterBuilder { double square(double); double square(float); - TrkrClusterContainer* m_clusterlist; // fill for output - ActsGeometry* m_tGeometry; // used to generate clusters - PHG4TpcCylinderGeomContainer* geom_container; + TrkrClusterContainer* m_clusterlist { nullptr }; // fill for output + ActsGeometry* m_tGeometry { nullptr }; // used to generate clusters + PHG4TpcCylinderGeomContainer* geom_container { nullptr }; // internal containers to fill and consume hits and fill with tracks TrkrHitSetContainer* m_hits { new TrkrHitSetContainerv1() }; - TrkrTruthTrack* current_track { nullptr }; + /* TrkrTruthTrack* current_track { nullptr }; */ std::map hitsetkey_cnt {}; - int n_tracks {0}; + public: + private: + int n_tracks {0}; int verbosity {0}; public: - TpcClusterBuilder( - TrkrClusterContainer* _truth_cluster_container - , ActsGeometry* _ActsGeometry - , PHG4TpcCylinderGeomContainer* _geom_container - ); + TpcClusterBuilder( ) { }; + /* TrkrClusterContainer* _truth_cluster_container */ + /* , ActsGeometry* _ActsGeometry */ + /* , PHG4TpcCylinderGeomContainer* _geom_container */ + /* ); */ - bool is_embedded_track {false}; - void cluster_and_reset (bool clear_hitsetkey_cnt); + void fixme_check(); + void fixme_short_check(); + + bool b_collect_hits { false }; + /* bool is_embedded_track {false}; */ + void cluster_hits (TrkrTruthTrack* track); void addhitset (TrkrDefs::hitsetkey, TrkrDefs::hitkey, float neffelectrons); void set_current_track (TrkrTruthTrack* _trkrtruthtrack); void print(TrkrTruthTrackContainer*, int nclusprint=-1); @@ -84,7 +93,19 @@ class TpcClusterBuilder { // From Tony Frawley July 5, 2022 double m_sampa_tbias = 39.6; // ns - void reset(bool clear_hitsetkey_cnt); + + // for pixel thresholds + private: + double m_pixel_thresholdrat { 0.01 }; + public: + void clear_hitsetkey_cnt(); + void set_pixel_thresholdrat (double val) { m_pixel_thresholdrat = val; }; + bool needs_input_nodes = true; + void set_input_nodes( + TrkrClusterContainer* _truth_cluster_container + , ActsGeometry* _ActsGeometry + , PHG4TpcCylinderGeomContainer* _geom_container + ); }; #endif //TRACKBASE_PADPLANEREADOUTSTRUCT_H From be509602be98d467e98019b42647ebce3b9d2744 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 2 May 2023 16:57:51 -0400 Subject: [PATCH 318/468] remove instance from sphenixnpc, compatible with new nopayloadclient --- offline/database/sphenixnpc/sphenixnpc.cc | 19 ++++--------------- offline/database/sphenixnpc/sphenixnpc.h | 9 ++++----- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index c42b1450cc..e04d9a7b48 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -6,24 +6,13 @@ #include #include -sphenixnpc *sphenixnpc::__instance = nullptr; - -sphenixnpc *sphenixnpc::instance(const std::string &globaltag) +sphenixnpc::sphenixnpc(const std::string &globaltag) { - if (!__instance) - { - __instance = new sphenixnpc(); - } - __instance->cache_set_GlobalTag(globaltag); - return __instance; + cache_set_GlobalTag(globaltag); } -sphenixnpc::~sphenixnpc() -{ - __instance = nullptr; -} -int sphenixnpc::createGlobalTag(const std::string &tagname) +int sphenixnpc::createThisGlobalTag(const std::string &tagname) { setGlobalTag(tagname); nlohmann::json resp = nopayloadclient::Client::createGlobalTag(); @@ -39,7 +28,7 @@ int sphenixnpc::createGlobalTag(const std::string &tagname) return iret; } -int sphenixnpc::deleteGlobalTag(const std::string &tagname) +int sphenixnpc::deleteThisGlobalTag(const std::string &tagname) { setGlobalTag(tagname); nlohmann::json result = nopayloadclient::Client::deleteGlobalTag(); diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index c6ac0eb1b6..5301c42bea 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -17,11 +17,11 @@ class sphenixnpc : public nopayloadclient::Client using nopayloadclient::Client::deleteGlobalTag; using nopayloadclient::Client::setGlobalTag; - static sphenixnpc *instance(const std::string &globaltag = "NONE"); - ~sphenixnpc(); + sphenixnpc(const std::string &globaltag); + ~sphenixnpc() = default; nlohmann::json getUrlDict(long long iov); nlohmann::json getUrlDict(long long iov1, long long iov2) override; - int createGlobalTag(const std::string &tagname); + int createThisGlobalTag(const std::string &tagname); int createDomain(const std::string &domain); nlohmann::json get(const std::string &pl_type, long long iov); int cache_set_GlobalTag(const std::string &name); @@ -29,13 +29,12 @@ class sphenixnpc : public nopayloadclient::Client std::string getCalibrationFile(const std::string &type, uint64_t iov); int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); - int deleteGlobalTag(const std::string &); + int deleteThisGlobalTag(const std::string &); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } private: - static sphenixnpc *__instance; int m_Verbosity = 0; nlohmann::json url_dict_; // valid until global tag is switched std::string m_CachedGlobalTag; From 6de016607c80dc2b751e0c2f0b571ac16574ac85 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 2 May 2023 16:58:17 -0400 Subject: [PATCH 319/468] remove instance from sphenixnpc --- offline/framework/ffamodules/CDBInterface.cc | 11 ++++++++--- offline/framework/ffamodules/CDBInterface.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index a3c38cf933..4849f5c322 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -1,5 +1,7 @@ #include "CDBInterface.h" +#include + #include #include @@ -15,7 +17,7 @@ #include #include -#include +//#include #include @@ -120,9 +122,12 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f std::cout << "rc->set_uint64Flag(\"TIMESTAMP\",<64 bit timestamp>)" << std::endl; gSystem->Exit(1); } - sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); + if (cdbclient == nullptr) + { + cdbclient = new sphenixnpc(rc->get_StringFlag("CDB_GLOBALTAG")); + } uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); - std::string return_url = cdb->getCalibrationFile(domain,timestamp); + std::string return_url = cdbclient->getCalibrationFile(domain,timestamp); if (return_url.empty()) { return_url = filename; diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index b150b34616..c561adae20 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -11,6 +11,7 @@ #include // for tuple class PHCompositeNode; +class sphenixnpc; class CDBInterface : public SubsysReco { @@ -30,7 +31,7 @@ class CDBInterface : public SubsysReco CDBInterface(const std::string &name = "CDBInterface"); static CDBInterface *__instance; - + sphenixnpc *cdbclient = nullptr; std::set> m_UrlVector; }; From 60150841048a2b3a0cd9ee59b6e0817594242b57 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 2 May 2023 18:32:18 -0400 Subject: [PATCH 320/468] use CDBInterface instead of sphenixnpc --- offline/packages/CaloReco/CaloTowerCalib.cc | 23 +++++---------------- offline/packages/CaloReco/Makefile.am | 1 - 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerCalib.cc b/offline/packages/CaloReco/CaloTowerCalib.cc index 19c190827c..ce6dab159b 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.cc +++ b/offline/packages/CaloReco/CaloTowerCalib.cc @@ -19,7 +19,7 @@ #include #include -#include +#include #include //____________________________________________________________________________.. @@ -58,11 +58,8 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) std::cout << "at run" << m_runNumber << std::endl; if (m_dettype == CaloTowerCalib::CEMC) { - recoConsts *rc = recoConsts::instance(); // place holder - rc->set_StringFlag("CDB_GLOBALTAG", "CEMCCalibTest"); - sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); - std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); + std::string calibdir = CDBInterface::instance()->getUrl("TestBeginValidity"); m_detector = "CEMC"; m_DETECTOR = TowerInfoContainer::EMCAL; m_fieldname = "cemc_abscalib_mip"; @@ -78,10 +75,7 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else if (m_dettype == CaloTowerCalib::HCALIN) { - recoConsts *rc = recoConsts::instance(); - rc->set_StringFlag("CDB_GLOBALTAG", "HCalCalibTest"); - sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); - std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); + std::string calibdir = CDBInterface::instance()->getUrl("TestBeginValidity"); m_detector = "HCALIN"; m_DETECTOR = TowerInfoContainer::HCAL; m_fieldname = "ihcal_abscalib_mip"; @@ -97,10 +91,7 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else if (m_dettype == CaloTowerCalib::HCALOUT) { - recoConsts *rc = recoConsts::instance(); - rc->set_StringFlag("CDB_GLOBALTAG", "HCalCalibTest"); - sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); - std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); + std::string calibdir = CDBInterface::instance()->getUrl("TestBeginValidity"); m_detector = "HCALOUT"; m_DETECTOR = TowerInfoContainer::HCAL; m_fieldname = "ohcal_abscalib_mip"; @@ -116,11 +107,7 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else if (m_dettype == CaloTowerCalib::EPD) { - recoConsts *rc = recoConsts::instance(); - // place holder - rc->set_StringFlag("CDB_GLOBALTAG", "EPDCalibTest"); - sphenixnpc *cdb = sphenixnpc::instance(rc->get_StringFlag("CDB_GLOBALTAG")); - std::string calibdir = cdb->getCalibrationFile("TestBeginValidity", m_runNumber); + std::string calibdir = CDBInterface::instance()->getUrl("TestBeginValidity"); m_detector = "EPD"; m_DETECTOR = TowerInfoContainer::SEPD; m_fieldname = "EPD_abscalib_mip"; diff --git a/offline/packages/CaloReco/Makefile.am b/offline/packages/CaloReco/Makefile.am index 53f6136721..bb9eb2c376 100644 --- a/offline/packages/CaloReco/Makefile.am +++ b/offline/packages/CaloReco/Makefile.am @@ -26,7 +26,6 @@ libcalo_reco_la_LIBADD = \ -lgslcblas \ -lg4vertex_io \ -lsph_onnx \ - -lsphenixnpc \ -lphparameter \ -lphool \ -lSubsysReco From 9a580b3eff93a2c4e3458903821a08a43b05df54 Mon Sep 17 00:00:00 2001 From: David Stewart <0ds.johnny@gmail.com> Date: Tue, 2 May 2023 19:23:23 -0400 Subject: [PATCH 321/468] Jenkins logic update --- simulation/g4simulation/g4intt/PHG4InttHitReco.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc index 9012e90c4d..34190c5dda 100644 --- a/simulation/g4simulation/g4intt/PHG4InttHitReco.cc +++ b/simulation/g4simulation/g4intt/PHG4InttHitReco.cc @@ -516,7 +516,9 @@ void PHG4InttHitReco::SetDefaultParameters() } void PHG4InttHitReco::truthcheck_g4hit(PHG4Hit* g4hit, PHCompositeNode* topNode) { - int new_trkid = (g4hit==nullptr) ? -1 : g4hit->get_trkid(); + if (g4hit==nullptr) return; + int new_trkid = g4hit->get_trkid(); + bool is_new_track = (new_trkid != m_trkid); if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("< Date: Wed, 3 May 2023 07:21:02 -0400 Subject: [PATCH 322/468] fix memory leak --- offline/database/sphenixnpc/sphenixnpc.h | 2 +- offline/framework/ffamodules/CDBInterface.cc | 7 +++++++ offline/framework/ffamodules/CDBInterface.h | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 5301c42bea..17a75ae945 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -18,7 +18,7 @@ class sphenixnpc : public nopayloadclient::Client using nopayloadclient::Client::setGlobalTag; sphenixnpc(const std::string &globaltag); - ~sphenixnpc() = default; + virtual ~sphenixnpc() = default; nlohmann::json getUrlDict(long long iov); nlohmann::json getUrlDict(long long iov1, long long iov2) override; int createThisGlobalTag(const std::string &tagname); diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 4849f5c322..68242a79a3 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -46,6 +46,13 @@ CDBInterface::CDBInterface(const std::string &name) se->addNewSubsystem(this); } +//____________________________________________________________________________.. + +CDBInterface::~CDBInterface() +{ + delete cdbclient; +} + //____________________________________________________________________________.. int CDBInterface::End(PHCompositeNode *topNode) { diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index c561adae20..c86002cd18 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -18,7 +18,7 @@ class CDBInterface : public SubsysReco public: static CDBInterface *instance(); - ~CDBInterface() override {} + ~CDBInterface() override; /// Called at the end of all processing. int End(PHCompositeNode *topNode) override; From d699dfba8f56bba867f2a00995728e2ca6fb28b0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 May 2023 09:22:58 -0400 Subject: [PATCH 323/468] fix remaining g4vertex --- offline/packages/NodeDump/DumpGlobalVertexMap.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/NodeDump/DumpGlobalVertexMap.cc b/offline/packages/NodeDump/DumpGlobalVertexMap.cc index b7fd965420..a312ae70bc 100644 --- a/offline/packages/NodeDump/DumpGlobalVertexMap.cc +++ b/offline/packages/NodeDump/DumpGlobalVertexMap.cc @@ -1,7 +1,7 @@ #include "DumpGlobalVertexMap.h" -#include -#include +#include +#include #include From 36c4a6a14e4622a027e3d42a359f8fc6db252a65 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 3 May 2023 10:12:49 -0400 Subject: [PATCH 324/468] Preparing to push --- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index f4da5696b5..dc53c591f4 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -409,10 +409,10 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) const bool isRGap = cmclus->getIsRGap(); - // Do the static + average distortion corrections if the container was found + // Do the static + average distortion corrections if the container was found Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); if( m_dcc_in) pos = m_distortionCorrection.get_corrected_position( pos, m_dcc_in ); - + TVector3 tmp_pos(pos[0], pos[1], pos[2]); TVector3 tmp_pos1(cmclus->getX1(), cmclus->getY1(), cmclus->getZ1()); @@ -835,7 +835,7 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) } // input tpc distortion correction - m_dcc_in = findNode::getClass(topNode,"TpcDistortionCorrectionContainer"); + m_dcc_in = findNode::getClass(topNode,"TpcDistortionCorrectionContainerStatic"); if( m_dcc_in ) { std::cout << "PHTpcCentralMembraneMatcher: found TPC distortion correction container" << std::endl; @@ -865,38 +865,40 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) PHIODataNode *CMFlashDifferenceNode = new PHIODataNode(m_cm_flash_diffs, "CM_FLASH_DIFFERENCES", "PHObject"); DetNode->addNode(CMFlashDifferenceNode); + + + // output tpc fluctuation distortion container + // this one is filled on the fly on a per-CM-event basis, and applied in the tracking chain + const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; + m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); + if( !m_dcc_out ) + { + + /// Get the DST node and check + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "PHTpcCentralMembraneMatcher::InitRun - DST Node missing, quitting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // Get the tracking subnode and create if not found + auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); + if (!svtxNode) + { + svtxNode = new PHCompositeNode("SVTX"); + dstNode->addNode(svtxNode); + } + + std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; + m_dcc_out = new TpcDistortionCorrectionContainer; + auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); + svtxNode->addNode(node); + } -// // output tpc fluctuation distortion container -// // this one is filled on the fly on a per-CM-event basis, and applied in the tracking chain -// const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; -// m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); -// if( !m_dcc_out ) -// { -// -// /// Get the DST node and check -// auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); -// if (!dstNode) -// { -// std::cout << "PHTpcCentralMembraneMatcher::InitRun - DST Node missing, quitting" << std::endl; -// return Fun4AllReturnCodes::ABORTRUN; -// } -// -// // Get the tracking subnode and create if not found -// auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); -// if (!svtxNode) -// { -// svtxNode = new PHCompositeNode("SVTX"); -// dstNode->addNode(svtxNode); -// } -// -// std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; -// m_dcc_out = new TpcDistortionCorrectionContainer; -// auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); -// svtxNode->addNode(node); -// } - - // create per event distortions. Do not put on the node tree - m_dcc_out = new TpcDistortionCorrectionContainer; + +// // create per event distortions. Do not put on the node tree +// m_dcc_out = new TpcDistortionCorrectionContainer; // also prepare the local distortion container, used to aggregate multple events m_dcc_out_aggregated.reset( new TpcDistortionCorrectionContainer ); From 2b93ef120621d8c0ab4b0fb4dd923464f1aca78d Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 3 May 2023 10:22:36 -0400 Subject: [PATCH 325/468] Removed putting Fluctuation distortions on node tree. Further workflow development needed first. --- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index dc53c591f4..846805e6fa 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -268,6 +268,7 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) hnclus = new TH1F("hnclus", " nclusters ", 3, 0., 3.); fout2.reset ( new TFile(m_histogramfilename2.c_str(),"RECREATE") ); + match_ntup = new TNtuple("match_ntup","Match NTuple","event:truthR:truthPhi:recoR:recoPhi:recoZ:nclus:r1:phi1:e1:layer1:r2:phi2:e2:layer2"); } hit_r_phi = new TH2F("hit_r_phi","hit r vs #phi;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); @@ -275,7 +276,6 @@ int PHTpcCentralMembraneMatcher::InitRun(PHCompositeNode *topNode) clust_r_phi_pos = new TH2F("clust_r_phi_pos","clust R vs #phi Z>0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); clust_r_phi_neg = new TH2F("clust_r_phi_neg","clust R vs #phi Z<0;#phi (rad); r (cm)",360,-M_PI,M_PI,500,0,100); - match_ntup = new TNtuple("match_ntup","Match NTuple","event:truthR:truthPhi:recoR:recoPhi:recoZ:nclus:r1:phi1:e1:layer1:r2:phi2:e2:layer2"); // Get truth cluster positions //===================== @@ -689,8 +689,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) cmdiff->setNclusters(nclus); m_cm_flash_diffs->addDifferenceSpecifyKey(key, cmdiff); - - match_ntup->Fill(m_event_index,m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z(),nclus,pos1[p.second].Perp(),pos1[p.second].Phi(),adc1[p.second],layer1[p.second],pos2[p.second].Perp(),pos2[p.second].Phi(),adc2[p.second],layer2[p.second]); + + if(m_savehistograms) match_ntup->Fill(m_event_index,m_truth_pos[p.first].Perp(),m_truth_pos[p.first].Phi(),reco_pos[p.second].Perp(),reco_pos[p.second].Phi(),reco_pos[p.second].Z(),nclus,pos1[p.second].Perp(),pos1[p.second].Phi(),adc1[p.second],layer1[p.second],pos2[p.second].Perp(),pos2[p.second].Phi(),adc2[p.second],layer2[p.second]); // store cluster position const double clus_r = reco_pos[p.second].Perp(); @@ -867,38 +867,38 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) DetNode->addNode(CMFlashDifferenceNode); - // output tpc fluctuation distortion container - // this one is filled on the fly on a per-CM-event basis, and applied in the tracking chain - const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; - m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); - if( !m_dcc_out ) - { + //// output tpc fluctuation distortion container + //// this one is filled on the fly on a per-CM-event basis, and applied in the tracking chain + //const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; + //m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); + //if( !m_dcc_out ) + //{ - /// Get the DST node and check - auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << "PHTpcCentralMembraneMatcher::InitRun - DST Node missing, quitting" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + // /// Get the DST node and check + // auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + // if (!dstNode) + // { + // std::cout << "PHTpcCentralMembraneMatcher::InitRun - DST Node missing, quitting" << std::endl; + // return Fun4AllReturnCodes::ABORTRUN; + // } - // Get the tracking subnode and create if not found - auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); - if (!svtxNode) - { - svtxNode = new PHCompositeNode("SVTX"); - dstNode->addNode(svtxNode); - } + // // Get the tracking subnode and create if not found + // auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); + // if (!svtxNode) + // { + // svtxNode = new PHCompositeNode("SVTX"); + // dstNode->addNode(svtxNode); + // } - std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; - m_dcc_out = new TpcDistortionCorrectionContainer; - auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); - svtxNode->addNode(node); - } + // std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; + // m_dcc_out = new TpcDistortionCorrectionContainer; + // auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); + // svtxNode->addNode(node); + // } -// // create per event distortions. Do not put on the node tree -// m_dcc_out = new TpcDistortionCorrectionContainer; + // create per event distortions. Do not put on the node tree + m_dcc_out = new TpcDistortionCorrectionContainer; // also prepare the local distortion container, used to aggregate multple events m_dcc_out_aggregated.reset( new TpcDistortionCorrectionContainer ); From 8ae3b54cdcec826681bf279316ff7421fecf29e3 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 May 2023 11:06:39 -0400 Subject: [PATCH 326/468] more build updates --- simulation/g4simulation/g4dst/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4dst/Makefile.am b/simulation/g4simulation/g4dst/Makefile.am index 83fdaf4f30..c8e9be23e5 100644 --- a/simulation/g4simulation/g4dst/Makefile.am +++ b/simulation/g4simulation/g4dst/Makefile.am @@ -24,7 +24,7 @@ libg4dst_la_LDFLAGS = \ -lg4intt_io \ -lg4jets_io \ -lg4tracking_io \ - -lg4vertex_io \ + -lglobalvertex_io \ -lintt_io \ -ljetbackground_io \ -lkfparticle_sphenix_io \ From ed55af381e944b6c81bee98517b605a0b852cbb7 Mon Sep 17 00:00:00 2001 From: timothyrinn <45397780+timothyrinn@users.noreply.github.com> Date: Wed, 3 May 2023 14:18:07 -0400 Subject: [PATCH 327/468] Add pedestal subtraction to the software zero suppression This change adds the pedestal subtraction to the software zero suppression so that it returns values consistent with the nominal data. --- offline/packages/CaloReco/CaloWaveformFitting.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 40e491f1ac..e8436f9dc1 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -90,7 +90,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit { // std::cout << "software zero suppression happened " << std::endl; h->Delete(); - v.push_back(v.at(6)); + v.push_back(v.at(6) - pedestal); v.push_back(-1); v.push_back(pedestal); } From b2e85625de3220790678431e1f31731e128323b8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 May 2023 15:17:15 -0400 Subject: [PATCH 328/468] fix tangent vector --- offline/packages/trackreco/ActsAlignmentStates.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index f56bcd6733..2d3d69d496 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -134,11 +134,11 @@ void ActsAlignmentStates::fillAlignmentStateMap(const Trajectory& traj, /// The local bound parameters still have access to global phi/theta double phi = state.smoothed()[Acts::eBoundPhi]; double theta = state.smoothed()[Acts::eBoundTheta]; + Acts::Vector3 tangent = Acts::makeDirectionUnitFromPhiTheta(phi,theta); - //! charge for phi is switched in Acts - tangent(0) *= -1; - tangent(1) *= -1; - + //! opposite convention for coordinates in Acts + tangent *= -1; + if(m_verbosity > 2) { std::cout << "tangent vector to track state is " << tangent.transpose() << std::endl; @@ -243,7 +243,8 @@ std::pair ActsAlignmentStates::get_projectionXY(co projx = X - (tangent.dot(X) / tangent.dot(Z)) * Z; projy = Y - (tangent.dot(Y) / tangent.dot(Z)) * Z; - + if(m_verbosity > 2) + std::cout << "projxy " << projx.transpose() << ", " << projy.transpose() << std::endl; return std::make_pair(projx, projy); } From 621ad05e39bbe961dfe6decedf565ad447992bc8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 May 2023 15:50:18 -0400 Subject: [PATCH 329/468] makemillefiles produces correct derivatives --- offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index 7c21f9276b..bfdc030dfa 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -367,7 +367,7 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve for (int j = 0; j < SvtxAlignmentState::NGL; ++j) { /// swap the order to match what is expected from the workflow - glbl_derivative[j] = state->get_global_derivative_matrix()(i, (j + 3) % SvtxAlignmentState::NGL); + glbl_derivative[j] = state->get_global_derivative_matrix()(i, j); if (is_layer_fixed(layer) || is_layer_param_fixed(layer, j)) { @@ -387,6 +387,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve for (int k = 0; k < SvtxAlignmentState::NGL; k++) { + if(glbl_derivative[k] > 0 || glbl_derivative[k] < 0) + std::cout << "NONZERO GLOBAL DERIVATIVE"< Date: Thu, 4 May 2023 09:05:13 -0400 Subject: [PATCH 330/468] fix bbc th1 --- offline/packages/bbc/BbcReconstruction.cc | 28 +++++++++++------------ offline/packages/bbc/BbcReconstruction.h | 3 ++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/offline/packages/bbc/BbcReconstruction.cc b/offline/packages/bbc/BbcReconstruction.cc index f8fff262a9..ee29f6d3b7 100644 --- a/offline/packages/bbc/BbcReconstruction.cc +++ b/offline/packages/bbc/BbcReconstruction.cc @@ -23,6 +23,8 @@ BbcReconstruction::BbcReconstruction(const std::string &name) : SubsysReco(name) { + h_evt_bbct[0] = nullptr; + h_evt_bbct[1] = nullptr; } //____________________________________________________________________________.. @@ -36,6 +38,18 @@ int BbcReconstruction::Init(PHCompositeNode *) m_gaussian = std::make_unique("gaussian", "gaus", 0, 20); m_gaussian->FixParameter(2, m_tres); + TString name, title; + for (int iarm = 0; iarm < 2; iarm++) + { + // + name = "hevt_bbct"; + name += iarm; + title = "bbc times, arm "; + title += iarm; + h_evt_bbct[iarm] = new TH1F(name, title, 200, 7.5, 11.5); + h_evt_bbct[iarm]->SetLineColor(4); + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -54,20 +68,6 @@ int BbcReconstruction::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int BbcReconstruction::process_event(PHCompositeNode *) { - TH1 *h_evt_bbct[2]{}; - h_evt_bbct[0] = nullptr; - h_evt_bbct[1] = nullptr; - TString name, title; - for (int iarm = 0; iarm < 2; iarm++) - { - // - name = "hevt_bbct"; - name += iarm; - title = "bbc times, arm "; - title += iarm; - h_evt_bbct[iarm] = new TH1F(name, title, 200, 7.5, 11.5); - h_evt_bbct[iarm]->SetLineColor(4); - } std::vector hit_times[2]; float bbcq[2] = {0}; diff --git a/offline/packages/bbc/BbcReconstruction.h b/offline/packages/bbc/BbcReconstruction.h index 0da97c43f7..7229100225 100644 --- a/offline/packages/bbc/BbcReconstruction.h +++ b/offline/packages/bbc/BbcReconstruction.h @@ -12,6 +12,7 @@ class PHCompositeNode; class BbcPmtContainer; class BbcVertexMap; class TF1; +class TH1; class BbcReconstruction : public SubsysReco { @@ -31,7 +32,7 @@ class BbcReconstruction : public SubsysReco std::unique_ptr m_gaussian = nullptr; float m_tres = 0.05; - + TH1 *h_evt_bbct[2]; BbcVertexMap *m_bbcvertexmap = nullptr; BbcPmtContainer *m_bbcpmts = nullptr; }; From bd0e30931b4a71f7031065d65e287c37366971a7 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 10:31:31 -0400 Subject: [PATCH 331/468] read from cdb if file is available --- offline/packages/trackreco/MakeActsGeometry.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 4824a22b0a..67586dec40 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -35,6 +35,8 @@ #include #include +#include + #include #include #include @@ -477,13 +479,15 @@ void MakeActsGeometry::buildActsSurfaces() } char *calibrationsroot = getenv("CALIBRATIONROOT"); m_magField = "sphenix3dtrackingmapxyz.root"; + + std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", + m_magField); + if (calibrationsroot != nullptr) { m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - //m_magField = std::string("/phenix/u/bogui/data/Field/sphenix3dtrackingmapxyz.root"); - //m_magField = std::string("/phenix/u/bogui/data/Field/sphenix3dbigmapxyz.root"); - + argstr[7] = "--bf-map-file"; argstr[8] = m_magField; argstr[9]= "--bf-map-tree"; From d2bb721f410b481ed753d5953176cfd76a20da98 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 10:31:58 -0400 Subject: [PATCH 332/468] trigger jenkins From 384903514326d05677c4c87b5f791f7e445e29d8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 11:54:51 -0400 Subject: [PATCH 333/468] fix cdb lookup --- offline/packages/trackreco/MakeActsGeometry.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 67586dec40..61c3407815 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -480,9 +480,8 @@ void MakeActsGeometry::buildActsSurfaces() char *calibrationsroot = getenv("CALIBRATIONROOT"); m_magField = "sphenix3dtrackingmapxyz.root"; - std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", - m_magField); - + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING"); + if (calibrationsroot != nullptr) { m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; From b40918a01206f602a662ab6b9d2ed60d515fbcfa Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 12:34:45 -0400 Subject: [PATCH 334/468] commit after git down From 0fd0381e396838895ad4d529282378a80be85ce7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 4 May 2023 15:25:44 -0400 Subject: [PATCH 335/468] remove libg4vertex_io remnants --- simulation/g4simulation/g4vertex/Makefile.am | 8 -------- 1 file changed, 8 deletions(-) diff --git a/simulation/g4simulation/g4vertex/Makefile.am b/simulation/g4simulation/g4vertex/Makefile.am index d38ae39a89..7812996dcd 100644 --- a/simulation/g4simulation/g4vertex/Makefile.am +++ b/simulation/g4simulation/g4vertex/Makefile.am @@ -12,11 +12,6 @@ AM_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib -libg4vertex_io_la_LIBADD = \ - -lphool \ - -ltrackbase_historic_io \ - -lglobalvertex_io - libg4vertex_la_LIBADD = \ -lbbc_io \ -lg4detectors \ @@ -42,14 +37,11 @@ libg4vertex_la_SOURCES = \ # linking tests noinst_PROGRAMS = \ - testexternals_g4vertex_io \ testexternals_g4vertex BUILT_SOURCES = \ testexternals.cc -testexternals_g4vertex_io_SOURCES = testexternals.cc - testexternals_g4vertex_SOURCES = testexternals.cc testexternals_g4vertex_LDADD = libg4vertex.la From c948013c53333929be575a6156f13c2877414635 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Thu, 4 May 2023 15:51:12 -0400 Subject: [PATCH 336/468] new stepping that directly add energy to towerinfo --- simulation/g4simulation/g4ihcal/Makefile.am | 1 + .../g4ihcal/PHG4IHCalSteppingAction.cc | 190 ++++++++++++++-- .../g4ihcal/PHG4IHCalSteppingAction.h | 12 +- .../g4ihcal/PHG4IHCalSubsystem.cc | 9 +- .../g4simulation/g4main/PHG4SteppingAction.h | 3 +- simulation/g4simulation/g4ohcal/Makefile.am | 1 + .../g4ohcal/PHG4OHCalSteppingAction.cc | 202 ++++++++++++++++-- .../g4ohcal/PHG4OHCalSteppingAction.h | 11 +- .../g4ohcal/PHG4OHCalSubsystem.cc | 7 +- 9 files changed, 391 insertions(+), 45 deletions(-) diff --git a/simulation/g4simulation/g4ihcal/Makefile.am b/simulation/g4simulation/g4ihcal/Makefile.am index dc362413e5..9745693c9e 100644 --- a/simulation/g4simulation/g4ihcal/Makefile.am +++ b/simulation/g4simulation/g4ihcal/Makefile.am @@ -17,6 +17,7 @@ AM_LDFLAGS = \ -L$(ROOTSYS)/lib libg4ihcal_la_LIBADD = \ + -lcalo_io \ -lfun4all \ -lphg4hit \ -lg4detectors diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc index 66122f3fea..f02ee3c9f2 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc @@ -13,8 +13,20 @@ #include // for PHG4SteppingAction #include +#include +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include +#include + +#include +#include +#include +#include + #include // Root headers @@ -24,22 +36,22 @@ #include // for G4ParticleDefinition #include // for G4ReferenceCountedHandle #include -#include // for G4StepPoint -#include // for fGeomBoundary, fAtRest... -#include // for G4String +#include // for G4StepPoint +#include // for fGeomBoundary, fAtRest... +#include // for G4String #include -#include // for G4ThreeVector -#include // for G4TouchableHandle -#include // for G4Track -#include // for fStopAndKill +#include // for G4ThreeVector +#include // for G4TouchableHandle +#include // for G4Track +#include // for fStopAndKill #include -#include // for G4double -#include // for G4VPhysicalVolume -#include // for G4VTouchable -#include // for G4VUserTrackInformation +#include // for G4double +#include // for G4VPhysicalVolume +#include // for G4VTouchable +#include // for G4VUserTrackInformation -#include // for isfinite -#include // for getenv +#include // for isfinite +#include // for getenv #include #include #include // for operator<<, operator+ @@ -55,6 +67,9 @@ PHG4IHCalSteppingAction::PHG4IHCalSteppingAction(PHG4IHCalDetector* detector, co , m_IsActive(m_Params->get_int_param("active")) , m_IsBlackHole(m_Params->get_int_param("blackhole")) , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model")) + , m_doG4Hit(m_Params->get_int_param("saveg4hit")) + , m_tmin(m_Params->get_double_param("tmin")) + , m_tmax(m_Params->get_double_param("tmax")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -74,7 +89,7 @@ PHG4IHCalSteppingAction::~PHG4IHCalSteppingAction() } //____________________________________________________________________________.. -int PHG4IHCalSteppingAction::Init() +int PHG4IHCalSteppingAction::InitWithNode(PHCompositeNode* topNode) { if (m_LightScintModelFlag) { @@ -100,12 +115,131 @@ int PHG4IHCalSteppingAction::Init() file->Close(); delete file; } + if (!m_doG4Hit) + { + try + { + CreateNodeTree(topNode); + } + catch (std::exception& e) + { + std::cout << e.what() << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + topNode->print(); + } + return 0; } +//____________________________________________________________________________.. +bool PHG4IHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) +{ + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); + G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); + // get volume of the current step + G4VPhysicalVolume* volume = touch->GetVolume(); + + // m_Detector->IsInIHCal(volume) + // returns + // 0 is outside of IHCal + // 1 is inside scintillator + // -1 is steel absorber + + int whichactive = m_Detector->IsInIHCal(volume); + + if (!whichactive) + { + return false; + } + int layer_id = -1; + int tower_id = -1; + // int sector_id = -1; + if (whichactive > 0) // scintillator + { + std::tuple layer_tower = m_Detector->GetLayerTowerId(volume); + // sector_id = std::get<0>(layer_tower); + layer_id = std::get<1>(layer_tower); + tower_id = std::get<2>(layer_tower); + + // std::cout<<"******** Inner HCal\t"<GetName()<<"\t"<GetPreStepPoint(); + G4StepPoint* postPoint = aStep->GetPostStepPoint(); + // time window cut + double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); + if (time < m_tmin || time > m_tmax) return false; + G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; + const G4Track* aTrack = aStep->GetTrack(); + // we only need visible energy here + double light_yield = eion; + + // correct evis using light map + if (m_LightScintModelFlag) + { + light_yield = GetVisibleEnergyDeposition(aStep); + if (m_MapCorrHist) + { + const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle(); + const G4ThreeVector& worldPosition = postPoint->GetPosition(); + G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition); + float lx = localPosition.x() / cm; + float ly = localPosition.y() / cm; + + // adjust to tilemap coordinates + int lcx = (int) (5.0 * lx) + 1; + int lcy = (int) (5.0 * (ly + 2.0)) + 1; + + if ((lcy >= 1) && (lcy <= m_MapCorrHist->GetNbinsY()) && + (lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsX())) + { + light_yield *= m_MapCorrHist->GetBinContent(lcx, lcy); + } + else + { + light_yield = 0.0; + } + } + else + { + light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y()); + } + } + // find the tower index for this step, tower_id is ieta, layer_id/4 is iphi + unsigned int ieta = tower_id; + unsigned int iphi = (unsigned int) layer_id / 4; + unsigned int tower_key = TowerInfoDefs::encode_hcal(ieta, iphi); + m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield); + // set keep for the track + if (light_yield > 0) + { + if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + { + if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + { + pp->SetKeep(1); // we want to keep the track + } + } + } + + return true; +} //____________________________________________________________________________.. bool PHG4IHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { + if ((!m_doG4Hit) && (!m_IsBlackHole)) + { + return NoHitSteppingAction(aStep); + } + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); // get volume of the current step @@ -222,18 +356,18 @@ bool PHG4IHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { m_Hit = new PHG4Hitv1(); } - //here we set the entrance values in cm + // here we set the entrance values in cm m_Hit->set_x(0, prePoint->GetPosition().x() / cm); m_Hit->set_y(0, prePoint->GetPosition().y() / cm); m_Hit->set_z(0, prePoint->GetPosition().z() / cm); // time in ns m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond); - //set and save the track ID + // set and save the track ID m_Hit->set_trkid(aTrack->GetTrackID()); m_SaveTrackId = aTrack->GetTrackID(); - //set the initial energy deposit + // set the initial energy deposit m_Hit->set_edep(0); - if (whichactive > 0) // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber + if (whichactive > 0) // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber { m_Hit->set_sector(sector_id); // the slat id m_Hit->set_scint_id(tower_id); // the slat id @@ -302,7 +436,7 @@ bool PHG4IHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond); - //sum up the energy to get total deposited + // sum up the energy to get total deposited m_Hit->set_edep(m_Hit->get_edep() + edep); if (whichactive > 0) // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber { @@ -320,7 +454,7 @@ bool PHG4IHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) float lx = localPosition.x() / cm; float ly = localPosition.y() / cm; - //adjust to tilemap coordinates + // adjust to tilemap coordinates int lcx = (int) (5.0 * lx) + 1; int lcy = (int) (5.0 * (ly + 2.0)) + 1; @@ -436,3 +570,19 @@ void PHG4IHCalSteppingAction::SetHitNodeName(const std::string& type, const std: gSystem->Exit(1); return; } + +void PHG4IHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) +{ + PHNodeIterator nodeItr(topNode); + PHCompositeNode* dst_node = dynamic_cast( + nodeItr.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cout << "PHComposite node created: DST" << std::endl; + dst_node = new PHCompositeNode("DST"); + topNode->addNode(dst_node); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERS_HCALIN", "PHObject"); + dst_node->addNode(towerNode); +} diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h index 244fead22e..7918a12c55 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h @@ -10,6 +10,7 @@ class G4Step; class G4VPhysicalVolume; class PHCompositeNode; +class TowerInfoContainer; class PHG4IHCalDetector; class PHParameters; class PHG4Hit; @@ -29,14 +30,17 @@ class PHG4IHCalSteppingAction : public PHG4SteppingAction //! stepping action bool UserSteppingAction(const G4Step *, bool) override; - int Init() override; + int InitWithNode(PHCompositeNode *topNode) override; //! reimplemented from base class void SetInterfacePointers(PHCompositeNode *) override; void SetHitNodeName(const std::string &type, const std::string &name) override; + void CreateNodeTree(PHCompositeNode *topNode); + private: + bool NoHitSteppingAction(const G4Step *aStep); //! pointer to the detector PHG4IHCalDetector *m_Detector = nullptr; @@ -61,8 +65,14 @@ class PHG4IHCalSteppingAction : public PHG4SteppingAction int m_IsActive = 0; int m_IsBlackHole = 0; int m_LightScintModelFlag = 0; + bool m_doG4Hit = true; + double m_tmin = -20.; + double m_tmax = 60.; + std::string m_AbsorberNodeName; std::string m_HitNodeName; + + TowerInfoContainer *m_CaloInfoContainer = nullptr; }; #endif // G4IHCAL_PHG4IHCALSTEPPINGACTION_H diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc index 0a0fabf553..7bce1f968a 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc @@ -95,7 +95,7 @@ int PHG4IHCalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) // create stepping action m_SteppingAction = new PHG4IHCalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); m_SteppingAction->SetHitNodeName("G4HIT", m_HitNodeName); m_SteppingAction->SetHitNodeName("G4HIT_ABSORBER", m_AbsorberNodeName); } @@ -105,7 +105,7 @@ int PHG4IHCalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) if (GetParams()->get_int_param("blackhole")) { m_SteppingAction = new PHG4IHCalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } } return 0; @@ -161,11 +161,16 @@ void PHG4IHCalSubsystem::SetDefaultParameters() set_default_double_param("rot_z", 0.); set_default_double_param("size_z", 435.000 + 10 ); set_default_double_param("Birk_const", 0.07943); + set_default_double_param("tmin", -20.); + set_default_double_param("tmax", 60.); + set_default_int_param("light_scint_model", 1); set_default_int_param(PHG4HcalDefs::n_towers, 64); set_default_int_param(PHG4HcalDefs::scipertwr, 4); set_default_int_param(PHG4HcalDefs::n_scinti_tiles, 12); + set_default_int_param("saveg4hit", 1); + set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); const char* Calibroot = getenv("CALIBRATIONROOT"); diff --git a/simulation/g4simulation/g4main/PHG4SteppingAction.h b/simulation/g4simulation/g4main/PHG4SteppingAction.h index d16ab02a0d..7911367f07 100644 --- a/simulation/g4simulation/g4main/PHG4SteppingAction.h +++ b/simulation/g4simulation/g4main/PHG4SteppingAction.h @@ -29,6 +29,7 @@ class PHG4SteppingAction virtual void Verbosity(const int i) { m_Verbosity = i; } virtual int Verbosity() const { return m_Verbosity; } virtual int Init() { return 0; } + virtual int InitWithNode(PHCompositeNode* ){ return 0; }; //! get scintillation photon count. It require a custom set SCINTILLATIONYIELD property to work virtual double GetScintLightYield(const G4Step* step); @@ -48,7 +49,7 @@ class PHG4SteppingAction virtual bool ValidCorrection() const; //! Set the G4HIT node names from Subsystem rather than constructing your own - virtual void SetHitNodeName(const std::string &, const std::string &) {return;} + virtual void SetHitNodeName(const std::string&, const std::string&) { return; } private: int m_Verbosity; diff --git a/simulation/g4simulation/g4ohcal/Makefile.am b/simulation/g4simulation/g4ohcal/Makefile.am index 828e6bc53e..8f5acc4568 100644 --- a/simulation/g4simulation/g4ohcal/Makefile.am +++ b/simulation/g4simulation/g4ohcal/Makefile.am @@ -17,6 +17,7 @@ AM_LDFLAGS = \ -L$(ROOTSYS)/lib libg4ohcal_la_LIBADD = \ + -lcalo_io \ -lfun4all \ -lphg4hit \ -lg4detectors diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc index b06f101c2e..7473b4dfcb 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc @@ -16,10 +16,20 @@ #include // for PHG4SteppingAction #include +#include #include +#include +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include -#include + +#include +#include +#include +#include // Root headers #include // for TAxis @@ -33,25 +43,25 @@ #include // for G4AffineTransform #include #include -#include // for G4LogicalVolume -#include // for G4NavigationHistory -#include // for G4ParticleDefinition +#include // for G4LogicalVolume +#include // for G4NavigationHistory +#include // for G4ParticleDefinition #include #include // for G4ReferenceCountedHandle #include -#include // for G4StepPoint -#include // for fGeomBoundary, fAtRest... -#include // for G4String +#include // for G4StepPoint +#include // for fGeomBoundary, fAtRest... +#include // for G4String #include -#include // for G4ThreeVector -#include // for G4TouchableHandle -#include // for G4Track -#include // for fStopAndKill +#include // for G4ThreeVector +#include // for G4TouchableHandle +#include // for G4Track +#include // for fStopAndKill #include -#include // for G4double -#include // for G4VPhysicalVolume -#include // for G4VTouchable -#include // for G4VUserTrackInformation +#include // for G4double +#include // for G4VPhysicalVolume +#include // for G4VTouchable +#include // for G4VUserTrackInformation // finally system headers #include @@ -73,6 +83,9 @@ PHG4OHCalSteppingAction::PHG4OHCalSteppingAction(PHG4OHCalDetector* detector, co , m_IsBlackHoleFlag(m_Params->get_int_param("blackhole")) , m_NScintiPlates(m_Params->get_int_param(PHG4HcalDefs::scipertwr) * m_Params->get_int_param("n_towers")) , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model")) + , m_doG4Hit(m_Params->get_int_param("saveg4hit")) + , m_tmin(m_Params->get_double_param("tmin")) + , m_tmax(m_Params->get_double_param("tmax")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -99,7 +112,7 @@ PHG4OHCalSteppingAction::~PHG4OHCalSteppingAction() } } -int PHG4OHCalSteppingAction::Init() +int PHG4OHCalSteppingAction::InitWithNode(PHCompositeNode* topNode) { m_EnableFieldCheckerFlag = m_Params->get_int_param("field_check"); @@ -145,12 +158,151 @@ int PHG4OHCalSteppingAction::Init() file->Close(); delete file; } + if (!m_doG4Hit) + { + try + { + CreateNodeTree(topNode); + } + catch (std::exception& e) + { + std::cout << e.what() << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + topNode->print(); + } return 0; } +//____________________________________________________________________________.. +bool PHG4OHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) +{ + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); + G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); + // get volume of the current step + G4VPhysicalVolume* volume = touch->GetVolume(); + + // m_Detector->IsInIHCal(volume) + // returns + // 0 is outside of IHCal + // 1 is inside scintillator + // -1 is steel absorber + + int whichactive = m_Detector->IsInOHCal(volume); + + if (!whichactive) + { + return false; + } + if (m_EnableFieldCheckerFlag) + { + FieldChecker(aStep); + } + int layer_id = -1; + int tower_id = -1; + int sector_id = -1; + if (whichactive > 0) // scintillator + { + std::tuple layer_tower = m_Detector->GetRowColumnId(volume); + sector_id = std::get<0>(layer_tower); + layer_id = std::get<1>(layer_tower); + tower_id = std::get<2>(layer_tower); + + //std::cout<<"******** Outer HCal\t"<GetName()<<"\t"<GetPreStepPoint(); + G4StepPoint* postPoint = aStep->GetPostStepPoint(); + // time window cut + double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); + if (time < m_tmin || time > m_tmax) return false; + G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; + const G4Track* aTrack = aStep->GetTrack(); + // we only need visible energy here + double light_yield = eion; + + // correct evis using light map + if (m_LightScintModelFlag) + { + light_yield = GetVisibleEnergyDeposition(aStep); + if ((m_MapCorrHistChim[tower_id]) || (m_MapCorrHist[tower_id])) + { + const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle(); + const G4ThreeVector& worldPosition = postPoint->GetPosition(); + G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition); + float lx = (localPosition.x() / cm); + float ly = (localPosition.y() / cm); + + // convert to the map bin coordinates: + int lcx = (int) (2.0 * lx) + 1; + int lcy = (int) (2.0 * (ly + 0.5)) + 1; + + if ((sector_id == 29) || (sector_id == 30) || (sector_id == 31)) + { + if ((lcy >= 1) && (lcy <= m_MapCorrHistChim[tower_id]->GetNbinsY()) && + (lcx >= 1) && (lcx <= m_MapCorrHistChim[tower_id]->GetNbinsX())) + { + light_yield *= (double) (m_MapCorrHistChim[tower_id]->GetBinContent(lcx, lcy)); + } + else + { + light_yield = 0.0; + } + } + else + { + if ((lcy >= 1) && (lcy <= m_MapCorrHist[tower_id]->GetNbinsY()) && + (lcx >= 1) && (lcx <= m_MapCorrHist[tower_id]->GetNbinsX())) + { + light_yield *= (double) (m_MapCorrHist[tower_id]->GetBinContent(lcx, lcy)); + } + else + { + light_yield = 0.0; + } + } + } + else + { + // old correction (linear ligh yield dependence along r), never tested + light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y()); + } + } + // find the tower index for this step, tower_id is ieta, layer_id/5 is iphi + unsigned int ieta = tower_id; + unsigned int iphi = (unsigned int) layer_id / 5; + unsigned int tower_key = TowerInfoDefs::encode_hcal(ieta, iphi); + m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield); + // set keep for the track + if (light_yield > 0) + { + if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + { + if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + { + pp->SetKeep(1); // we want to keep the track + } + } + } + + return true; +} + //____________________________________________________________________________.. bool PHG4OHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was_used*/) { + if ((!m_doG4Hit) && (!m_IsBlackHoleFlag)) + { + return NoHitSteppingAction(aStep); + } + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); // get volume of the current step @@ -284,7 +436,7 @@ bool PHG4OHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was m_SaveTrackId = aTrack->GetTrackID(); // set the initial energy deposit m_Hit->set_edep(0); - if (whichactive > 0) // return of IsInOHCalDetector, > 0 hit in scintillator, < 0 hit in absorber + if (whichactive > 0) // return of IsInOHCalDetector, > 0 hit in scintillator, < 0 hit in absorber { m_Hit->set_sector(sector_id); // the sector id m_Hit->set_scint_id(tower_id); // the slat id @@ -576,3 +728,19 @@ void PHG4OHCalSteppingAction::SetHitNodeName(const std::string& type, const std: gSystem->Exit(1); return; } + +void PHG4OHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) +{ + PHNodeIterator nodeItr(topNode); + PHCompositeNode* dst_node = dynamic_cast( + nodeItr.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cout << "PHComposite node created: DST" << std::endl; + dst_node = new PHCompositeNode("DST"); + topNode->addNode(dst_node); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERS_HCALOUT", "PHObject"); + dst_node->addNode(towerNode); +} diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h index 0cece6b355..0c5079c9d9 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h @@ -10,6 +10,7 @@ class G4Step; class G4VPhysicalVolume; class PHCompositeNode; +class TowerInfoContainer; class PHG4OHCalDetector; class PHParameters; class PHG4Hit; @@ -29,7 +30,7 @@ class PHG4OHCalSteppingAction : public PHG4SteppingAction //! stepping action bool UserSteppingAction(const G4Step *, bool) override; - int Init() override; + int InitWithNode(PHCompositeNode *topNode) override; //! reimplemented from base class void SetInterfacePointers(PHCompositeNode *) override; @@ -38,8 +39,9 @@ class PHG4OHCalSteppingAction : public PHG4SteppingAction void FieldChecker(const G4Step *); void EnableFieldChecker(const int i = 1) { m_EnableFieldCheckerFlag = i; } - + void CreateNodeTree(PHCompositeNode *topNode); private: + bool NoHitSteppingAction(const G4Step *aStep); //! pointer to the detector PHG4OHCalDetector *m_Detector = nullptr; @@ -68,8 +70,13 @@ class PHG4OHCalSteppingAction : public PHG4SteppingAction int m_IsBlackHoleFlag = 0; int m_NScintiPlates = -1; int m_LightScintModelFlag = 0; + bool m_doG4Hit = true; + double m_tmin = -20.; + double m_tmax = 60.; std::string m_AbsorberNodeName; std::string m_HitNodeName; + + TowerInfoContainer *m_CaloInfoContainer = nullptr; }; #endif // G4OHCAL_PHG4OHCALSTEPPINGACTION_H diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc index d9f44be414..3462a388ad 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc @@ -98,7 +98,7 @@ int PHG4OHCalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) } // create stepping action m_SteppingAction = new PHG4OHCalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); m_SteppingAction->SetHitNodeName("G4HIT", m_HitNodeName); m_SteppingAction->SetHitNodeName("G4HIT_ABSORBER", m_AbsorberNodeName); } @@ -107,7 +107,7 @@ int PHG4OHCalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) if (GetParams()->get_int_param("blackhole")) { m_SteppingAction = new PHG4OHCalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } } @@ -168,12 +168,15 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_double_param("rot_z", 0.); set_default_double_param("size_z", 639.240 + 10); set_default_double_param("Birk_const", 0.07943); + set_default_double_param("tmin", -20.); + set_default_double_param("tmax", 60.); set_default_int_param("field_check", 0); set_default_int_param("light_scint_model", 1); set_default_int_param("n_towers", 64); set_default_int_param(PHG4HcalDefs::scipertwr, 5); set_default_int_param("n_scinti_tiles", 12); + set_default_int_param("saveg4hit", 1); set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); std::string defaultmapfilename; From 69f8cd367e6ee6cbe701fde6243cbc856a131c96 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 20:56:57 -0400 Subject: [PATCH 337/468] fix field map lookup --- offline/packages/trackreco/MakeActsGeometry.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 61c3407815..08138d8062 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -473,19 +473,16 @@ void MakeActsGeometry::buildActsSurfaces() /// Alter args if using field map if(m_magField.find(".root") != std::string::npos) { - if(m_magField.find("2d") != std::string::npos) - { - m_magFieldRescale = 1; - } + char *calibrationsroot = getenv("CALIBRATIONROOT"); m_magField = "sphenix3dtrackingmapxyz.root"; - m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING"); - if (calibrationsroot != nullptr) - { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; - } + { + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + } + + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); argstr[7] = "--bf-map-file"; argstr[8] = m_magField; From ae2523fe57b8128f8f55f6d348723b1a95b9dbab Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 May 2023 15:20:59 -0400 Subject: [PATCH 338/468] make track residual tuple module change to tree test and clang-format --- .../packages/TrackingDiagnostics/Makefile.am | 2 + .../TrackingDiagnostics/TrackResiduals.cc | 336 ++++++++++++++++++ .../TrackingDiagnostics/TrackResiduals.h | 93 +++++ 3 files changed, 431 insertions(+) create mode 100644 offline/packages/TrackingDiagnostics/TrackResiduals.cc create mode 100644 offline/packages/TrackingDiagnostics/TrackResiduals.h diff --git a/offline/packages/TrackingDiagnostics/Makefile.am b/offline/packages/TrackingDiagnostics/Makefile.am index 080a988662..d20020a3d9 100644 --- a/offline/packages/TrackingDiagnostics/Makefile.am +++ b/offline/packages/TrackingDiagnostics/Makefile.am @@ -13,6 +13,7 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ KshortReconstruction.h \ helixResiduals.h \ + TrackResiduals.h \ TrkrNtuplizer.h lib_LTLIBRARIES = \ @@ -21,6 +22,7 @@ lib_LTLIBRARIES = \ libTrackingDiagnostics_la_SOURCES = \ KshortReconstruction.cc \ helixResiduals.cc \ + TrackResiduals.cc \ TrkrNtuplizer.cc libTrackingDiagnostics_la_LIBADD = \ diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc new file mode 100644 index 0000000000..dc3be16c74 --- /dev/null +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -0,0 +1,336 @@ + +#include "TrackResiduals.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +namespace +{ + template + inline T square(const T& t) + { + return t * t; + } + template + inline T r(const T& x, const T& y) + { + return std::sqrt(square(x) + square(y)); + } + + std::vector get_cluster_keys(SvtxTrack* track) + { + std::vector out; + for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (seed) + { + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); + } + } + + return out; + } +} // namespace + +//____________________________________________________________________________.. +TrackResiduals::TrackResiduals(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +TrackResiduals::~TrackResiduals() +{ +} + +//____________________________________________________________________________.. +int TrackResiduals::Init(PHCompositeNode*) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TrackResiduals::InitRun(PHCompositeNode*) +{ + m_outfile = new TFile(m_outfileName.c_str(), "RECREATE"); + createBranches(); + + return Fun4AllReturnCodes::EVENT_OK; +} +void TrackResiduals::clearClusterStateVectors() +{ + m_cluslx.clear(); + m_cluslz.clear(); + m_cluselx.clear(); + m_cluselz.clear(); + m_clusgx.clear(); + m_clusgy.clear(); + m_clusgz.clear(); + m_cluslayer.clear(); + m_clussize.clear(); + + m_statelx.clear(); + m_statelz.clear(); + m_stateelx.clear(); + m_stateelz.clear(); + m_stategx.clear(); + m_stategy.clear(); + m_stategz.clear(); + m_statepx.clear(); + m_statepy.clear(); + m_statepz.clear(); +} +//____________________________________________________________________________.. +int TrackResiduals::process_event(PHCompositeNode* topNode) +{ + auto trackmap = findNode::getClass(topNode, "SvtxTrackMap"); + auto clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); + auto geometry = findNode::getClass(topNode, "ActsGeometry"); + auto vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if (!trackmap or !clustermap or !geometry or !vertexmap) + { + std::cout << "Missing node, can't continue" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + ActsTransformations transformer; + + if (Verbosity() > 1) + { + std::cout << "Track map size is " << trackmap->size() << std::endl; + } + + for (const auto& [key, track] : *trackmap) + { + if (!track) + { + continue; + } + m_trackid = key; + m_crossing = track->get_crossing(); + m_px = track->get_px(); + m_py = track->get_py(); + m_pz = track->get_pz(); + m_pt = std::sqrt(square(m_px) + square(m_py)); + m_eta = atanh(m_pz / std::sqrt(square(m_pt) + square(m_pz))); + m_phi = atan2(m_py, m_px); + float CVxx = track->get_error(3, 3); + float CVxy = track->get_error(3, 4); + float CVyy = track->get_error(4, 4); + m_deltapt = std::sqrt((CVxx * square(m_px) + 2 * CVxy * m_px * m_py + CVyy * square(m_py)) / (square(m_px) + square(m_py))); + + m_charge = track->get_charge(); + m_quality = track->get_quality(); + m_chisq = track->get_chisq(); + m_ndf = track->get_ndf(); + m_nmaps = 0; + m_nintt = 0; + m_ntpc = 0; + m_nmms = 0; + m_vertexid = track->get_vertex_id(); + auto vertex = vertexmap->find(m_vertexid)->second; + if (vertex) + { + m_vx = vertex->get_x(); + m_vy = vertex->get_y(); + m_vz = vertex->get_z(); + } + + m_pcax = track->get_x(); + m_pcay = track->get_y(); + m_pcaz = track->get_z(); + + clearClusterStateVectors(); + if (Verbosity() > 1) + { + std::cout << "Track " << key << " has cluster/states" + << std::endl; + } + + for (const auto& ckey : get_cluster_keys(track)) + { + TrkrCluster* cluster = clustermap->findCluster(ckey); + switch (TrkrDefs::getTrkrId(ckey)) + { + case TrkrDefs::mvtxId: + m_nmaps++; + break; + case TrkrDefs::inttId: + m_nintt++; + break; + case TrkrDefs::tpcId: + m_ntpc++; + break; + case TrkrDefs::micromegasId: + m_nmms++; + break; + } + + Acts::Vector3 clusglob = geometry->getGlobalPosition(ckey, cluster); + + auto matched_state = track->begin_states(); + float drmin = -1; + float clusr = r(clusglob.x(), clusglob.y()); + + for (auto state_iter = track->begin_states(); + state_iter != track->end_states(); + ++state_iter) + { + SvtxTrackState* state = state_iter->second; + float stater = r(state->get_x(), state->get_y()); + float thisdr = std::abs(clusr - stater); + if (drmin < 0 or thisdr < drmin) + { + matched_state = state_iter; + drmin = thisdr; + } + else + { + break; + } + } + + SvtxTrackState* state = matched_state->second; + + //! have cluster and state, fill vectors + m_cluslx.push_back(cluster->getLocalX()); + m_cluslz.push_back(cluster->getLocalY()); + m_cluselx.push_back(cluster->getRPhiError()); + m_cluselz.push_back(cluster->getZError()); + m_clusgx.push_back(clusglob.x()); + m_clusgy.push_back(clusglob.y()); + m_clusgz.push_back(clusglob.z()); + m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getPhiSize() + cluster->getZSize()); + + if (Verbosity() > 1) + { + std::cout << "Track state/clus in layer " + << TrkrDefs::getLayer(ckey) << std::endl; + } + + auto surf = geometry->maps().getSurface(ckey, cluster); + Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + Acts::Vector2 stateloc; + auto norm = surf->normal(geometry->geometry().getGeoContext()); + auto result = surf->globalToLocal(geometry->geometry().getGeoContext(), + stateglob * Acts::UnitConstants::cm, + norm); + if (result.ok()) + { + stateloc = result.value() / Acts::UnitConstants::cm; + } + else + { + //! manual transform for tpc + Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); + loct /= Acts::UnitConstants::cm; + stateloc(0) = loct(0); + stateloc(1) = loct(1); + } + + const Acts::BoundSymMatrix actscov = + transformer.rotateSvtxTrackCovToActs(state); + + m_statelx.push_back(stateloc(0)); + m_statelz.push_back(stateloc(1)); + m_stateelx.push_back(std::sqrt(actscov(Acts::eBoundLoc0, Acts::eBoundLoc0)) / Acts::UnitConstants::cm); + m_stateelz.push_back(std::sqrt(actscov(Acts::eBoundLoc1, Acts::eBoundLoc1)) / Acts::UnitConstants::cm); + m_stategx.push_back(state->get_x()); + m_stategy.push_back(state->get_y()); + m_stategz.push_back(state->get_z()); + m_statepx.push_back(state->get_px()); + m_statepy.push_back(state->get_py()); + m_statepz.push_back(state->get_pz()); + m_statepl.push_back(state->get_pathlength()); + } + + m_nhits = m_nmaps + m_nintt + m_ntpc + m_nmms; + + m_tree->Fill(); + } + + m_event++; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TrackResiduals::End(PHCompositeNode*) +{ + m_outfile->cd(); + m_tree->Write(); + m_outfile->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +void TrackResiduals::createBranches() +{ + m_tree = new TTree("residualtree", "A tree with track, cluster, and state info"); + m_tree->Branch("trackid", &m_trackid, "m_trackid/I"); + m_tree->Branch("crossing", &m_crossing, "m_crossing/I"); + m_tree->Branch("px", &m_px, "m_px/F"); + m_tree->Branch("py", &m_py, "m_py/F"); + m_tree->Branch("pz", &m_pz, "m_pz/F"); + m_tree->Branch("pt", &m_pt, "m_pt/F"); + m_tree->Branch("eta", &m_eta, "m_eta/F"); + m_tree->Branch("phi", &m_phi, "m_phi/F"); + m_tree->Branch("deltapt", &m_deltapt, "m_deltapt/F"); + m_tree->Branch("charge", &m_charge, "m_charge/I"); + m_tree->Branch("quality", &m_quality, "m_quality/F"); + m_tree->Branch("ndf", &m_ndf, "m_ndf/F"); + m_tree->Branch("nhits", &m_nhits, "m_nhits/I"); + m_tree->Branch("nmaps", &m_nmaps, "m_nmaps/I"); + m_tree->Branch("nintt", &m_nintt, "m_nintt/I"); + m_tree->Branch("ntpc", &m_ntpc, "m_ntpc/I"); + m_tree->Branch("nmms", &m_nmms, "m_nmms/I"); + m_tree->Branch("vertexid", &m_vertexid, "m_vertexid/I"); + m_tree->Branch("vx", &m_vx, "m_vx/F"); + m_tree->Branch("vy", &m_vy, "m_vy/F"); + m_tree->Branch("vz", &m_vz, "m_vz/F"); + m_tree->Branch("pcax", &m_pcax, "m_pcax/F"); + m_tree->Branch("pcay", &m_pcay, "m_pcay/F"); + m_tree->Branch("pcaz", &m_pcaz, "m_pcaz/F"); + + m_tree->Branch("cluslx", &m_cluslx); + m_tree->Branch("cluslz", &m_cluslz); + m_tree->Branch("cluselx", &m_cluselx); + m_tree->Branch("cluselz", &m_cluselz); + m_tree->Branch("clusgx", &m_clusgx); + m_tree->Branch("clusgy", &m_clusgy); + m_tree->Branch("clusgz", &m_clusgz); + m_tree->Branch("cluslayer", &m_cluslayer); + m_tree->Branch("clussize", &m_clussize); + + m_tree->Branch("statelx", &m_statelx); + m_tree->Branch("statelz", &m_statelz); + m_tree->Branch("stateelx", &m_stateelx); + m_tree->Branch("stateelz", &m_stateelz); + m_tree->Branch("stategx", &m_stategx); + m_tree->Branch("stategy", &m_stategy); + m_tree->Branch("stategz", &m_stategz); + m_tree->Branch("statepx", &m_statepx); + m_tree->Branch("statepy", &m_statepy); + m_tree->Branch("statepz", &m_statepz); + m_tree->Branch("statepl", &m_statepl); +} diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h new file mode 100644 index 0000000000..b4da68bb76 --- /dev/null +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -0,0 +1,93 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TRACKRESIDUALS_H +#define TRACKRESIDUALS_H + +#include + +#include +#include +#include +#include + +#include +#include +#include + +class PHCompositeNode; + +class TrackResiduals : public SubsysReco +{ + public: + TrackResiduals(const std::string &name = "TrackResiduals"); + + ~TrackResiduals() override; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + int End(PHCompositeNode *topNode) override; + void outfileName(std::string name) { m_outfileName = name; } + + private: + void clearClusterStateVectors(); + void createBranches(); + + std::string m_outfileName = ""; + TFile *m_outfile = nullptr; + TTree *m_tree = nullptr; + + int m_event = 0; + //! Track level quantities + unsigned int m_trackid = std::numeric_limits::quiet_NaN(); + unsigned int m_crossing = std::numeric_limits::quiet_NaN(); + float m_px = std::numeric_limits::quiet_NaN(); + float m_py = std::numeric_limits::quiet_NaN(); + float m_pz = std::numeric_limits::quiet_NaN(); + float m_pt = std::numeric_limits::quiet_NaN(); + float m_eta = std::numeric_limits::quiet_NaN(); + float m_phi = std::numeric_limits::quiet_NaN(); + float m_deltapt = std::numeric_limits::quiet_NaN(); + int m_charge = std::numeric_limits::quiet_NaN(); + float m_quality = std::numeric_limits::quiet_NaN(); + float m_chisq = std::numeric_limits::quiet_NaN(); + float m_ndf = std::numeric_limits::quiet_NaN(); + int m_nhits = std::numeric_limits::quiet_NaN(); + int m_nmaps = std::numeric_limits::quiet_NaN(); + int m_nintt = std::numeric_limits::quiet_NaN(); + int m_ntpc = std::numeric_limits::quiet_NaN(); + int m_nmms = std::numeric_limits::quiet_NaN(); + unsigned int m_vertexid = std::numeric_limits::quiet_NaN(); + float m_vx = std::numeric_limits::quiet_NaN(); + float m_vy = std::numeric_limits::quiet_NaN(); + float m_vz = std::numeric_limits::quiet_NaN(); + float m_pcax = std::numeric_limits::quiet_NaN(); + float m_pcay = std::numeric_limits::quiet_NaN(); + float m_pcaz = std::numeric_limits::quiet_NaN(); + + //! clusters on track information + std::vector m_cluslx; + std::vector m_cluslz; + std::vector m_cluselx; + std::vector m_cluselz; + std::vector m_clusgx; + std::vector m_clusgy; + std::vector m_clusgz; + std::vector m_cluslayer; + std::vector m_clussize; + + //! states on track information + std::vector m_statelx; + std::vector m_statelz; + std::vector m_stateelx; + std::vector m_stateelz; + std::vector m_stategx; + std::vector m_stategy; + std::vector m_stategz; + std::vector m_statepx; + std::vector m_statepy; + std::vector m_statepz; + std::vector m_statepl; +}; + +#endif // TRACKRESIDUALS_H From 7cba7ae64c85973254f13c4f0c99e061d284fdf9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 5 May 2023 10:27:29 -0400 Subject: [PATCH 339/468] Fix vertex lookup --- offline/packages/globalvertex/GlobalVertexReco.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 180f4398b5..db0b4e6045 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -295,11 +295,12 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } /// Associate any tracks that were not assigned a track-vertex + for (const auto &[tkey, track] : *trackmap) { //! Check that the vertex hasn't already been assigned auto trackvtxid = track->get_vertex_id(); - if (globalmap->find(trackvtxid)->second != nullptr) + if (globalmap->find(trackvtxid) != globalmap->end()) { continue; } From 3b7dfa08cd188a61fd6bbb396688a6d246bb0cb1 Mon Sep 17 00:00:00 2001 From: Jakub Kvapil Date: Fri, 5 May 2023 13:30:18 -0400 Subject: [PATCH 340/468] first version of MVTX unpacker, currently contains dummy fill since there is no decoder --- offline/packages/mvtx/Makefile.am | 4 +- offline/packages/mvtx/MvtxRawDataDecoder.cc | 168 ++++++++++++++++++++ offline/packages/mvtx/MvtxRawDataDecoder.h | 45 ++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 offline/packages/mvtx/MvtxRawDataDecoder.cc create mode 100644 offline/packages/mvtx/MvtxRawDataDecoder.h diff --git a/offline/packages/mvtx/Makefile.am b/offline/packages/mvtx/Makefile.am index f06786c9d3..692a171039 100644 --- a/offline/packages/mvtx/Makefile.am +++ b/offline/packages/mvtx/Makefile.am @@ -20,6 +20,7 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ MvtxClusterizer.h \ MvtxHitPruner.h \ + MvtxRawDataDecoder.h \ CylinderGeom_Mvtx.h \ SegmentationAlpide.h @@ -34,7 +35,8 @@ nobase_dist_pcm_DATA = \ # sources for mvtx library libmvtx_la_SOURCES = \ MvtxClusterizer.cc \ - MvtxHitPruner.cc + MvtxHitPruner.cc \ + MvtxRawDataDecoder.cc libmvtx_la_LIBADD = \ libmvtx_io.la \ diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.cc b/offline/packages/mvtx/MvtxRawDataDecoder.cc new file mode 100644 index 0000000000..43d840a570 --- /dev/null +++ b/offline/packages/mvtx/MvtxRawDataDecoder.cc @@ -0,0 +1,168 @@ +/*! + * \file MvtxRawDataDecoder.cc + * \author Jakub Kvapil + */ + +#include "MvtxRawDataDecoder.h" +#include "trackbase/MvtxDefs.h" + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +//_________________________________________________________ +MvtxRawDataDecoder::MvtxRawDataDecoder( const std::string& name ): + SubsysReco( name ) +{} + +//_____________________________________________________________________ +int MvtxRawDataDecoder::Init(PHCompositeNode* /*topNode*/ ) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MvtxRawDataDecoder::InitRun(PHCompositeNode *topNode) +{ + + // get dst node + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "MvtxRawDataDecoder::InitRun - DST Node missing, doing nothing." << std::endl; + exit(1); + } + + // create hitset container if needed + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + if (!hitsetcontainer) + { + // find or create TRKR node + PHNodeIterator dstiter(dstNode); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!trkrnode) + { + trkrnode = new PHCompositeNode("TRKR"); + dstNode->addNode(trkrnode); + } + + // create container and add to the tree + hitsetcontainer = new TrkrHitSetContainerv1; + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + trkrnode->addNode(newNode); + } + + return Fun4AllReturnCodes::EVENT_OK; + +} + +//___________________________________________________________________________ +int MvtxRawDataDecoder::process_event(PHCompositeNode *topNode) +{ + + // load relevant nodes + // Get the TrkrHitSetContainer node + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + assert(trkrhitsetcontainer); + + // PRDF node + auto event = findNode::getClass(topNode, "PRDF"); + assert(event); + // check event type + + +//UNCOMMENT THIS ONCE HAVING DECODER!!!! +/* if(event->getEvtType() >= 8) + { return Fun4AllReturnCodes::DISCARDEVENT; } + + // get MVTX packet number + auto packet = event->getPacket(2001); + if( !packet ) + { + // no data + std::cout << "MvtxRawDataDecoder::process_event - event contains no MVTX data" << std::endl; + // return Fun4AllReturnCodes::EVENT_OK; + } + +*/ + + //loop over triggers ADD + //loop over chips + for( int i=0; i<1; i++ ) + { + int strobe = 11+i; //get from decoder; + int layer = 0;//get from decoder; + int stave = 1;//get from decoder; + int chip = 2;//get from decoder; + + if( Verbosity() ){ + std::cout + << "MvtxRawDataDecoder::process_event -" + << " strobe: " << strobe + << " layer: " << layer + << " stave: " << stave + << " chip: " << chip + << std::endl; + } + + // map fee and channel to physical hitsetid and physical strip + // get hitset key matching this fee + const TrkrDefs::hitsetkey hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, strobe); + if( !hitsetkey ) continue; + + // get matching hitset + const auto hitset_it = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); + + for( int ihit=0; ihit<10/*nhit in chip from decoder*/; ++ihit ){ + uint16_t col = 150;//get from decoder; + uint16_t row = ihit*10;//get from decoder; + + // generate hit key + const TrkrDefs::hitkey hitkey = MvtxDefs::genHitKey(col,row); + + // find existing hit, or create + auto hit = hitset_it->second->getHit(hitkey); + if( hit ){ + std::cout << "MvtxRawDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " hitkey: " << hitkey << std::endl; + continue; + } + + // create hit and insert in hitset + hit = new TrkrHitv2; + hitset_it->second->addHitSpecificKey(hitkey, hit); + + // increment counter + ++m_hitcounts[hitsetkey]; + + } + } + + return Fun4AllReturnCodes::EVENT_OK; + +} + +//_____________________________________________________________________ +int MvtxRawDataDecoder::End(PHCompositeNode* /*topNode*/ ) +{ + if( Verbosity() ) + { + for( const auto& [hitsetkey, count]:m_hitcounts ) + { std::cout << "MvtxRawDataDecoder - hitsetkey: " << hitsetkey << ", count: " << count << std::endl; } + } + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.h b/offline/packages/mvtx/MvtxRawDataDecoder.h new file mode 100644 index 0000000000..a3bd3e2da4 --- /dev/null +++ b/offline/packages/mvtx/MvtxRawDataDecoder.h @@ -0,0 +1,45 @@ +#ifndef MVTX_MVTXRAWDATADECODER_H +#define MVTX_MVTXRAWDATADECODER_H + +/*! + * \file MvtxRawDataDecoder.h + * \author Jakub Kvapil + */ + +#include +#include "trackbase/MvtxDefs.h" + +#include +#include +#include + +class PHCompositeNode; + +/// mvtx raw data decoder +class MvtxRawDataDecoder : public SubsysReco +{ + public: + + /// constructor + MvtxRawDataDecoder( const std::string &name = "MvtxRawDataDecoder" ); + + /// global initialization + int Init(PHCompositeNode*) override; + + /// run initialization + int InitRun(PHCompositeNode*) override; + + /// event processing + int process_event(PHCompositeNode*) override; + + /// end of processing + int End(PHCompositeNode*) override; + + private: + /// keep track of number of hits per hitsetid + using hitcountmap_t = std::map; + hitcountmap_t m_hitcounts; + +}; + +#endif From 3c83e6cfae5baf9e5c505c9a96bb930d000d243b Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Fri, 5 May 2023 15:43:35 -0400 Subject: [PATCH 341/468] Added helper class for dead channel analysis --- offline/packages/intt/InttDeadMapHelper.cc | 289 +++++++++++++++++++++ offline/packages/intt/InttDeadMapHelper.h | 73 ++++++ 2 files changed, 362 insertions(+) create mode 100644 offline/packages/intt/InttDeadMapHelper.cc create mode 100644 offline/packages/intt/InttDeadMapHelper.h diff --git a/offline/packages/intt/InttDeadMapHelper.cc b/offline/packages/intt/InttDeadMapHelper.cc new file mode 100644 index 0000000000..0a2c05fcbb --- /dev/null +++ b/offline/packages/intt/InttDeadMapHelper.cc @@ -0,0 +1,289 @@ +#include "InttDeadMapHelper.h" + +InttDeadMapHelper::InttDeadMapHelper(InttDeadMap_Long_t const& _N, InttDeadMap_Double_t const& _n_z, InttDeadMap_Double_t const& _n_t) +{ + N = _N; + points = new struct InttDeadMap_Point_s[N]; + + n_z = _n_z; + n_t = _n_t; + p = 1.0 - erfl(n_z / sqrtl(2.0)); + q = sqrtl(p * (1.0 - p)); + + mu = 0; + sg = 0; + + n_g = 0; + n_l = 0; + n_u = 0; + + i_lower = 0; + i_upper = N; + D = 0; +} + +InttDeadMapHelper::~InttDeadMapHelper() +{ + delete[] points; +} + +void InttDeadMapHelper::quicksort_hitkey(InttDeadMap_Long_t const& _l, InttDeadMap_Long_t const& _u) +{ + if(_l < 0)return; + if(_u < 1)return; + if(_u <= _l)return; + + InttDeadMap_Long_t i_pivot = _l - 1; + + { + InttDeadMap_Long_t i; + + struct InttDeadMap_Point_s pivot = points[i_upper - 1]; + struct InttDeadMap_Point_s temp; + + for(i = _l; i < _u - 1; ++i) + { + if(points[i].hitkey <= pivot.hitkey) + { + ++i_pivot; + temp = points[i]; + points[i] = points[i_pivot]; + points[i_pivot] = temp; + } + } + + ++i_pivot; + temp = points[i_pivot]; + points[i_pivot] = points[_u - 1]; + points[_u - 1] = temp; + } + + quicksort_hitkey(_l, i_pivot); + quicksort_hitkey(i_pivot + 1, _u); +} + +void InttDeadMapHelper::quicksort_counts(InttDeadMap_Long_t const& _l, InttDeadMap_Long_t const& _u) +{ + if(_l < 0)return; + if(_u < 1)return; + if(_u <= _l)return; + + InttDeadMap_Long_t i_pivot = _l - 1; + + { + InttDeadMap_Long_t i; + + struct InttDeadMap_Point_s pivot = points[i_upper - 1]; + struct InttDeadMap_Point_s temp; + + for(i = _l; i < _u - 1; ++i) + { + if(points[i].counts <= pivot.counts) + { + ++i_pivot; + temp = points[i]; + points[i] = points[i_pivot]; + points[i_pivot] = temp; + } + } + + ++i_pivot; + temp = points[i_pivot]; + points[i_pivot] = points[_u - 1]; + points[_u - 1] = temp; + } + + quicksort_hitkey(_l, i_pivot); + quicksort_hitkey(i_pivot + 1, _u); +} + + +struct InttDeadMapHelper::InttDeadMap_Point_s* InttDeadMapHelper::get_point(InttDeadMap_HitKey_t const& hitkey, InttDeadMap_Long_t const& _l, InttDeadMap_Long_t const& _u) +{ + if(points[(_u + _l) / 2].hitkey == hitkey) return &(points[(i_upper + i_lower) / 2]); + + if(_u - _l <= 1) return nullptr; + + if(hitkey < points[(_u + _l) / 2].hitkey) return get_point(hitkey, _l, (_u + _l) / 2); + if(hitkey > points[(_u + _l) / 2].hitkey) return get_point(hitkey, (_u + _l) / 2, _u); + + return nullptr; +} + +int InttDeadMapHelper::count_type_i() +{ + //Alternatively, instead of a two-pass and then classify, + //I can fit to a Gaussian and use a goodness-of-fit parameter + InttDeadMap_Long_t i = 0; + + InttDeadMap_Double_t lower; + InttDeadMap_Double_t upper; + + mu = 0; + sg = 0; + + n_g = 0; + n_l = 0; + n_u = 0; + + for(i = i_lower; i < i_upper; ++i) + { + mu += points[i].counts; + } + mu /= (i_upper - i_lower); + + for(i = i_lower; i < i_upper; ++i) + { + sg += (points[i].counts - mu) * (points[i].counts - mu); + } + sg /= (i_upper - i_lower); + sg = sqrtl(sg); + + lower = mu - n_z * sg; + upper = mu + n_z * sg; + + for(i = i_lower; i < i_upper; ++i) + { + if(points[i].counts < lower) + { + ++n_l; + points[i].status = InttDeadMap_Status_LOWER; + continue; + } + + if(upper < points[i].counts) + { + ++n_u; + points[i].status = InttDeadMap_Status_UPPER; + continue; + } + + ++n_g; + points[i].status = InttDeadMap_Status_GOOD; + } + + return EXIT_SUCCESS; +} + +int InttDeadMapHelper::check_type_i() +{ + printf("check_type_i\n"); + + if(i_upper - i_lower <= 1)return EXIT_FAILURE; + + count_type_i(); + + { + int flag = 0; + + InttDeadMap_Long_t d; + + InttDeadMap_Double_t lower = p * (i_upper - i_lower) - n_t * q * sqrtl(i_upper - i_lower); + InttDeadMap_Double_t upper = p * (i_upper - i_lower) + n_t * q * sqrtl(i_upper - i_lower); + + d = 0; + if(n_l + n_u < floor(lower)) + { + d = floor(lower) - n_l - n_u; + } + if(ceil(upper) < n_l + n_u) + { + d = n_l + n_u - ceil(upper); + } + if(n_l - n_u > ceil((upper - lower) / 2.0)) + { + d = n_l - n_u - ceil((upper - lower) / 2.0); + } + if(n_u - n_l > ceil((upper - lower) / 2.0)) + { + d = n_u - n_l - ceil((upper - lower) / 2.0); + } + + if(d == 0)return EXIT_SUCCESS; + + std::cout << "\t" << floor(lower) << " < " << n_l << " + " << n_u << " < " << ceil(upper) << std::endl; + std::cout << "\t" << mu << " " << sg << std::endl; + + lower = mu - n_z * sg; + upper = mu + n_z * sg; + + flag = 0; + flag = flag || points[i_lower].status != InttDeadMap_Status_GOOD; + flag = flag || points[i_upper - 1].status != InttDeadMap_Status_GOOD; + + D = 0; + while(d) + { + if(i_upper - i_lower <= 1)break; + + if(points[i_upper - 1].counts - mu < mu - points[i_lower].counts) + { + if(flag && points[i_lower].status == InttDeadMap_Status_GOOD)break; + points[i_lower].status = InttDeadMap_Status_LOWER; + ++i_lower; + } + else + { + if(flag && points[i_upper - 1].status == InttDeadMap_Status_GOOD)break; + points[i_upper - 1].status = InttDeadMap_Status_UPPER; + --i_upper; + } + + --d; + ++D; + } + } + + return EXIT_SUCCESS; + return check_type_i(); +} + +void InttDeadMapHelper::gen_points(InttDeadMap_Double_t const& frac) +{ + InttDeadMap_Long_t n_bad = ceil(frac * N); + + mu = 4121.1324151; + sg = 124.14124; + + InttDeadMap_Double_t z[2]; + InttDeadMap_Double_t u[2]; + + InttDeadMap_Long_t i; + InttDeadMap_HitKey_t h; + InttDeadMap_Double_t c; + + for(i = 0; i < N; ++i) + { + if(i % 2 == 0) + { + u[0] = (InttDeadMap_Double_t)rand() / (InttDeadMap_Double_t)RAND_MAX; + u[1] = (InttDeadMap_Double_t)rand() / (InttDeadMap_Double_t)RAND_MAX; + + z[0] = sqrt(-2.0 * log(u[0])) * cos(2.0 * 3.14159265358979 * u[1]); + z[1] = sqrt(-2.0 * log(u[0])) * sin(2.0 * 3.14159265358979 * u[1]); + } + + c = mu + sg * z[i % 2]; + + points[i].hitkey = i; + points[i].counts = c; + points[i].status = InttDeadMap_Status_GOOD; + } + + c = 999999.999; + for(i = 0; i < n_bad; ++i) + { + h = rand() % N; + points[h].counts = c; + } + + c = 0.0; + for(i = 0; i < n_bad; ++i) + { + h = rand() % N; + points[h].counts = c; + } +} + + + diff --git a/offline/packages/intt/InttDeadMapHelper.h b/offline/packages/intt/InttDeadMapHelper.h new file mode 100644 index 0000000000..e9bbfa9354 --- /dev/null +++ b/offline/packages/intt/InttDeadMapHelper.h @@ -0,0 +1,73 @@ +#ifndef INTT_DEAD_MAP_HELPER_H +#define INTT_DEAD_MAP_HELPER_H + +//C style includes +#include +#include + +//CPP style includes +#include + +//ROOT and sPHENIX includes +#include //for getHitSetKey + +//class TrkrHitSetKey; or whatever it is + +class InttDeadMapHelper +{ +public: + typedef int InttDeadMap_HitKey_t; + typedef long double InttDeadMap_Double_t; + typedef long long InttDeadMap_Long_t; + + enum InttDeadMap_Status_e + { + InttDeadMap_Status_GOOD, + InttDeadMap_Status_LOWER, + InttDeadMap_Status_UPPER + }; + + struct InttDeadMap_Point_s + { + InttDeadMap_HitKey_t hitkey; + InttDeadMap_Long_t counts; + InttDeadMap_Status_e status; + }; + + InttDeadMapHelper(InttDeadMap_Long_t const&, InttDeadMap_Double_t const&, InttDeadMap_Double_t const&); + ~InttDeadMapHelper(); + + void gen_points(InttDeadMap_Double_t const&); + +//commented while debugging +//protected: + struct InttDeadMap_Point_s* get_point(InttDeadMap_HitKey_t const&, InttDeadMap_Long_t const&, InttDeadMap_Long_t const&); + + int count_type_i(); + int check_type_i(); + + void quicksort_hitkey(InttDeadMap_Long_t const&, InttDeadMap_Long_t const&); + void quicksort_counts(InttDeadMap_Long_t const&, InttDeadMap_Long_t const&); + + + InttDeadMap_Long_t N; + InttDeadMap_Point_s* points; + + InttDeadMap_Double_t n_z; + InttDeadMap_Double_t n_t; + InttDeadMap_Double_t p; + InttDeadMap_Double_t q; + + InttDeadMap_Double_t mu; + InttDeadMap_Double_t sg; + + InttDeadMap_Long_t n_g; + InttDeadMap_Long_t n_l; + InttDeadMap_Long_t n_u; + + InttDeadMap_Long_t i_lower; + InttDeadMap_Long_t i_upper; + InttDeadMap_Long_t D; +}; + +#endif From d1022443c774cc1a722a1a5799953962e1f345b5 Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Fri, 5 May 2023 16:55:04 -0400 Subject: [PATCH 342/468] Debugged quicksort methods and implemented copy constructor for Jenkins --- offline/packages/intt/InttDeadMapHelper.cc | 79 +++++++++++++++++++--- offline/packages/intt/InttDeadMapHelper.h | 4 ++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/offline/packages/intt/InttDeadMapHelper.cc b/offline/packages/intt/InttDeadMapHelper.cc index 0a2c05fcbb..bfab2850ed 100644 --- a/offline/packages/intt/InttDeadMapHelper.cc +++ b/offline/packages/intt/InttDeadMapHelper.cc @@ -1,5 +1,54 @@ #include "InttDeadMapHelper.h" +InttDeadMapHelper::InttDeadMapHelper() +{ + N = 0; + points = nullptr; + + n_z = 0.0; + n_t = 0.0; + p = 0.0; + q = 0.0; + + mu = 0; + sg = 0; + + n_g = 0; + n_l = 0; + n_u = 0; + + i_lower = 0; + i_upper = 0; + D = 0; +} + +InttDeadMapHelper::InttDeadMapHelper(InttDeadMapHelper const& _o) +{ + N = _o.N; + points = new struct InttDeadMap_Point_s[N]; + for(InttDeadMap_Long_t i = 0; i < N; ++i) + { + points[i] = _o.points[i]; + } + + n_z = _o.n_z; + n_t = _o.n_t; + + p = _o.p; + q = _o.q; + + mu = _o.mu; + sg = _o.sg; + + n_g = _o.n_g; + n_l = _o.n_l; + n_u = _o.n_u; + + i_lower = _o.i_lower; + i_upper = _o.i_upper; + D = _o.D; +} + InttDeadMapHelper::InttDeadMapHelper(InttDeadMap_Long_t const& _N, InttDeadMap_Double_t const& _n_z, InttDeadMap_Double_t const& _n_t) { N = _N; @@ -24,7 +73,7 @@ InttDeadMapHelper::InttDeadMapHelper(InttDeadMap_Long_t const& _N, InttDeadMap_D InttDeadMapHelper::~InttDeadMapHelper() { - delete[] points; + if(points)delete[] points; } void InttDeadMapHelper::quicksort_hitkey(InttDeadMap_Long_t const& _l, InttDeadMap_Long_t const& _u) @@ -32,13 +81,14 @@ void InttDeadMapHelper::quicksort_hitkey(InttDeadMap_Long_t const& _l, InttDeadM if(_l < 0)return; if(_u < 1)return; if(_u <= _l)return; + if(!points)return; InttDeadMap_Long_t i_pivot = _l - 1; { InttDeadMap_Long_t i; - struct InttDeadMap_Point_s pivot = points[i_upper - 1]; + struct InttDeadMap_Point_s pivot = points[_u - 1]; struct InttDeadMap_Point_s temp; for(i = _l; i < _u - 1; ++i) @@ -67,13 +117,14 @@ void InttDeadMapHelper::quicksort_counts(InttDeadMap_Long_t const& _l, InttDeadM if(_l < 0)return; if(_u < 1)return; if(_u <= _l)return; + if(!points)return; InttDeadMap_Long_t i_pivot = _l - 1; { InttDeadMap_Long_t i; - struct InttDeadMap_Point_s pivot = points[i_upper - 1]; + struct InttDeadMap_Point_s pivot = points[_u- 1]; struct InttDeadMap_Point_s temp; for(i = _l; i < _u - 1; ++i) @@ -93,13 +144,14 @@ void InttDeadMapHelper::quicksort_counts(InttDeadMap_Long_t const& _l, InttDeadM points[_u - 1] = temp; } - quicksort_hitkey(_l, i_pivot); - quicksort_hitkey(i_pivot + 1, _u); + quicksort_counts(_l, i_pivot); + quicksort_counts(i_pivot + 1, _u); } struct InttDeadMapHelper::InttDeadMap_Point_s* InttDeadMapHelper::get_point(InttDeadMap_HitKey_t const& hitkey, InttDeadMap_Long_t const& _l, InttDeadMap_Long_t const& _u) { + if(!points) return nullptr; if(points[(_u + _l) / 2].hitkey == hitkey) return &(points[(i_upper + i_lower) / 2]); if(_u - _l <= 1) return nullptr; @@ -112,6 +164,8 @@ struct InttDeadMapHelper::InttDeadMap_Point_s* InttDeadMapHelper::get_point(Intt int InttDeadMapHelper::count_type_i() { + if(!points)return EXIT_FAILURE; + //Alternatively, instead of a two-pass and then classify, //I can fit to a Gaussian and use a goodness-of-fit parameter InttDeadMap_Long_t i = 0; @@ -167,6 +221,8 @@ int InttDeadMapHelper::count_type_i() int InttDeadMapHelper::check_type_i() { + if(!points)return EXIT_FAILURE; + printf("check_type_i\n"); if(i_upper - i_lower <= 1)return EXIT_FAILURE; @@ -199,10 +255,12 @@ int InttDeadMapHelper::check_type_i() d = n_u - n_l - ceil((upper - lower) / 2.0); } - if(d == 0)return EXIT_SUCCESS; - std::cout << "\t" << floor(lower) << " < " << n_l << " + " << n_u << " < " << ceil(upper) << std::endl; - std::cout << "\t" << mu << " " << sg << std::endl; + std::cout << "\t" << "mu: " << mu << "\tsg: " << sg << std::endl; + std::cout << "\t" << "lower: " << i_lower << "\tupper: " << i_upper << std::endl; + std::cout << "\td_l: " << (mu - points[i_lower].counts) / sg; + std::cout << "\td_u: " << (points[i_upper - 1].counts - mu) / sg << std::endl; + if(d == 0)return EXIT_SUCCESS; lower = mu - n_z * sg; upper = mu + n_z * sg; @@ -234,13 +292,14 @@ int InttDeadMapHelper::check_type_i() } } - return EXIT_SUCCESS; return check_type_i(); } void InttDeadMapHelper::gen_points(InttDeadMap_Double_t const& frac) { - InttDeadMap_Long_t n_bad = ceil(frac * N); + if(!points)return; + + InttDeadMap_Long_t n_bad = ceil(frac * N / 2.0); mu = 4121.1324151; sg = 124.14124; diff --git a/offline/packages/intt/InttDeadMapHelper.h b/offline/packages/intt/InttDeadMapHelper.h index e9bbfa9354..1082bf9e9b 100644 --- a/offline/packages/intt/InttDeadMapHelper.h +++ b/offline/packages/intt/InttDeadMapHelper.h @@ -34,7 +34,11 @@ class InttDeadMapHelper InttDeadMap_Status_e status; }; + InttDeadMapHelper(); + + InttDeadMapHelper(InttDeadMapHelper const&); InttDeadMapHelper(InttDeadMap_Long_t const&, InttDeadMap_Double_t const&, InttDeadMap_Double_t const&); + ~InttDeadMapHelper(); void gen_points(InttDeadMap_Double_t const&); From 09af9eb63b3ac92fa18a810724ac08f66dd0c5c4 Mon Sep 17 00:00:00 2001 From: Jakub Kvapil Date: Fri, 5 May 2023 17:25:44 -0400 Subject: [PATCH 343/468] updated includes --- offline/packages/mvtx/MvtxRawDataDecoder.cc | 20 ++++++++++---------- offline/packages/mvtx/MvtxRawDataDecoder.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.cc b/offline/packages/mvtx/MvtxRawDataDecoder.cc index 43d840a570..efa38efa33 100644 --- a/offline/packages/mvtx/MvtxRawDataDecoder.cc +++ b/offline/packages/mvtx/MvtxRawDataDecoder.cc @@ -6,19 +6,19 @@ #include "MvtxRawDataDecoder.h" #include "trackbase/MvtxDefs.h" -#include -#include -#include +#include "Event/Event.h" +#include "Event/EventTypes.h" +#include "Event/packet.h" -#include +#include "fun4all/Fun4AllReturnCodes.h" -#include -#include -#include +#include "phool/getClass.h" +#include "phool/PHCompositeNode.h" +#include "phool/PHNodeIterator.h" -#include -#include -#include +#include "trackbase/TrkrHitv2.h" +#include "trackbase/TrkrHitSet.h" +#include "trackbase/TrkrHitSetContainerv1.h" #include #include diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.h b/offline/packages/mvtx/MvtxRawDataDecoder.h index a3bd3e2da4..093b7cd102 100644 --- a/offline/packages/mvtx/MvtxRawDataDecoder.h +++ b/offline/packages/mvtx/MvtxRawDataDecoder.h @@ -6,7 +6,7 @@ * \author Jakub Kvapil */ -#include +#include "fun4all/SubsysReco.h" #include "trackbase/MvtxDefs.h" #include From 44d99daccab7034be23e21b75d7eb579199c5779 Mon Sep 17 00:00:00 2001 From: Jakub Kvapil Date: Fri, 5 May 2023 17:30:09 -0400 Subject: [PATCH 344/468] reverted previous change, alphabetically ordered --- offline/packages/mvtx/MvtxRawDataDecoder.cc | 22 ++++++++++----------- offline/packages/mvtx/MvtxRawDataDecoder.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.cc b/offline/packages/mvtx/MvtxRawDataDecoder.cc index efa38efa33..349cf02471 100644 --- a/offline/packages/mvtx/MvtxRawDataDecoder.cc +++ b/offline/packages/mvtx/MvtxRawDataDecoder.cc @@ -4,21 +4,21 @@ */ #include "MvtxRawDataDecoder.h" -#include "trackbase/MvtxDefs.h" -#include "Event/Event.h" -#include "Event/EventTypes.h" -#include "Event/packet.h" +#include +#include +#include -#include "fun4all/Fun4AllReturnCodes.h" +#include -#include "phool/getClass.h" -#include "phool/PHCompositeNode.h" -#include "phool/PHNodeIterator.h" +#include +#include +#include -#include "trackbase/TrkrHitv2.h" -#include "trackbase/TrkrHitSet.h" -#include "trackbase/TrkrHitSetContainerv1.h" +#include +#include +#include +#include #include #include diff --git a/offline/packages/mvtx/MvtxRawDataDecoder.h b/offline/packages/mvtx/MvtxRawDataDecoder.h index 093b7cd102..e33eccc51f 100644 --- a/offline/packages/mvtx/MvtxRawDataDecoder.h +++ b/offline/packages/mvtx/MvtxRawDataDecoder.h @@ -6,8 +6,8 @@ * \author Jakub Kvapil */ -#include "fun4all/SubsysReco.h" -#include "trackbase/MvtxDefs.h" +#include +#include #include #include From e4afffc80550c5bb0d831ce464040b612952fcc8 Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Fri, 5 May 2023 17:38:40 -0400 Subject: [PATCH 345/468] Implemented operator= for Jenkins --- offline/packages/intt/InttDeadMapHelper.cc | 31 ++++++++++++++++++++++ offline/packages/intt/InttDeadMapHelper.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/offline/packages/intt/InttDeadMapHelper.cc b/offline/packages/intt/InttDeadMapHelper.cc index bfab2850ed..d267adf8f9 100644 --- a/offline/packages/intt/InttDeadMapHelper.cc +++ b/offline/packages/intt/InttDeadMapHelper.cc @@ -49,6 +49,37 @@ InttDeadMapHelper::InttDeadMapHelper(InttDeadMapHelper const& _o) D = _o.D; } +InttDeadMapHelper& InttDeadMapHelper::operator=(InttDeadMapHelper const& _o) +{ + if(this == &_o)return *this; + + N = _o.N; + points = new struct InttDeadMap_Point_s[N]; + for(InttDeadMap_Long_t i = 0; i < N; ++i) + { + points[i] = _o.points[i]; + } + + n_z = _o.n_z; + n_t = _o.n_t; + + p = _o.p; + q = _o.q; + + mu = _o.mu; + sg = _o.sg; + + n_g = _o.n_g; + n_l = _o.n_l; + n_u = _o.n_u; + + i_lower = _o.i_lower; + i_upper = _o.i_upper; + D = _o.D; + + return *this; +} + InttDeadMapHelper::InttDeadMapHelper(InttDeadMap_Long_t const& _N, InttDeadMap_Double_t const& _n_z, InttDeadMap_Double_t const& _n_t) { N = _N; diff --git a/offline/packages/intt/InttDeadMapHelper.h b/offline/packages/intt/InttDeadMapHelper.h index 1082bf9e9b..1ca9f3c519 100644 --- a/offline/packages/intt/InttDeadMapHelper.h +++ b/offline/packages/intt/InttDeadMapHelper.h @@ -37,6 +37,8 @@ class InttDeadMapHelper InttDeadMapHelper(); InttDeadMapHelper(InttDeadMapHelper const&); + InttDeadMapHelper& operator=(InttDeadMapHelper const&); + InttDeadMapHelper(InttDeadMap_Long_t const&, InttDeadMap_Double_t const&, InttDeadMap_Double_t const&); ~InttDeadMapHelper(); From b55f4e3af8929fcedecd5f52f2d6bce80e03e276 Mon Sep 17 00:00:00 2001 From: luisval Date: Fri, 5 May 2023 19:43:41 -0400 Subject: [PATCH 346/468] Adding Functionality for Laser Stepping Over Angles in ROOT file --- .../g4simulation/g4tpc/PHG4TpcDirectLaser.cc | 108 ++++++++++++++++-- .../g4simulation/g4tpc/PHG4TpcDirectLaser.h | 21 ++++ 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc index 8b91ba1e03..0504012022 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc @@ -25,6 +25,8 @@ #include #include // for TVector3, operator* +#include +#include #include // for the speed of light @@ -236,13 +238,29 @@ int PHG4TpcDirectLaser::InitRun(PHCompositeNode* topNode) SetupLasers(); // print configuration - std::cout << "PHG4TpcDirectLaser::InitRun - m_autoAdvanceDirectLaser: " << m_autoAdvanceDirectLaser << std::endl; - std::cout << "PHG4TpcDirectLaser::InitRun - phi steps: " << nPhiSteps << " min: " << minPhi << " max: " << maxPhi << std::endl; - std::cout << "PHG4TpcDirectLaser::InitRun - theta steps: " << nThetaSteps << " min: " << minTheta << " max: " << maxTheta << std::endl; - std::cout << "PHG4TpcDirectLaser::InitRun - nTotalSteps: " << nTotalSteps << std::endl; - + if(m_steppingpattern == true) + { + std::cout<< "PHG4TpcDirectLaser::InitRun - m_steppingpattern: " << m_steppingpattern << std::endl; + std::cout<< "PHG4TpcDirectLaser::InitRun - nTotalSteps: " << nTotalSteps << std::endl; + } + else + { + std::cout << "PHG4TpcDirectLaser::InitRun - m_autoAdvanceDirectLaser: " << m_autoAdvanceDirectLaser << std::endl; + std::cout << "PHG4TpcDirectLaser::InitRun - phi steps: " << nPhiSteps << " min: " << minPhi << " max: " << maxPhi << std::endl; + std::cout << "PHG4TpcDirectLaser::InitRun - theta steps: " << nThetaSteps << " min: " << minTheta << " max: " << maxTheta << std::endl; + std::cout << "PHG4TpcDirectLaser::InitRun - nTotalSteps: " << nTotalSteps << std::endl; + } std::cout << "PHG4TpcDirectLaser::InitRun - electrons_per_cm: " << electrons_per_cm << std::endl; std::cout << "PHG4TpcDirectLaser::InitRun - electrons_per_gev " << electrons_per_gev << std::endl; + + //TFile * infile1 = TFile::Open("theta_phi_laser.root"); + + std::string LASER_ANGLES_ROOTFILE = std::string(getenv("CALIBRATIONROOT")) + "/TPC/DirectLaser/theta_phi_laser.root"; + TFile* infile1 = TFile::Open(LASER_ANGLES_ROOTFILE.c_str()); + + pattern = (TNtuple*) infile1->Get("angles"); + pattern->SetBranchAddress("#theta",&theta_p); + pattern->SetBranchAddress("#phi",&phi_p); return Fun4AllReturnCodes::EVENT_OK; } @@ -266,10 +284,18 @@ int PHG4TpcDirectLaser::process_event(PHCompositeNode* topNode) { AimToNextPatternStep(); } + //_________________________________________________ + + else if (m_steppingpattern) + { + AimToNextPatternStep(); + } + + //_________________________________________________ else { // use arbitrary direction - AimToThetaPhi( arbitrary_theta, arbitrary_phi); + AimToThetaPhi(arbitrary_theta, arbitrary_phi); } return Fun4AllReturnCodes::EVENT_OK; @@ -329,7 +355,21 @@ void PHG4TpcDirectLaser::SetThetaStepping(int n, double min, double max) return; } +//_____________________________________________________________ +void PHG4TpcDirectLaser::SetFileStepping(int n) +{ + if (n < 0 || n > 13802) //13802 = hard coded number of tuple entries + { + std::cout << PHWHERE << " - invalid" << std::endl; + return; + } + nTotalSteps = n; + + return; +} + //_____________________________________________________________ + void PHG4TpcDirectLaser::SetupLasers() { // clear previous lasers @@ -361,21 +401,33 @@ void PHG4TpcDirectLaser::SetupLasers() laser.m_direction = 1; laser.m_phi = M_PI / 2 * i - (15 * M_PI/180); //additional offset of 15 deg. } + // rotate around z laser.m_position.RotateZ(laser.m_phi); // append - m_lasers.push_back(laser); + m_lasers.push_back(laser); //All lasers + // if(i==0) m_lasers.push_back(laser);//Only laser 1 + // if(i==3) m_lasers.push_back(laser);// Laser 4 + // if(i<4) m_lasers.push_back(laser);//Lasers 1, 2, 3, 4 } } - + //_____________________________________________________________ void PHG4TpcDirectLaser::AimToNextPatternStep() { if (nTotalSteps >= 1) { - AimToPatternStep(currentPatternStep); - ++currentPatternStep; + if (m_steppingpattern) + { + AimToPatternStep_File(currentPatternStep); + ++currentPatternStep; + } + else + { + AimToPatternStep(currentPatternStep); + ++currentPatternStep; + } } } @@ -422,7 +474,41 @@ void PHG4TpcDirectLaser::AimToPatternStep(int n) return; } -//_____________________________________________________________ +//_____________________________________________________________ + +void PHG4TpcDirectLaser::AimToPatternStep_File(int n) +{ + //trim against overflows + n = n % nTotalSteps; + + if (Verbosity()) + { + std::cout << "PHG4TpcDirectLaser::AimToPatternStep_File - step: " << n << "/" << nTotalSteps << std::endl; + } + + // store as current pattern + currentPatternStep = n; + + pattern->GetEntry(n); + + // calculate theta + std::cout << "From file, current entry = " << n << " Theta: " << theta_p <<" Phi: " << phi_p << std::endl; + + const double theta = theta_p*M_PI/180.; + + // calculate phi + const double phi = phi_p*M_PI/180.; + + + // generate laser tracks + AimToThetaPhi(theta, phi); + + return; +} + +//_____________________________________________________________ + + void PHG4TpcDirectLaser::AppendLaserTrack(double theta, double phi, const PHG4TpcDirectLaser::Laser& laser) { if (!m_g4hitcontainer) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.h b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.h index 557c649dac..6cea75296e 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.h @@ -6,6 +6,7 @@ #include #include +#include #include #include // for string, allocator @@ -46,6 +47,10 @@ class PHG4TpcDirectLaser : public SubsysReco, public PHParameterInterface /// define steps along theta void SetThetaStepping(int n, double min, double max); + /// define steps for file + void SetFileStepping(int n); + + /// get total number of steps int GetNpatternSteps() const { @@ -64,6 +69,12 @@ class PHG4TpcDirectLaser : public SubsysReco, public PHParameterInterface m_autoAdvanceDirectLaser = value; }; + /// advance automatically through pattern from file + void SetDirectLaserPatternfromFile(bool value) + { + m_steppingpattern = value; + }; + void SetArbitraryThetaPhi(double theta, double phi) { arbitrary_theta = theta; @@ -81,6 +92,12 @@ class PHG4TpcDirectLaser : public SubsysReco, public PHParameterInterface /// aim lasers to a give step void AimToPatternStep(int n); + /// aim lasers to a give step from file + void AimToPatternStep_File(int n); + + float theta_p, phi_p; + TNtuple *pattern = nullptr; + /// aim to next step void AimToNextPatternStep(); @@ -141,6 +158,10 @@ class PHG4TpcDirectLaser : public SubsysReco, public PHParameterInterface /// set to true to change direct laser tracks from one event to the other bool m_autoAdvanceDirectLaser = false; + /// set to true to get stepping patern from file + bool m_steppingpattern = false; + + /// g4hit container PHG4HitContainer *m_g4hitcontainer = nullptr; From f66c865d89a676a5d9a6e31f41ed9b1cda3747fa Mon Sep 17 00:00:00 2001 From: Shuonli Date: Fri, 5 May 2023 20:08:25 -0400 Subject: [PATCH 347/468] build tower geom node in detector subsystem for new stepping --- .../g4simulation/g4ihcal/PHG4IHCalDetector.cc | 138 +++++++++++++++++- .../g4simulation/g4ihcal/PHG4IHCalDetector.h | 4 + .../g4ihcal/PHG4IHCalSteppingAction.cc | 15 +- .../g4ihcal/PHG4IHCalSubsystem.cc | 6 +- .../g4simulation/g4ohcal/PHG4OHCalDetector.cc | 133 ++++++++++++++++- .../g4simulation/g4ohcal/PHG4OHCalDetector.h | 4 + .../g4ohcal/PHG4OHCalSteppingAction.cc | 17 ++- .../g4ohcal/PHG4OHCalSubsystem.cc | 10 +- 8 files changed, 309 insertions(+), 18 deletions(-) diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.cc index f1af9f4b2c..444f6fb0d4 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.cc @@ -9,12 +9,26 @@ #include #include #include +#include -#include +#include +#include +#include // for PHNode +#include +#include // for PHObject +#include +#include #include + #include #include +#include // for convert_name_... +#include // for RawTowerGeom +#include // for RawTowerGeomC... +#include +#include + #include #include @@ -129,7 +143,7 @@ void PHG4IHCalDetector::ConstructMe(G4LogicalVolume *logicWorld) } } } - + if(!m_Params->get_int_param("saveg4hit")) AddGeometryNode(); return; } @@ -141,7 +155,7 @@ int PHG4IHCalDetector::ConstructIHCal(G4LogicalVolume *hcalenvelope) gdmlParser.SetOverlapCheck(OverlapCheck()); gdmlParser.Read(m_GDMPath, false); - G4AssemblyVolume *abs_asym = reader->GetAssembly("InnerSector"); //absorber + G4AssemblyVolume *abs_asym = reader->GetAssembly("InnerSector"); // absorber m_ScintiMotherAssembly = reader->GetAssembly("InnerTileAssembly90"); // scintillator std::vector::iterator it = abs_asym->GetVolumesIterator(); static const unsigned int tilepersec = 24 * 4 * 2; @@ -421,3 +435,121 @@ int PHG4IHCalDetector::map_layerid(const int layer_id) } return rowid; } + +//This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco. +void PHG4IHCalDetector::AddGeometryNode() +{ + PHNodeIterator iter(topNode()); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << "Run Node missing, exiting." << std::endl; + gSystem->Exit(1); + exit(1); + } + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", m_SuperDetector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(m_SuperDetector); + runNode->addNode(RunDetNode); + } + m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector; + m_RawTowerGeom = findNode::getClass(topNode(), m_TowerGeomNodeName); + if (!m_RawTowerGeom) + { + m_RawTowerGeom = new RawTowerGeomContainer_Cylinderv1(RawTowerDefs::convert_name_to_caloid(m_SuperDetector)); + PHIODataNode *newNode = new PHIODataNode(m_RawTowerGeom, m_TowerGeomNodeName, "PHObject"); + RunDetNode->addNode(newNode); + } + double innerrad = m_Params->get_double_param(PHG4HcalDefs::innerrad); + double thickness = m_Params->get_double_param(PHG4HcalDefs::outerrad) - innerrad; + m_RawTowerGeom->set_radius(innerrad); + m_RawTowerGeom->set_thickness(thickness); + m_RawTowerGeom->set_phibins(m_Params->get_int_param(PHG4HcalDefs::n_towers)); + m_RawTowerGeom->set_etabins(m_Params->get_int_param("etabins")); + double geom_ref_radius = innerrad + thickness / 2.; + double phistart = m_Params->get_double_param("phistart"); + if (!std::isfinite(phistart)) + { + std::cout << PHWHERE << " phistart is not finite: " << phistart + << ", exiting now (this will crash anyway)" << std::endl; + gSystem->Exit(1); + } + for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++) + { + double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers); + std::pair range = std::make_pair(phiend, phistart); + phistart = phiend; + m_RawTowerGeom->set_phibounds(i, range); + } + double etalowbound = - m_Params->get_double_param("scinti_eta_coverage_neg"); + for (int i = 0; i < m_Params->get_int_param("etabins"); i++) + { + //double etahibound = etalowbound + 2.2 / get_int_param("etabins"); + double etahibound = etalowbound + + (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins"); + std::pair range = std::make_pair(etalowbound, etahibound); + m_RawTowerGeom->set_etabounds(i, range); + etalowbound = etahibound; + } + for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++) + { + for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++) + { + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::convert_name_to_caloid(m_SuperDetector), ieta, iphi); + + const double x(geom_ref_radius * cos(m_RawTowerGeom->get_phicenter(iphi))); + const double y(geom_ref_radius * sin(m_RawTowerGeom->get_phicenter(iphi))); + const double z(geom_ref_radius / tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta)))); + + RawTowerGeom *tg = m_RawTowerGeom->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + return; + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + return; + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + return; + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeom->add_tower_geometry(tg); + } + } + } + if (Verbosity() > 0) + { + m_RawTowerGeom->identify(); + } + +} diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.h b/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.h index 7d5c162b17..770a6463ec 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.h +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalDetector.h @@ -20,6 +20,7 @@ class PHG4IHCalDisplayAction; class PHParameters; class PHG4Subsystem; class PHG4GDMLConfig; +class RawTowerGeomContainer; class PHG4IHCalDetector : public PHG4Detector { @@ -50,6 +51,7 @@ class PHG4IHCalDetector : public PHG4Detector int GetSectorId(G4VPhysicalVolume *volume) const; private: + void AddGeometryNode(); int map_towerid(const int tower_id); int map_layerid(const int layer_id); int ConstructIHCal(G4LogicalVolume *sandwich); @@ -81,6 +83,8 @@ class PHG4IHCalDetector : public PHG4Detector PHG4GDMLConfig *gdml_config = nullptr; std::string m_GDMPath; + RawTowerGeomContainer *m_RawTowerGeom = nullptr; + std::string m_TowerGeomNodeName; }; #endif // G4IHCAL_PHG4IHCALDETECTOR_H diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc index f02ee3c9f2..8c22f61c01 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc @@ -126,7 +126,7 @@ int PHG4IHCalSteppingAction::InitWithNode(PHCompositeNode* topNode) std::cout << e.what() << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - topNode->print(); + if (Verbosity() > 1) topNode->print(); } return 0; @@ -181,7 +181,7 @@ bool PHG4IHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) const G4Track* aTrack = aStep->GetTrack(); // we only need visible energy here double light_yield = eion; - + // correct evis using light map if (m_LightScintModelFlag) { @@ -582,7 +582,14 @@ void PHG4IHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) dst_node = new PHCompositeNode("DST"); topNode->addNode(dst_node); } + PHNodeIterator dstiter(dst_node); + PHCompositeNode* DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector())); + if (!DetNode) + { + DetNode = new PHCompositeNode(m_Detector->SuperDetector()); + dst_node->addNode(DetNode); + } m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); - PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERS_HCALIN", "PHObject"); - dst_node->addNode(towerNode); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject"); + DetNode->addNode(towerNode); } diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc index 7bce1f968a..af52dec626 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc @@ -152,6 +152,9 @@ void PHG4IHCalSubsystem::SetDefaultParameters() set_default_double_param("light_balance_inner_radius", NAN); set_default_double_param("light_balance_outer_corr", NAN); set_default_double_param("light_balance_outer_radius", NAN); + set_default_double_param("phistart", NAN); + set_default_double_param("scinti_eta_coverage_neg", 1.1); + set_default_double_param("scinti_eta_coverage_pos", 1.1); set_default_double_param(PHG4HcalDefs::outerrad, 274.010 / 2 + 3); set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); @@ -169,7 +172,8 @@ void PHG4IHCalSubsystem::SetDefaultParameters() set_default_int_param(PHG4HcalDefs::n_towers, 64); set_default_int_param(PHG4HcalDefs::scipertwr, 4); set_default_int_param(PHG4HcalDefs::n_scinti_tiles, 12); - set_default_int_param("saveg4hit", 1); + set_default_int_param("etabins", 24); + set_default_int_param("saveg4hit", 0); set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc index 17eb36f5e1..6b279ece8f 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.cc @@ -10,17 +10,29 @@ #include #include #include +#include #include #include +#include +#include +#include // for PHNode +#include +#include // for PHObject #include -#include +#include #include #include #include +#include // for convert_name_... +#include // for RawTowerGeom +#include // for RawTowerGeomC... +#include +#include + #include #include @@ -150,7 +162,7 @@ void PHG4OHCalDetector::ConstructMe(G4LogicalVolume *logicWorld) } } } - + if(!m_Params->get_int_param("saveg4hit")) AddGeometryNode(); return; } @@ -477,3 +489,120 @@ int PHG4OHCalDetector::map_layerid(const unsigned int isector, const int layer_i } return rowid; } + +// This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco. +void PHG4OHCalDetector::AddGeometryNode() +{ + PHNodeIterator iter(topNode()); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << "Run Node missing, exiting." << std::endl; + gSystem->Exit(1); + exit(1); + } + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", m_SuperDetector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(m_SuperDetector); + runNode->addNode(RunDetNode); + } + m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector; + m_RawTowerGeom = findNode::getClass(topNode(), m_TowerGeomNodeName); + if (!m_RawTowerGeom) + { + m_RawTowerGeom = new RawTowerGeomContainer_Cylinderv1(RawTowerDefs::convert_name_to_caloid(m_SuperDetector)); + PHIODataNode *newNode = new PHIODataNode(m_RawTowerGeom, m_TowerGeomNodeName, "PHObject"); + RunDetNode->addNode(newNode); + } + double innerrad = m_Params->get_double_param(PHG4HcalDefs::innerrad); + double thickness = m_Params->get_double_param(PHG4HcalDefs::outerrad) - innerrad; + m_RawTowerGeom->set_radius(innerrad); + m_RawTowerGeom->set_thickness(thickness); + m_RawTowerGeom->set_phibins(m_Params->get_int_param(PHG4HcalDefs::n_towers)); + m_RawTowerGeom->set_etabins(m_Params->get_int_param("etabins")); + double geom_ref_radius = innerrad + thickness / 2.; + double phistart = m_Params->get_double_param("phistart"); + if (!std::isfinite(phistart)) + { + std::cout << PHWHERE << " phistart is not finite: " << phistart + << ", exiting now (this will crash anyway)" << std::endl; + gSystem->Exit(1); + } + for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++) + { + double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers); + std::pair range = std::make_pair(phiend, phistart); + phistart = phiend; + m_RawTowerGeom->set_phibounds(i, range); + } + double etalowbound = -m_Params->get_double_param("scinti_eta_coverage_neg"); + for (int i = 0; i < m_Params->get_int_param("etabins"); i++) + { + // double etahibound = etalowbound + 2.2 / get_int_param("etabins"); + double etahibound = etalowbound + + (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins"); + std::pair range = std::make_pair(etalowbound, etahibound); + m_RawTowerGeom->set_etabounds(i, range); + etalowbound = etahibound; + } + for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++) + { + for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++) + { + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::convert_name_to_caloid(m_SuperDetector), ieta, iphi); + + const double x(geom_ref_radius * cos(m_RawTowerGeom->get_phicenter(iphi))); + const double y(geom_ref_radius * sin(m_RawTowerGeom->get_phicenter(iphi))); + const double z(geom_ref_radius / tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta)))); + + RawTowerGeom *tg = m_RawTowerGeom->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + return; + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + return; + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + return; + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeom->add_tower_geometry(tg); + } + } + } + if (Verbosity() > 0) + { + m_RawTowerGeom->identify(); + } +} diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.h b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.h index b56689d231..8626d71bd2 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalDetector.h @@ -20,6 +20,7 @@ class PHG4OHCalFieldSetup; class PHParameters; class PHG4Subsystem; class PHG4GDMLConfig; +class RawTowerGeomContainer; class PHG4OHCalDetector : public PHG4Detector { @@ -47,6 +48,7 @@ class PHG4OHCalDetector : public PHG4Detector std::tuple GetRowColumnId(G4VPhysicalVolume *volume) const; private: + void AddGeometryNode(); int ConstructOHCal(G4LogicalVolume *hcalenvelope); int map_towerid(const int tower_id); int map_layerid(const unsigned int isector, const int layer_id); @@ -78,6 +80,8 @@ class PHG4OHCalDetector : public PHG4Detector PHG4GDMLConfig *gdml_config = nullptr; std::string m_GDMPath; + RawTowerGeomContainer *m_RawTowerGeom = nullptr; + std::string m_TowerGeomNodeName; }; #endif // G4OHCAL_PHG4OHCALDETECTOR_H diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc index 7473b4dfcb..ca3c663533 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc @@ -169,7 +169,7 @@ int PHG4OHCalSteppingAction::InitWithNode(PHCompositeNode* topNode) std::cout << e.what() << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - topNode->print(); + if (Verbosity() > 1) topNode->print(); } return 0; } @@ -208,7 +208,7 @@ bool PHG4OHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) layer_id = std::get<1>(layer_tower); tower_id = std::get<2>(layer_tower); - //std::cout<<"******** Outer HCal\t"<GetName()<<"\t"<GetName()<<"\t"<GetTrack(); // we only need visible energy here double light_yield = eion; - + // correct evis using light map if (m_LightScintModelFlag) { @@ -740,7 +740,14 @@ void PHG4OHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) dst_node = new PHCompositeNode("DST"); topNode->addNode(dst_node); } + PHNodeIterator dstiter(dst_node); + PHCompositeNode* DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector())); + if (!DetNode) + { + DetNode = new PHCompositeNode(m_Detector->SuperDetector()); + dst_node->addNode(DetNode); + } m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); - PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERS_HCALOUT", "PHObject"); - dst_node->addNode(towerNode); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject"); + DetNode->addNode(towerNode); } diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc index 3462a388ad..c9d960c42f 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc @@ -9,7 +9,7 @@ #include -#include // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include // for PHG4SteppingAction @@ -159,6 +159,9 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_double_param("light_balance_inner_radius", NAN); set_default_double_param("light_balance_outer_corr", NAN); set_default_double_param("light_balance_outer_radius", NAN); + set_default_double_param("phistart", NAN); + set_default_double_param("scinti_eta_coverage_neg", 1.1); + set_default_double_param("scinti_eta_coverage_pos", 1.1); set_default_double_param("outer_radius", 269.317 + 5); set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); @@ -168,7 +171,7 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_double_param("rot_z", 0.); set_default_double_param("size_z", 639.240 + 10); set_default_double_param("Birk_const", 0.07943); - set_default_double_param("tmin", -20.); + set_default_double_param("tmin", -20.); set_default_double_param("tmax", 60.); set_default_int_param("field_check", 0); set_default_int_param("light_scint_model", 1); @@ -176,7 +179,8 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_int_param("n_towers", 64); set_default_int_param(PHG4HcalDefs::scipertwr, 5); set_default_int_param("n_scinti_tiles", 12); - set_default_int_param("saveg4hit", 1); + set_default_int_param("etabins", 24); + set_default_int_param("saveg4hit", 0); set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); std::string defaultmapfilename; From 0c2cb42cce8dc8b7340814a2b10e7e3a5e32e753 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Sat, 6 May 2023 15:30:41 -0400 Subject: [PATCH 348/468] Add methods to fix tpc sectors. --- .../HelicalFitter.cc | 44 +++++++++++++++---- .../TrackerMillepedeAlignment/HelicalFitter.h | 3 ++ offline/packages/trackbase/TrackFitUtils.cc | 2 + 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 332042931a..f93ab0a4c6 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -180,7 +180,7 @@ int HelicalFitter::process_event(PHCompositeNode*) auto xloc = cluster->getLocalX(); // in cm auto zloc = cluster->getLocalY(); if(trkrid == TrkrDefs::tpcId) { zloc = convertTimeToZ(cluskey, cluster); } - //float y = 0.0; // Because the fitpoint is on the surface, y will always be zero in local coordinates + //float yloc = 0.0; // Because the fitpoint is on the surface, y will always be zero in local coordinates Acts::Vector2 residual(xloc - fitpoint_local(0), zloc - fitpoint_local(1)); @@ -207,11 +207,6 @@ int HelicalFitter::process_event(PHCompositeNode*) int glbl_label[NGL]; getGlobalLabels(surf, glbl_label); // these depend on the sensor grouping - // These derivatives are for the local parameters - // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) - //std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); - //std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); - float lcl_derivativeX[NLC]; float lcl_derivativeY[NLC]; getLocalDerivativesXY(surf, global, fitpars, lcl_derivativeX, lcl_derivativeY, layer); @@ -222,11 +217,23 @@ int HelicalFitter::process_event(PHCompositeNode*) for(unsigned int i = 0; i < NGL; ++i) { - if(is_layer_param_fixed(layer, i) || is_layer_fixed(layer)) + if( is_layer_param_fixed(layer, i) || is_layer_fixed(layer) ) { glbl_derivativeX[i] = 0; glbl_derivativeY[i] = 0; } + + if(trkrid == TrkrDefs::tpcId) + { + unsigned int sector = TpcDefs::getSectorId(cluskey_vec[ivec]); + unsigned int side = TpcDefs::getSide(cluskey_vec[ivec]); + if(is_tpc_sector_fixed(layer, sector, side)) + { + std::cout << " layer " << layer << " sector " << sector << "side " << side << std::endl; + glbl_derivativeX[i] = 0; + glbl_derivativeY[i] = 0; + } + } } // Add the measurement separately for each coordinate direction to Mille @@ -293,7 +300,8 @@ int HelicalFitter::process_event(PHCompositeNode*) } } - if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) + //if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) + if(!isnan(residual(1)) && clus_sigma(1) < 1.0) {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivativeY, glbl_label, residual(1), _error_inflation*clus_sigma(1));} } @@ -861,6 +869,7 @@ unsigned int HelicalFitter::addSiliconClusters(std::vector& fitpars, std: { fixed_layers.insert(layer); } + bool HelicalFitter::is_layer_param_fixed(unsigned int layer, unsigned int param) { @@ -879,6 +888,25 @@ void HelicalFitter::set_layer_param_fixed(unsigned int layer, unsigned int param fixed_layer_params.insert(pair); } +void HelicalFitter::set_tpc_sector_fixed(unsigned int region, unsigned int sector, unsigned int side) + { + // make a combined subsector index + unsigned int subsector = region * 24 + side * 12 + sector; + fixed_sectors.insert(subsector); + } + +bool HelicalFitter::is_tpc_sector_fixed(unsigned int layer, unsigned int sector, unsigned int side) + { + bool ret = false; + unsigned int region = getTpcRegion(layer); + unsigned int subsector = region * 24 + side * 12 + sector; + auto it = fixed_sectors.find(subsector); + if(it != fixed_sectors.end()) + ret = true; + + return ret; + } + void HelicalFitter::correctTpcGlobalPositions(std::vector global_vec, std::vector cluskey_vec) { for(unsigned int iclus=0;iclus fixed_layers; + std::set fixed_sectors; std::set> fixed_layer_params; // set default groups to lowest level diff --git a/offline/packages/trackbase/TrackFitUtils.cc b/offline/packages/trackbase/TrackFitUtils.cc index 81c37388a3..14fa95d376 100644 --- a/offline/packages/trackbase/TrackFitUtils.cc +++ b/offline/packages/trackbase/TrackFitUtils.cc @@ -370,12 +370,14 @@ Acts::Vector3 TrackFitUtils::getPCALinePoint(Acts::Vector3 global, Acts::Vector3 // The position of the closest point on the line to global is: // posref + projection of difference between the point and posref on the tangent vector Acts::Vector3 pca = posref + ( (global - posref).dot(tangent) ) * tangent; + /* if( (pca-posref).norm() > 0.001) { std::cout << " getPCALinePoint: old pca " << posref(0) << " " << posref(1) << " " << posref(2) << std::endl; std::cout << " getPCALinePoint: new pca " << pca(0) << " " << pca(1) << " " << pca(2) << std::endl; std::cout << " getPCALinePoint: delta pca " << pca(0) - posref(0) << " " << pca(1)-posref(1) << " " << pca(2) -posref(2) << std::endl; } + */ return pca; } From 41e0e2aadf08a350a09789afbb14e0d8a454d414 Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Sat, 6 May 2023 18:30:59 -0400 Subject: [PATCH 349/468] Final Update for Pull request to properly load the magnetic field map with CDB for KFParticle --- .../KFParticle_eventReconstruction.cc | 39 +++++------ .../KFParticle_eventReconstruction.h | 13 ++-- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 64 ++++++++++++++----- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 19 +++--- 4 files changed, 85 insertions(+), 50 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 1042d98c4d..2ba5b47fa8 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -26,9 +26,9 @@ /*****************/ #include "KFParticle_eventReconstruction.h" -#include "KFParticle_Tools.h" +#include "KFParticle_Tools.h" -//KFParticle stuff +// KFParticle stuff #include #include @@ -56,9 +56,6 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: std::vector>& selectedIntermediates, int& nPVs, int& multiplicity) { - //ALICE field is 0.5T but they set it to -5 in KFParticle? Checked momentum sums and -1.4 is more accurate - KFParticle::SetField(-1.4e0); - std::vector primaryVertices; if (m_use_fake_pv) primaryVertices.push_back(createFakePV()); @@ -137,9 +134,9 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte for (int i = 0; i < m_num_intermediate_states; ++i) num_tracks_used_by_intermediates += m_num_tracks_from_intermediate[i]; int num_remaining_tracks = m_num_tracks - num_tracks_used_by_intermediates; - unsigned int num_pot_inter_a, num_pot_inter_b, num_pot_inter_c, num_pot_inter_d; //Number of potential intermediates found + unsigned int num_pot_inter_a, num_pot_inter_b, num_pot_inter_c, num_pot_inter_d; // Number of potential intermediates found num_pot_inter_a = potentialIntermediates[0].size(); - num_pot_inter_b = m_num_intermediate_states < 2 ? 1 : potentialIntermediates[1].size(); //Ensure the code inside the loop below is executed + num_pot_inter_b = m_num_intermediate_states < 2 ? 1 : potentialIntermediates[1].size(); // Ensure the code inside the loop below is executed num_pot_inter_c = m_num_intermediate_states < 3 ? 1 : potentialIntermediates[2].size(); num_pot_inter_d = m_num_intermediate_states < 4 ? 1 : potentialIntermediates[3].size(); @@ -174,7 +171,8 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte int trackElement_to_remove = -1; auto it = std::find_if(daughterParticlesAdv.begin(), daughterParticlesAdv.end(), - [&trackID_to_remove](const KFParticle& obj) { return obj.Id() == trackID_to_remove; }); + [&trackID_to_remove](const KFParticle& obj) + { return obj.Id() == trackID_to_remove; }); if (it != daughterParticlesAdv.end()) { @@ -200,7 +198,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte required_unique_vertexID += m_daughter_charge[i] * kfp_Tools_evtReco.getParticleMass(m_daughter_name[i].c_str()); } - uniqueCombinations = findUniqueDaughterCombinations(num_tracks_used_by_intermediates, m_num_tracks); //Unique comb of remaining trackIDs + uniqueCombinations = findUniqueDaughterCombinations(num_tracks_used_by_intermediates, m_num_tracks); // Unique comb of remaining trackIDs listOfTracksToAppend = appendTracksToIntermediates(motherDecayProducts, daughterParticlesAdv, goodTrackIndexAdv_withoutIntermediates, num_remaining_tracks); @@ -237,7 +235,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte for (int k = 0; k < m_num_intermediate_states; ++k) goodIntermediates[k].push_back(motherDecayProducts[k]); for (int k = 0; k < num_tracks_used_by_intermediates; ++k) goodDaughters[k].push_back(finalTracks[k]); for (int k = 0; k < num_remaining_tracks; ++k) - { //Need to deal with track mass and PID assignment for extra tracks + { // Need to deal with track mass and PID assignment for extra tracks int trackArrayID = k + m_num_intermediate_states; KFParticle slowTrack; slowTrack.Create(motherDecayProducts[trackArrayID].Parameters(), @@ -272,10 +270,10 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte for (int j = 0; j < m_num_intermediate_states; ++j) goodIntermediates[j].clear(); for (int j = 0; j < m_num_tracks; ++j) goodDaughters[j].clear(); } - } //Close forth intermediate - } //Close third intermediate - } //Close second intermediate - } //Close first intermediate + } // Close forth intermediate + } // Close third intermediate + } // Close second intermediate + } // Close first intermediate } void KFParticle_eventReconstruction::getCandidateDecay(std::vector& selectedMotherCand, @@ -297,18 +295,18 @@ void KFParticle_eventReconstruction::getCandidateDecay(std::vector& float required_unique_vertexID = 0; for (int i = n_track_start; i < n_track_stop; ++i) required_unique_vertexID += m_daughter_charge[i] * kfp_Tools_evtReco.getParticleMass(m_daughter_name[i].c_str()); - for (unsigned int i_comb = 0; i_comb < goodTracksThatMeetCand.size(); ++i_comb) //Loop over all good track combinations + for (unsigned int i_comb = 0; i_comb < goodTracksThatMeetCand.size(); ++i_comb) // Loop over all good track combinations { KFParticle daughterTracks[nTracks]; for (int i_track = 0; i_track < nTracks; ++i_track) { daughterTracks[i_track] = daughterParticlesCand[goodTracksThatMeetCand[i_comb][i_track]]; - } //Build array of the good tracks in that combination + } // Build array of the good tracks in that combination - for (unsigned int i_uc = 0; i_uc < uniqueCombinations.size(); ++i_uc) //Loop over unique track PID assignments + for (unsigned int i_uc = 0; i_uc < uniqueCombinations.size(); ++i_uc) // Loop over unique track PID assignments { - for (unsigned int i_pv = 0; i_pv < primaryVerticesCand.size(); ++i_pv) //Loop over all PVs in the event + for (unsigned int i_pv = 0; i_pv < primaryVerticesCand.size(); ++i_pv) // Loop over all PVs in the event { std::string* names = &uniqueCombinations[i_uc][0]; std::tie(candidate, isGood) = getCombination(daughterTracks, names, primaryVerticesCand[i_pv], m_constrain_to_vertex, @@ -405,3 +403,8 @@ KFParticle KFParticle_eventReconstruction::createFakePV() return kfp_vertex; } + +void KFParticle_eventReconstruction::setBz(double Bz_Tesla) +{ + KFParticle::SetField(Bz_Tesla); +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h index f1b33a71bf..4a3e854a02 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h @@ -50,7 +50,7 @@ class KFParticle_eventReconstruction : public KFParticle_Tools std::vector>& selectedIntermediates, int& nPVs, int& multiplicity); - ///Used to reconstruct simple decays with no intermediate states + /// Used to reconstruct simple decays with no intermediate states void buildBasicChain(std::vector& selectedMotherBasic, std::vector& selectedVertexBasic, std::vector>& selectedDaughtersBasic, @@ -58,7 +58,7 @@ class KFParticle_eventReconstruction : public KFParticle_Tools const std::vector& goodTrackIndexBasic, const std::vector& primaryVerticesBasic); - ///Used to reconstruct more complicated decays with up to four intermediate states + /// Used to reconstruct more complicated decays with up to four intermediate states void buildChain(std::vector& selectedMotherAdv, std::vector& selectedVertexAdv, std::vector>& selectedDaughtersAdv, @@ -67,7 +67,7 @@ class KFParticle_eventReconstruction : public KFParticle_Tools const std::vector& goodTrackIndexAdv, const std::vector& primaryVerticesAdv); - ///Basic building block for event reconstruction and selection + /// Basic building block for event reconstruction and selection void getCandidateDecay(std::vector& selectedMotherCand, std::vector& selectedVertexCand, std::vector>& selectedDaughtersCand, @@ -77,19 +77,20 @@ class KFParticle_eventReconstruction : public KFParticle_Tools int n_track_start, int n_track_stop, bool isIntermediate, int intermediateNumber, bool constrainMass); - ///Method to chose best candidate from a selection of common SV's + /// Method to chose best candidate from a selection of common SV's int selectBestCombination(bool PVconstraint, bool isAnInterMother, std::vector possibleCandidates, std::vector possibleVertex); KFParticle createFakePV(); + void setBz(double Bz_Tesla); protected: bool m_constrain_to_vertex; bool m_constrain_int_mass; bool m_use_fake_pv; - //private: + // private: }; -#endif //KFPARTICLESPHENIX_KFPARTICLEEVENTRECONSTRUCTION_H +#endif // KFPARTICLESPHENIX_KFPARTICLEEVENTRECONSTRUCTION_H diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 73ec502580..3def12a23b 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,17 +29,20 @@ #include #include - +#include // for obtaining the B field value +#include // for getting the TTree from the file + // #include // for KFParticle #include // for Fun4AllBase::VERBOSITY... #include // for SubsysReco -#include // for toupper -#include // for sqrt -#include // for size_t, exit -#include // for operator<<, endl, basi... -#include // for map -#include // for tie, tuple +#include // for accessing the field map file from the CDB +#include // for toupper +#include // for sqrt +#include // for size_t, exit +#include // for operator<<, endl, basi... +#include // for map +#include // for tie, tuple class PHCompositeNode; @@ -91,6 +94,32 @@ int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) int returnCode = 0; if (!m_decayDescriptor.empty()) returnCode = parseDecayDescriptor(); + // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + char *calibrationsroot = getenv("CALIBRATIONROOT"); + std::string m_magField = "sphenix3dtrackingmapxyz.root"; + // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name + + if (calibrationsroot != nullptr) + { + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + } + + TFile *fin = new TFile(m_magField.c_str()); + fin->cd(); + + TTree *fieldmap = (TTree *) fin->Get("fieldmap"); + TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10); + + fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0"); + + // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction + m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T + + fieldmap->Delete(); + BzHist->Delete(); + fin->Close(); + return returnCode; } @@ -116,7 +145,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) if (Verbosity() >= VERBOSITY_SOME) std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - + setBz(m_Bz); createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity); if (!m_has_intermediates_sPHENIX) intermediates = daughters; @@ -233,33 +262,34 @@ int KFParticle_sPHENIX::parseDecayDescriptor() std::string startIntermediate = "{"; std::string endIntermediate = "}"; - //These tracks require a + or - after their name for TDatabasePDG + // These tracks require a + or - after their name for TDatabasePDG std::string specialTracks[] = {"e", "mu", "pi", "K"}; std::string manipulateDecayDescriptor = m_decayDescriptor; - //Remove all white space before we begin + // Remove all white space before we begin size_t pos; while ((pos = manipulateDecayDescriptor.find(" ")) != std::string::npos) manipulateDecayDescriptor.replace(pos, 1, ""); - //Check for charge conjugate requirement + // Check for charge conjugate requirement std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3); - std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) { c = ::toupper(c); }); + std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) + { c = ::toupper(c); }); - //Remove the CC check if needed + // Remove the CC check if needed if (checkForCC == "[]CC") { manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4); getChargeConjugate(true); } - //Find the initial particle + // Find the initial particle size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow); mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint); if (!findParticle(mother)) ddCanBeParsed = false; manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length()); - //Try and find the intermediates + // Try and find the intermediates while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos) { size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos); @@ -272,7 +302,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() else ddCanBeParsed = false; - //Now find the daughters associated to this intermediate + // Now find the daughters associated to this intermediate int nDaughters = 0; intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length()); while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos) @@ -315,7 +345,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() nTracks += nDaughters; } - //Now find any remaining reconstructable tracks from the mother + // Now find any remaining reconstructable tracks from the mother while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos) { daughter = manipulateDecayDescriptor.substr(0, daughterLocator); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 6c24b5f48b..5eeee2d680 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -33,10 +33,10 @@ #include "KFParticle_DST.h" #include "KFParticle_nTuple.h" -//sPHENIX stuff +// sPHENIX stuff #include -//KFParticle stuff +// KFParticle stuff #include #include // for max @@ -76,7 +76,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K int parseDecayDescriptor(); - ///Parameters for the user to vary + /// Parameters for the user to vary void setDecayDescriptor(const std::string &decayDescriptor) { m_decayDescriptor = decayDescriptor; } @@ -200,9 +200,9 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void allowZeroMassTracks(bool allow) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate) - { - m_extrapolateTracksToSV = extrapolate; - m_extrapolateTracksToSV_nTuple = extrapolate; + { + m_extrapolateTracksToSV = extrapolate; + m_extrapolateTracksToSV_nTuple = extrapolate; } void constrainIntermediateMasses(bool constrain_int_mass) { m_constrain_int_mass = constrain_int_mass; } @@ -290,10 +290,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void getAllPVInfo(bool pvinfo) { m_get_all_PVs = pvinfo; } - ///Use alternate vertex and track fitters + /// Use alternate vertex and track fitters void setVertexMapNodeName(const std::string &vtx_map_node_name) { m_vtx_map_node_name = m_vtx_map_node_name_nTuple = vtx_map_node_name; } - ///Use alternate vertex and track fitters + /// Use alternate vertex and track fitters void setTrackMapNodeName(const std::string &trk_map_node_name) { m_trk_map_node_name = m_trk_map_node_name_nTuple = trk_map_node_name; } private: @@ -302,9 +302,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K bool m_require_mva; bool m_save_dst; bool m_save_output; + float m_Bz = 0; std::string m_outfile_name; TFile *m_outfile; std::string m_decayDescriptor; }; -#endif //KFPARTICLESPHENIX_KFPARTICLESPHENIX_H +#endif // KFPARTICLESPHENIX_KFPARTICLESPHENIX_H From f23fece73f9f40d9afd5093e4c7297bcdd5faa42 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 7 May 2023 00:03:34 -0400 Subject: [PATCH 350/468] add new stepping for old geom --- .../g4simulation/g4detectors/Makefile.am | 1 + .../g4detectors/PHG4InnerHcalDetector.cc | 130 ++++++++++++ .../g4detectors/PHG4InnerHcalDetector.h | 6 +- .../PHG4InnerHcalSteppingAction.cc | 197 +++++++++++++++-- .../g4detectors/PHG4InnerHcalSteppingAction.h | 10 +- .../g4detectors/PHG4InnerHcalSubsystem.cc | 11 +- .../g4detectors/PHG4OuterHcalDetector.cc | 130 ++++++++++++ .../g4detectors/PHG4OuterHcalDetector.h | 4 + .../PHG4OuterHcalSteppingAction.cc | 199 ++++++++++++++++-- .../g4detectors/PHG4OuterHcalSteppingAction.h | 9 +- .../g4detectors/PHG4OuterHcalSubsystem.cc | 13 +- .../g4ihcal/PHG4IHCalSubsystem.cc | 2 +- 12 files changed, 661 insertions(+), 51 deletions(-) diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index 1e65ce5de0..d33a0ca26f 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -27,6 +27,7 @@ AM_LDFLAGS = \ libg4detectors_io_la_LIBADD = \ -lphool \ + -lcalo_io \ -lphparameter diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.cc index 9b480e4a50..7bcc849c56 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.cc @@ -11,9 +11,21 @@ #include #include +#include +#include +#include // for PHNode +#include +#include // for PHObject +#include #include #include +#include // for convert_name_... +#include // for RawTowerGeom +#include // for RawTowerGeomC... +#include +#include + #include #include @@ -488,6 +500,7 @@ void PHG4InnerHcalDetector::ConstructMe(G4LogicalVolume *logicWorld) } ++it; } + if (!m_Params->get_int_param("saveg4hit")) AddGeometryNode(); return; } @@ -934,3 +947,120 @@ std::pair PHG4InnerHcalDetector::GetLayerTowerId(G4VPhysicalVolume *vo // terminates, so using the standard exit() makes them happy exit(1); } + +// This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco. +void PHG4InnerHcalDetector::AddGeometryNode() +{ + PHNodeIterator iter(topNode()); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << "Run Node missing, exiting." << std::endl; + gSystem->Exit(1); + exit(1); + } + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", m_SuperDetector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(m_SuperDetector); + runNode->addNode(RunDetNode); + } + m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector; + m_RawTowerGeom = findNode::getClass(topNode(), m_TowerGeomNodeName); + if (!m_RawTowerGeom) + { + m_RawTowerGeom = new RawTowerGeomContainer_Cylinderv1(RawTowerDefs::convert_name_to_caloid(m_SuperDetector)); + PHIODataNode *newNode = new PHIODataNode(m_RawTowerGeom, m_TowerGeomNodeName, "PHObject"); + RunDetNode->addNode(newNode); + } + double innerrad = m_Params->get_double_param(PHG4HcalDefs::innerrad); + double thickness = m_Params->get_double_param(PHG4HcalDefs::outerrad) - innerrad; + m_RawTowerGeom->set_radius(innerrad); + m_RawTowerGeom->set_thickness(thickness); + m_RawTowerGeom->set_phibins(m_Params->get_int_param(PHG4HcalDefs::n_towers)); + m_RawTowerGeom->set_etabins(m_Params->get_int_param("etabins")); + double geom_ref_radius = innerrad + thickness / 2.; + double phistart = m_Params->get_double_param("phistart"); + if (!std::isfinite(phistart)) + { + std::cout << PHWHERE << " phistart is not finite: " << phistart + << ", exiting now (this will crash anyway)" << std::endl; + gSystem->Exit(1); + } + for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++) + { + double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers); + std::pair range = std::make_pair(phiend, phistart); + phistart = phiend; + m_RawTowerGeom->set_phibounds(i, range); + } + double etalowbound = -m_Params->get_double_param("scinti_eta_coverage_neg"); + for (int i = 0; i < m_Params->get_int_param("etabins"); i++) + { + // double etahibound = etalowbound + 2.2 / get_int_param("etabins"); + double etahibound = etalowbound + + (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins"); + std::pair range = std::make_pair(etalowbound, etahibound); + m_RawTowerGeom->set_etabounds(i, range); + etalowbound = etahibound; + } + for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++) + { + for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++) + { + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::convert_name_to_caloid(m_SuperDetector), ieta, iphi); + + const double x(geom_ref_radius * cos(m_RawTowerGeom->get_phicenter(iphi))); + const double y(geom_ref_radius * sin(m_RawTowerGeom->get_phicenter(iphi))); + const double z(geom_ref_radius / tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta)))); + + RawTowerGeom *tg = m_RawTowerGeom->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + return; + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + return; + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + return; + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeom->add_tower_geometry(tg); + } + } + } + if (Verbosity() > 0) + { + m_RawTowerGeom->identify(); + } +} \ No newline at end of file diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.h b/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.h index 1802d44893..b5fb54037f 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.h +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalDetector.h @@ -11,7 +11,7 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include // for Cartesian_base_ref_count::... #include -#include // for Point_2 +#include // for Point_2 #pragma GCC diagnostic pop #include @@ -28,6 +28,7 @@ class PHCompositeNode; class PHG4InnerHcalDisplayAction; class PHParameters; class PHG4Subsystem; +class RawTowerGeomContainer; class PHG4InnerHcalDetector : public PHG4Detector { @@ -66,6 +67,7 @@ class PHG4InnerHcalDetector : public PHG4Detector std::pair GetLayerTowerId(G4VPhysicalVolume *volume) const; protected: + void AddGeometryNode(); int ConstructInnerHcal(G4LogicalVolume *sandwich); double x_at_y(Point_2 &p0, Point_2 &p1, double yin); PHG4InnerHcalDisplayAction *m_DisplayAction = nullptr; @@ -103,6 +105,8 @@ class PHG4InnerHcalDetector : public PHG4Detector std::map> m_ScintiTilePhysVolMap; std::vector m_ScintiTilesVec; std::string m_ScintiLogicNamePrefix; + RawTowerGeomContainer *m_RawTowerGeom = nullptr; + std::string m_TowerGeomNodeName; }; #endif // G4DETECTORS_PHG4INNERHCALDETECTOR_H diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc index 425af46b50..5a1d1e1924 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc @@ -14,6 +14,18 @@ #include +#include + +#include +#include +#include +#include + +#include +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include #include @@ -26,21 +38,21 @@ #include // for G4ParticleDefinition #include // for G4ReferenceCountedHandle #include -#include // for G4StepPoint -#include // for fGeomBoundary, fAtRest... -#include // for G4String +#include // for G4StepPoint +#include // for fGeomBoundary, fAtRest... +#include // for G4String #include -#include // for G4ThreeVector -#include // for G4TouchableHandle -#include // for G4Track -#include // for fStopAndKill +#include // for G4ThreeVector +#include // for G4TouchableHandle +#include // for G4Track +#include // for fStopAndKill #include -#include // for G4double -#include // for G4VPhysicalVolume -#include // for G4VTouchable -#include // for G4VUserTrackInformation +#include // for G4double +#include // for G4VPhysicalVolume +#include // for G4VTouchable +#include // for G4VUserTrackInformation -#include // for isfinite +#include // for isfinite #include #include #include @@ -57,6 +69,9 @@ PHG4InnerHcalSteppingAction::PHG4InnerHcalSteppingAction(PHG4InnerHcalDetector* , m_IsActive(m_Params->get_int_param("active")) , m_IsBlackHole(m_Params->get_int_param("blackhole")) , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model")) + , m_doG4Hit(m_Params->get_int_param("saveg4hit")) + , m_tmin(m_Params->get_double_param("tmin")) + , m_tmax(m_Params->get_double_param("tmax")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -76,7 +91,7 @@ PHG4InnerHcalSteppingAction::~PHG4InnerHcalSteppingAction() } //____________________________________________________________________________.. -int PHG4InnerHcalSteppingAction::Init() +int PHG4InnerHcalSteppingAction::InitWithNode(PHCompositeNode* topNode) { if (m_LightScintModelFlag) { @@ -98,18 +113,135 @@ int PHG4InnerHcalSteppingAction::Init() { std::cout << "ERROR: could not find Histogram " << m_Params->get_string_param("MapHistoName") << " in " << m_Params->get_string_param("MapFileName") << std::endl; gSystem->Exit(1); - exit(1); // make code checkers which do not know gSystem->Exit() happy + exit(1); // make code checkers which do not know gSystem->Exit() happy } m_MapCorrHist->SetDirectory(nullptr); // rootism: this needs to be set otherwise histo vanished when closing the file file->Close(); delete file; } + if (!m_doG4Hit) + { + try + { + CreateNodeTree(topNode); + } + catch (std::exception& e) + { + std::cout << e.what() << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + if (Verbosity() > 1) topNode->print(); + } + return 0; } +//____________________________________________________________________________.. +bool PHG4InnerHcalSteppingAction::NoHitSteppingAction(const G4Step* aStep) +{ + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); + G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); + // get volume of the current step + G4VPhysicalVolume* volume = touch->GetVolume(); + + // m_Detector->IsInIHCal(volume) + // returns + // 0 is outside of IHCal + // 1 is inside scintillator + // -1 is steel absorber + + int whichactive = m_Detector->IsInInnerHcal(volume); + + if (!whichactive) + { + return false; + } + int layer_id = -1; + int tower_id = -1; + if (whichactive > 0) // scintillator + { + std::pair layer_tower = m_Detector->GetLayerTowerId(volume); + layer_id = layer_tower.first; + tower_id = layer_tower.second; + + // std::cout<<"******** Inner HCal\t"<GetName()<<"\t"<GetPreStepPoint(); + G4StepPoint* postPoint = aStep->GetPostStepPoint(); + // time window cut + double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); + if (time < m_tmin || time > m_tmax) return false; + G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; + const G4Track* aTrack = aStep->GetTrack(); + // we only need visible energy here + double light_yield = eion; + + // correct evis using light map + if (m_LightScintModelFlag) + { + light_yield = GetVisibleEnergyDeposition(aStep); // for scintillator only, calculate light yields + if (m_MapCorrHist) + { + const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle(); + const G4ThreeVector& worldPosition = postPoint->GetPosition(); + G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition); + float lx = (localPosition.x() / cm); + float lz = fabs(localPosition.z() / cm); + // adjust to tilemap coordinates + int lcz = (int) (5.0 * lz) + 1; + int lcx = (int) (5.0 * (lx + 12.1)) + 1; + + if ((lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsY()) && + (lcz >= 1) && (lcz <= m_MapCorrHist->GetNbinsX())) + { + light_yield *= (double) (m_MapCorrHist->GetBinContent(lcz, lcx)); + } + else + { + light_yield = 0.0; + } + } + else + { + // old correction (linear ligh yield dependence along r), never tested + light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y()); + } + } + // find the tower index for this step, tower_id is ieta, layer_id/4 is iphi + unsigned int ieta = tower_id; + unsigned int iphi = (unsigned int) layer_id / 4; + unsigned int tower_key = TowerInfoDefs::encode_hcal(ieta, iphi); + m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield); + // set keep for the track + if (light_yield > 0) + { + if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + { + if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + { + pp->SetKeep(1); // we want to keep the track + } + } + } + + return true; +} + //____________________________________________________________________________.. bool PHG4InnerHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { + if ((!m_doG4Hit) && (!m_IsBlackHole)) + { + return NoHitSteppingAction(aStep); + } G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); // get volume of the current step @@ -203,18 +335,18 @@ bool PHG4InnerHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { m_Hit = new PHG4Hitv1(); } - //here we set the entrance values in cm + // here we set the entrance values in cm m_Hit->set_x(0, prePoint->GetPosition().x() / cm); m_Hit->set_y(0, prePoint->GetPosition().y() / cm); m_Hit->set_z(0, prePoint->GetPosition().z() / cm); // time in ns m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond); - //set and save the track ID + // set and save the track ID m_Hit->set_trkid(aTrack->GetTrackID()); m_SaveTrackId = aTrack->GetTrackID(); - //set the initial energy deposit + // set the initial energy deposit m_Hit->set_edep(0); - if (whichactive > 0) // return of IsInInnerHcalDetector, > 0 hit in scintillator, < 0 hit in absorber + if (whichactive > 0) // return of IsInInnerHcalDetector, > 0 hit in scintillator, < 0 hit in absorber { m_Hit->set_scint_id(tower_id); // the slat id m_Hit->set_eion(0); // only implemented for v5 otherwise empty @@ -282,7 +414,7 @@ bool PHG4InnerHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond); - //sum up the energy to get total deposited + // sum up the energy to get total deposited m_Hit->set_edep(m_Hit->get_edep() + edep); if (whichactive > 0) // return of IsInInnerHcalDetector, > 0 hit in scintillator, < 0 hit in absorber { @@ -299,7 +431,7 @@ bool PHG4InnerHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition); float lx = (localPosition.x() / cm); float lz = fabs(localPosition.z() / cm); - //adjust to tilemap coordinates + // adjust to tilemap coordinates int lcz = (int) (5.0 * lz) + 1; int lcx = (int) (5.0 * (lx + 12.1)) + 1; @@ -396,7 +528,7 @@ void PHG4InnerHcalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode) absorbernodename = "G4HIT_ABSORBER_" + m_Detector->GetName(); } - //now look for the map and grab a pointer to it. + // now look for the map and grab a pointer to it. m_Hits = findNode::getClass(topNode, hitnodename); m_AbsorberHits = findNode::getClass(topNode, absorbernodename); @@ -413,3 +545,26 @@ void PHG4InnerHcalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode) } } } + +void PHG4InnerHcalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) +{ + PHNodeIterator nodeItr(topNode); + PHCompositeNode* dst_node = dynamic_cast( + nodeItr.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cout << "PHComposite node created: DST" << std::endl; + dst_node = new PHCompositeNode("DST"); + topNode->addNode(dst_node); + } + PHNodeIterator dstiter(dst_node); + PHCompositeNode* DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector())); + if (!DetNode) + { + DetNode = new PHCompositeNode(m_Detector->SuperDetector()); + dst_node->addNode(DetNode); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject"); + DetNode->addNode(towerNode); +} \ No newline at end of file diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h index 4c6349feb8..6defe9ff8f 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h @@ -8,6 +8,7 @@ class G4Step; class G4VPhysicalVolume; class PHCompositeNode; +class TowerInfoContainer; class PHG4InnerHcalDetector; class PHParameters; class PHG4Hit; @@ -27,12 +28,15 @@ class PHG4InnerHcalSteppingAction : public PHG4SteppingAction //! stepping action bool UserSteppingAction(const G4Step *, bool) override; - int Init() override; + int InitWithNode(PHCompositeNode *topNode) override; //! reimplemented from base class void SetInterfacePointers(PHCompositeNode *) override; + void CreateNodeTree(PHCompositeNode *topNode); + private: + bool NoHitSteppingAction(const G4Step *aStep); //! pointer to the detector PHG4InnerHcalDetector *m_Detector = nullptr; @@ -57,6 +61,10 @@ class PHG4InnerHcalSteppingAction : public PHG4SteppingAction int m_IsActive = -1; int m_IsBlackHole = -1; int m_LightScintModelFlag = -1; + bool m_doG4Hit = true; + double m_tmin = -20.; + double m_tmax = 60.; + TowerInfoContainer *m_CaloInfoContainer = nullptr; }; #endif // G4DETECTORS_PHG4INNERHCALSTEPPINGACTION_H diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc index aaf6f261a3..b085bc9578 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc @@ -7,7 +7,7 @@ #include -#include // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include // for PHG4SteppingAction @@ -100,7 +100,7 @@ int PHG4InnerHcalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) // create stepping action m_SteppingAction = new PHG4InnerHcalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } else { @@ -108,7 +108,7 @@ int PHG4InnerHcalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) if (GetParams()->get_int_param("blackhole")) { m_SteppingAction = new PHG4InnerHcalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } } return 0; @@ -155,6 +155,7 @@ void PHG4InnerHcalSubsystem::SetDefaultParameters() set_default_double_param("light_balance_inner_radius", NAN); set_default_double_param("light_balance_outer_corr", NAN); set_default_double_param("light_balance_outer_radius", NAN); + set_default_double_param("phistart", NAN); set_default_double_param(PHG4HcalDefs::outerrad, 134.42); set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); @@ -168,6 +169,8 @@ void PHG4InnerHcalSubsystem::SetDefaultParameters() set_default_double_param("scinti_gap_neighbor", 0.1); set_default_double_param("scinti_inner_gap", 0.85); set_default_double_param("scinti_outer_gap", 1.22 * (5.0 / 4.0)); + set_default_double_param("tmin", -20.); + set_default_double_param("tmax", 60.); // some math issue in the code subtracts 0.4mm so the scintillator // does not end at 133.09 as per drawing but at 133.05 // adding 0.4mm compensates for this (so 133.13 gives the desired 133.09 @@ -187,6 +190,8 @@ void PHG4InnerHcalSubsystem::SetDefaultParameters() set_default_int_param(PHG4HcalDefs::n_scinti_tiles, 12); set_default_int_param(PHG4HcalDefs::n_scinti_tiles_pos, 12); set_default_int_param(PHG4HcalDefs::n_scinti_tiles_neg, 12); + set_default_int_param("etabins", 24); + set_default_int_param("saveg4hit", 1); set_default_string_param("material", "G4_Al"); std::string defaultmapfilename; diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.cc index 06964e03d1..97a2358f13 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.cc @@ -13,6 +13,18 @@ #include #include +#include +#include +#include // for PHNode +#include +#include // for PHObject +#include + +#include // for convert_name_... +#include // for RawTowerGeom +#include // for RawTowerGeomC... +#include +#include #include @@ -479,6 +491,7 @@ void PHG4OuterHcalDetector::ConstructMe(G4LogicalVolume *logicWorld) } ++it; } + if(!m_Params->get_int_param("saveg4hit")) AddGeometryNode(); return; } @@ -978,3 +991,120 @@ std::pair PHG4OuterHcalDetector::GetLayerTowerId(G4VPhysicalVolume *vo // terminates, so using the standard exit() makes them happy exit(1); } + +// This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco. +void PHG4OuterHcalDetector::AddGeometryNode() +{ + PHNodeIterator iter(topNode()); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << "Run Node missing, exiting." << std::endl; + gSystem->Exit(1); + exit(1); + } + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", m_SuperDetector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(m_SuperDetector); + runNode->addNode(RunDetNode); + } + m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector; + m_RawTowerGeom = findNode::getClass(topNode(), m_TowerGeomNodeName); + if (!m_RawTowerGeom) + { + m_RawTowerGeom = new RawTowerGeomContainer_Cylinderv1(RawTowerDefs::convert_name_to_caloid(m_SuperDetector)); + PHIODataNode *newNode = new PHIODataNode(m_RawTowerGeom, m_TowerGeomNodeName, "PHObject"); + RunDetNode->addNode(newNode); + } + double innerrad = m_Params->get_double_param(PHG4HcalDefs::innerrad); + double thickness = m_Params->get_double_param(PHG4HcalDefs::outerrad) - innerrad; + m_RawTowerGeom->set_radius(innerrad); + m_RawTowerGeom->set_thickness(thickness); + m_RawTowerGeom->set_phibins(m_Params->get_int_param(PHG4HcalDefs::n_towers)); + m_RawTowerGeom->set_etabins(m_Params->get_int_param("etabins")); + double geom_ref_radius = innerrad + thickness / 2.; + double phistart = m_Params->get_double_param("phistart"); + if (!std::isfinite(phistart)) + { + std::cout << PHWHERE << " phistart is not finite: " << phistart + << ", exiting now (this will crash anyway)" << std::endl; + gSystem->Exit(1); + } + for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++) + { + double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers); + std::pair range = std::make_pair(phiend, phistart); + phistart = phiend; + m_RawTowerGeom->set_phibounds(i, range); + } + double etalowbound = -m_Params->get_double_param("scinti_eta_coverage_neg"); + for (int i = 0; i < m_Params->get_int_param("etabins"); i++) + { + // double etahibound = etalowbound + 2.2 / get_int_param("etabins"); + double etahibound = etalowbound + + (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins"); + std::pair range = std::make_pair(etalowbound, etahibound); + m_RawTowerGeom->set_etabounds(i, range); + etalowbound = etahibound; + } + for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++) + { + for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++) + { + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::convert_name_to_caloid(m_SuperDetector), ieta, iphi); + + const double x(geom_ref_radius * cos(m_RawTowerGeom->get_phicenter(iphi))); + const double y(geom_ref_radius * sin(m_RawTowerGeom->get_phicenter(iphi))); + const double z(geom_ref_radius / tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta)))); + + RawTowerGeom *tg = m_RawTowerGeom->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + return; + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + return; + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + return; + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeom->add_tower_geometry(tg); + } + } + } + if (Verbosity() > 0) + { + m_RawTowerGeom->identify(); + } +} diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.h b/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.h index 0027343d7a..f4b9be894a 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.h +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalDetector.h @@ -30,6 +30,7 @@ class PHG4OuterHcalDisplayAction; class PHG4OuterHcalFieldSetup; class PHParameters; class PHG4Subsystem; +class RawTowerGeomContainer; class PHG4OuterHcalDetector : public PHG4Detector { @@ -64,6 +65,7 @@ class PHG4OuterHcalDetector : public PHG4Detector std::pair GetLayerTowerId(G4VPhysicalVolume *volume) const; protected: + void AddGeometryNode(); int ConstructOuterHcal(G4LogicalVolume *hcalenvelope); G4VSolid *ConstructSteelPlate(G4LogicalVolume *hcalenvelope); G4AssemblyVolume *ConstructHcalScintillatorAssembly(G4LogicalVolume *hcalenvelope); @@ -104,6 +106,8 @@ class PHG4OuterHcalDetector : public PHG4Detector std::vector m_ScintiTilesVec; std::set m_SteelAbsorberVec; std::map> m_ScintiTilePhysVolMap; + RawTowerGeomContainer *m_RawTowerGeom = nullptr; + std::string m_TowerGeomNodeName; }; #endif diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc index 8f89c77a8a..03115d7129 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc @@ -11,6 +11,7 @@ #include +#include #include #include @@ -20,8 +21,18 @@ #include // for PHG4SteppingAction #include +#include +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include +#include +#include +#include +#include + // Root headers #include // for TAxis #include @@ -33,23 +44,23 @@ #include #include -#include // for G4ParticleDefinition +#include // for G4ParticleDefinition #include #include // for G4ReferenceCountedHandle #include -#include // for G4StepPoint -#include // for fGeomBoundary, fAtRest... -#include // for G4String +#include // for G4StepPoint +#include // for fGeomBoundary, fAtRest... +#include // for G4String #include -#include // for G4ThreeVector -#include // for G4TouchableHandle -#include // for G4Track -#include // for fStopAndKill +#include // for G4ThreeVector +#include // for G4TouchableHandle +#include // for G4Track +#include // for fStopAndKill #include -#include // for G4double -#include // for G4VPhysicalVolume -#include // for G4VTouchable -#include // for G4VUserTrackInformation +#include // for G4double +#include // for G4VPhysicalVolume +#include // for G4VTouchable +#include // for G4VUserTrackInformation // finally system headers #include @@ -72,6 +83,9 @@ PHG4OuterHcalSteppingAction::PHG4OuterHcalSteppingAction(PHG4OuterHcalDetector* , m_IsBlackHoleFlag(m_Params->get_int_param("blackhole")) , m_NScintiPlates(m_Params->get_int_param(PHG4HcalDefs::scipertwr) * m_Params->get_int_param("n_towers")) , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model")) + , m_doG4Hit(m_Params->get_int_param("saveg4hit")) + , m_tmin(m_Params->get_double_param("tmin")) + , m_tmax(m_Params->get_double_param("tmax")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -90,7 +104,7 @@ PHG4OuterHcalSteppingAction::~PHG4OuterHcalSteppingAction() delete m_MapCorrHist; } -int PHG4OuterHcalSteppingAction::Init() +int PHG4OuterHcalSteppingAction::InitWithNode(PHCompositeNode* topNode) { m_EnableFieldCheckerFlag = m_Params->get_int_param("field_check"); if (m_LightScintModelFlag) @@ -113,18 +127,140 @@ int PHG4OuterHcalSteppingAction::Init() { std::cout << "ERROR: could not find Histogram " << m_Params->get_string_param("MapHistoName") << " in " << m_Params->get_string_param("MapFileName") << std::endl; gSystem->Exit(1); - exit(1); // make code checkers which do not know gSystem->Exit() happy + exit(1); // make code checkers which do not know gSystem->Exit() happy } m_MapCorrHist->SetDirectory(nullptr); // rootism: this needs to be set otherwise histo vanished when closing the file file->Close(); delete file; } + if (!m_doG4Hit) + { + try + { + CreateNodeTree(topNode); + } + catch (std::exception& e) + { + std::cout << e.what() << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + if (Verbosity() > 1) topNode->print(); + } return 0; } +//____________________________________________________________________________.. +bool PHG4OuterHcalSteppingAction::NoHitSteppingAction(const G4Step* aStep) +{ + G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); + G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); + // get volume of the current step + G4VPhysicalVolume* volume = touch->GetVolume(); + + // m_Detector->IsInIHCal(volume) + // returns + // 0 is outside of IHCal + // 1 is inside scintillator + // -1 is steel absorber + + int whichactive = m_Detector->IsInOuterHcal(volume); + + if (!whichactive) + { + return false; + } + if (m_EnableFieldCheckerFlag) + { + FieldChecker(aStep); + } + int layer_id = -1; + int tower_id = -1; + if (whichactive > 0) // scintillator + { + std::pair layer_tower = m_Detector->GetLayerTowerId(volume); + layer_id = layer_tower.first; + tower_id = layer_tower.second; + + // std::cout<<"******** Outer HCal\t"<GetName()<<"\t"<GetPreStepPoint(); + G4StepPoint* postPoint = aStep->GetPostStepPoint(); + // time window cut + double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); + if (time < m_tmin || time > m_tmax) return false; + G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; + const G4Track* aTrack = aStep->GetTrack(); + // we only need visible energy here + double light_yield = eion; + + // correct evis using light map + if (m_LightScintModelFlag) + { + light_yield = GetVisibleEnergyDeposition(aStep); + if (m_MapCorrHist) + { + const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle(); + const G4ThreeVector& worldPosition = postPoint->GetPosition(); + G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition); + float lx = localPosition.x() / cm; + float lz = fabs(localPosition.z() / cm); // reverse the sense for towerid<12 + + // convert to the map bin coordinates: + // map is in 0.5 cm bins + int lcz = (int) (2.0 * lz) + 1; + int lcx = (int) (2.0 * (lx + 42.75)) + 1; + + if ((lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsY()) && + (lcz >= 1) && (lcz <= m_MapCorrHist->GetNbinsX())) + { + light_yield *= m_MapCorrHist->GetBinContent(lcz, lcx); + } + else + { + light_yield = 0.0; + } + } + else + { + // old correction (linear ligh yield dependence along r), never tested + light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y()); + } + } + // find the tower index for this step, tower_id is ieta, layer_id/5 is iphi + unsigned int ieta = tower_id; + unsigned int iphi = (unsigned int) layer_id / 5; + unsigned int tower_key = TowerInfoDefs::encode_hcal(ieta, iphi); + m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield); + // set keep for the track + if (light_yield > 0) + { + if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + { + if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + { + pp->SetKeep(1); // we want to keep the track + } + } + } + + return true; +} + //____________________________________________________________________________.. bool PHG4OuterHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { + if ((!m_doG4Hit) && (!m_IsBlackHoleFlag)) + { + return NoHitSteppingAction(aStep); + } G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle(); G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle(); // get volume of the current step @@ -222,7 +358,7 @@ bool PHG4OuterHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { m_Hit = new PHG4Hitv1(); } - //here we set the entrance values in cm + // here we set the entrance values in cm m_Hit->set_x(0, prePoint->GetPosition().x() / cm); m_Hit->set_y(0, prePoint->GetPosition().y() / cm); m_Hit->set_z(0, prePoint->GetPosition().z() / cm); @@ -245,12 +381,12 @@ bool PHG4OuterHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) // time in ns m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond); - //set the track ID + // set the track ID m_Hit->set_trkid(aTrack->GetTrackID()); m_SaveTrackId = aTrack->GetTrackID(); - //set the initial energy deposit + // set the initial energy deposit m_Hit->set_edep(0); - if (whichactive > 0) // return of IsInOuterHcalDetector, > 0 hit in scintillator, < 0 hit in absorber + if (whichactive > 0) // return of IsInOuterHcalDetector, > 0 hit in scintillator, < 0 hit in absorber { m_Hit->set_scint_id(tower_id); // the slat id m_Hit->set_eion(0); @@ -316,7 +452,7 @@ bool PHG4OuterHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond); - //sum up the energy to get total deposited + // sum up the energy to get total deposited m_Hit->set_edep(m_Hit->get_edep() + edep); if (whichactive > 0) @@ -432,7 +568,7 @@ void PHG4OuterHcalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode) absorbernodename = "G4HIT_ABSORBER_" + m_Detector->GetName(); } - //now look for the map and grab a pointer to it. + // now look for the map and grab a pointer to it. m_Hits = findNode::getClass(topNode, hitnodename); m_AbsorberHits = findNode::getClass(topNode, absorbernodename); @@ -523,3 +659,26 @@ void PHG4OuterHcalSteppingAction::FieldChecker(const G4Step* aStep) << "," << globPosVec[1] / cm << " cm" << std::endl; } } + +void PHG4OuterHcalSteppingAction::CreateNodeTree(PHCompositeNode* topNode) +{ + PHNodeIterator nodeItr(topNode); + PHCompositeNode* dst_node = dynamic_cast( + nodeItr.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cout << "PHComposite node created: DST" << std::endl; + dst_node = new PHCompositeNode("DST"); + topNode->addNode(dst_node); + } + PHNodeIterator dstiter(dst_node); + PHCompositeNode* DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector())); + if (!DetNode) + { + DetNode = new PHCompositeNode(m_Detector->SuperDetector()); + dst_node->addNode(DetNode); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); + PHIODataNode* towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject"); + DetNode->addNode(towerNode); +} diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h index 0c08cc7ba3..86dd407d23 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h @@ -8,6 +8,7 @@ class G4Step; class G4VPhysicalVolume; class PHCompositeNode; +class TowerInfoContainer; class PHG4OuterHcalDetector; class PHParameters; class PHG4Hit; @@ -27,15 +28,17 @@ class PHG4OuterHcalSteppingAction : public PHG4SteppingAction //! stepping action bool UserSteppingAction(const G4Step *, bool) override; - int Init() override; + int InitWithNode(PHCompositeNode *topNode) override; //! reimplemented from base class void SetInterfacePointers(PHCompositeNode *) override; void FieldChecker(const G4Step *); void EnableFieldChecker(const int i = 1) { m_EnableFieldCheckerFlag = i; } + void CreateNodeTree(PHCompositeNode *topNode); private: + bool NoHitSteppingAction(const G4Step *aStep); //! pointer to the detector PHG4OuterHcalDetector *m_Detector = nullptr; @@ -63,6 +66,10 @@ class PHG4OuterHcalSteppingAction : public PHG4SteppingAction int m_IsBlackHoleFlag = -1; int m_NScintiPlates = -1; int m_LightScintModelFlag = 0; + bool m_doG4Hit = true; + double m_tmin = -20.; + double m_tmax = 60.; + TowerInfoContainer *m_CaloInfoContainer = nullptr; }; #endif // G4DETECTORS_PHG4OUTERHCALSTEPPINGACTION_H diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc index fc905acbc3..3d2239a521 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc @@ -7,7 +7,7 @@ #include -#include // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include // for PHG4SteppingAction @@ -98,14 +98,14 @@ int PHG4OuterHcalSubsystem::InitRunSubsystem(PHCompositeNode *topNode) } // create stepping action m_SteppingAction = new PHG4OuterHcalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } else { if (GetParams()->get_int_param("blackhole")) { m_SteppingAction = new PHG4OuterHcalSteppingAction(m_Detector, GetParams()); - m_SteppingAction->Init(); + m_SteppingAction->InitWithNode(topNode); } } @@ -157,6 +157,9 @@ void PHG4OuterHcalSubsystem::SetDefaultParameters() set_default_double_param("light_balance_inner_radius", NAN); set_default_double_param("light_balance_outer_corr", NAN); set_default_double_param("light_balance_outer_radius", NAN); + set_default_double_param("phistart", NAN); + set_default_double_param("scinti_eta_coverage_neg", 1.1); + set_default_double_param("scinti_eta_coverage_pos", 1.1); // some math issue in the code does not subtract the magnet cutout correctly // (maybe some factor of 2 in a G4 volume creation) // The engineering drawing values are: @@ -173,6 +176,8 @@ void PHG4OuterHcalSubsystem::SetDefaultParameters() set_default_double_param("rot_x", 0.); set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); + set_default_double_param("tmin", -20.); + set_default_double_param("tmax", 60.); set_default_double_param("scinti_eta_coverage", 1.1); set_default_double_param("scinti_gap", 0.85); set_default_double_param("scinti_gap_neighbor", 0.1); @@ -190,6 +195,8 @@ void PHG4OuterHcalSubsystem::SetDefaultParameters() set_default_int_param("field_check", 0); set_default_int_param("light_scint_model", 1); set_default_int_param("magnet_cutout_first_scinti", 8); // tile start at 0, drawing tile starts at 1 + set_default_int_param("etabins", 24); + set_default_int_param("saveg4hit", 1); // if ncross is set (and tilt_angle is NAN) tilt_angle is calculated // from number of crossings diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc index af52dec626..c76c39c5ac 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc @@ -173,7 +173,7 @@ void PHG4IHCalSubsystem::SetDefaultParameters() set_default_int_param(PHG4HcalDefs::scipertwr, 4); set_default_int_param(PHG4HcalDefs::n_scinti_tiles, 12); set_default_int_param("etabins", 24); - set_default_int_param("saveg4hit", 0); + set_default_int_param("saveg4hit", 1); set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); From 91718d810eb452a4b46d2f4f3d78ab4ea02180a0 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 7 May 2023 01:57:22 -0400 Subject: [PATCH 351/468] include the correct lib(maybe...) --- simulation/g4simulation/g4detectors/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index d33a0ca26f..13d90a89bf 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -27,7 +27,6 @@ AM_LDFLAGS = \ libg4detectors_io_la_LIBADD = \ -lphool \ - -lcalo_io \ -lphparameter @@ -39,6 +38,7 @@ libg4detectors_la_LIBADD = \ -lgmp \ -lphg4gdml \ -lphool \ + -lcalo_io \ -lSubsysReco pkginclude_HEADERS = \ From 0baead8ca3a975a6ecd9a91bedbe355ac50c6a13 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 7 May 2023 18:06:47 -0400 Subject: [PATCH 352/468] set default stepping to the old one --- simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc index c9d960c42f..922b52fe5c 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc @@ -180,7 +180,7 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_int_param(PHG4HcalDefs::scipertwr, 5); set_default_int_param("n_scinti_tiles", 12); set_default_int_param("etabins", 24); - set_default_int_param("saveg4hit", 0); + set_default_int_param("saveg4hit", 1); set_default_string_param("GDMPath", "DefaultParameters-InvadPath"); std::string defaultmapfilename; From d8e42a47dd4055b695565581ee8151e981523c0f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 May 2023 09:11:39 -0400 Subject: [PATCH 353/468] fix tpc localz --- .../TrackingDiagnostics/TrackResiduals.cc | 22 +++++++++++++++++-- .../TrackingDiagnostics/TrackResiduals.h | 6 ++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index dc3be16c74..674d704604 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -214,7 +213,12 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) //! have cluster and state, fill vectors m_cluslx.push_back(cluster->getLocalX()); - m_cluslz.push_back(cluster->getLocalY()); + float clusz = cluster->getLocalY(); + if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::tpcId) + { + clusz = convertTimeToZ(geometry,ckey, cluster); + } + m_cluslz.push_back(clusz); m_cluselx.push_back(cluster->getRPhiError()); m_cluselz.push_back(cluster->getZError()); m_clusgx.push_back(clusglob.x()); @@ -274,6 +278,20 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +float TrackResiduals::convertTimeToZ(ActsGeometry* geometry, TrkrDefs::cluskey cluster_key, TrkrCluster *cluster) +{ + // must convert local Y from cluster average time of arival to local cluster z position + double drift_velocity = geometry->get_drift_velocity(); + double zdriftlength = cluster->getLocalY() * drift_velocity; + double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is + double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north + unsigned int side = TpcDefs::getSide(cluster_key); + if(side == 0) zloc = -zloc; + float z = zloc; // in cm + + return z; +} + //____________________________________________________________________________.. int TrackResiduals::End(PHCompositeNode*) { diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index b4da68bb76..a9b1b8ffdf 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -10,11 +10,15 @@ #include #include +#include + #include #include #include +class TrkrCluster; class PHCompositeNode; +class ActsGeometry; class TrackResiduals : public SubsysReco { @@ -32,7 +36,7 @@ class TrackResiduals : public SubsysReco private: void clearClusterStateVectors(); void createBranches(); - + float convertTimeToZ(ActsGeometry* geometry, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); std::string m_outfileName = ""; TFile *m_outfile = nullptr; TTree *m_tree = nullptr; From 969517c5db9b1508647c3fd8b7f6efb400d9a408 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 May 2023 13:15:39 -0400 Subject: [PATCH 354/468] add alignment defs class --- .../AlignmentDefs.cc | 116 ++++++++++++++++++ .../TrackerMillepedeAlignment/AlignmentDefs.h | 39 ++++++ .../TrackerMillepedeAlignment/Makefile.am | 2 + 3 files changed, 157 insertions(+) create mode 100644 offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc create mode 100644 offline/packages/TrackerMillepedeAlignment/AlignmentDefs.h diff --git a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc new file mode 100644 index 0000000000..dc42bd2969 --- /dev/null +++ b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc @@ -0,0 +1,116 @@ +#include "AlignmentDefs.h" + + +void AlignmentDefs::getGlobalLabels(Surface surf, int glbl_label[]) +{ + Acts::GeometryIdentifier id = surf->geometryId(); + int label_base = getLabelBase(id); // This value depends on how the surfaces are grouped + for(int i=0; i 23 && layer < 39) + region = 1; + if(layer > 38 && layer < 55) + region = 2; + + return region; +} +int AlignmentDefs::getLabelBase(Acts::GeometryIdentifier id) +{ + + unsigned int volume = id.volume(); + unsigned int acts_layer = id.layer(); + unsigned int layer = base_layer_map.find(volume)->second + acts_layer / 2 -1; + unsigned int sensor = id.sensitive() - 1; // Acts starts at 1 + + int label_base = 1; // Mille wants to start at 1 + + // decide what level of grouping we want + if(layer < 7) + { + if(si_grp == siliconGrp::snsr) + { + // every sensor has a different label + int stave = sensor / nsensors_stave[layer]; + label_base += layer*1000000 + stave*10000 + sensor*10; + return label_base; + } + if(si_grp == siliconGrp::stv) + { + // layer and stave, assign all sensors to the stave number + int stave = sensor / nsensors_stave[layer]; + label_base += layer*1000000 + stave*10000; + return label_base; + } + if(si_grp == siliconGrp::brrl) + // layer only, assign all sensors to sensor 0 + label_base += layer*1000000 + 0; + return label_base; + } + else if(layer > 6 && layer < 55) + { + if(tpc_grp == tpcGrp::htst) + { + // want every hitset (layer, sector, side) to have a separate label + // each group of 12 subsurfaces (sensors) is in a single hitset + int hitset = sensor/12; // 0-11 on side 0, 12-23 on side 1 + label_base += layer*1000000 + hitset*10000; + return label_base; + } + if(tpc_grp == tpcGrp::sctr) + { + // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets + int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 + int sector = (sensor - side *144) / 12; + // for a given layer there are only 12 sectors x 2 sides + // The following gives the sectors in the inner, mid, outer regions unique group labels + int region = getTpcRegion(layer); // inner, mid, outer + label_base += 7*1000000 + (region * 24 + side*12 + sector) *10000; + return label_base; + } + if(tpc_grp == tpcGrp::tp) + { + // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors + label_base += 7*1000000 + 0; + return label_base; + } + } + else + { + if(mms_grp == mmsGrp::tl) + { + // every tile has different label + int tile = sensor; + label_base += layer*1000000 + tile*10000+sensor*10; + return label_base; + } + if(mms_grp == mmsGrp::mm) + { + // assign layer 55 and tile 0 to all + label_base += 55*1000000 + 0; + return label_base; + } + } + + return -1; +} + +void AlignmentDefs::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) +{ + std::cout << " float buffer: " << " residual " << " " << residual(index); + for (int il=0;il + +namespace AlignmentDefs +{ + enum siliconGrp {snsr, stv, brrl}; + enum tpcGrp {htst, sctr, tp}; + enum mmsGrp {tl, mm}; + + //! Map relating Acts::VolumeID to sPHENIX layer + std::map base_layer_map = { {10, 0}, {12,3}, {14,7}, {16,55} }; + int nsensors_stave[7] = {9,9,9,4,4,4,4}; + + int getTpcRegion(int layer); + void getGlobalLabels(Surface surf, int glbl_label[]); + int getLabelBase(Acts::GeometryIdentifier id); + void printBuffers(int index, Acts::Vector2 residual, + Acts::Vector2 clus_sigma, float lcl_derivative[], + float glbl_derivative[], int glbl_label[]); + + std::map m_layerMisalignment; + + void setLayerUncInflation(const unsigned int layer, + const float unc) + { + m_layerMisalignment.insert(std::make_pair(layer, unc)); + } + + static const int NGL = 6; + static const int NLC = 5; + siliconGrp si_grp = siliconGrp::snsr; + tpcGrp tpc_grp = tpcGrp::htst; + mmsGrp mms_grp = mmsGrp::tl; + + +} +#endif diff --git a/offline/packages/TrackerMillepedeAlignment/Makefile.am b/offline/packages/TrackerMillepedeAlignment/Makefile.am index d463b206e1..52da46c171 100644 --- a/offline/packages/TrackerMillepedeAlignment/Makefile.am +++ b/offline/packages/TrackerMillepedeAlignment/Makefile.am @@ -28,6 +28,7 @@ libtrackeralign_la_LIBADD = \ -ltpc_io pkginclude_HEADERS = \ + AlignmentDefs.h \ MakeMilleFiles.h \ Mille.h \ HelicalFitter.h @@ -35,6 +36,7 @@ pkginclude_HEADERS = \ pcmdir = $(libdir) libtrackeralign_la_SOURCES = \ + AlignmentDefs.cc \ MakeMilleFiles.cc \ Mille.cc \ HelicalFitter.cc From a2b901225c71ab556b0b735409863324e863009b Mon Sep 17 00:00:00 2001 From: luisval Date: Mon, 8 May 2023 16:35:58 -0400 Subject: [PATCH 355/468] Initializing angles variables in constructor to pass Jenkins quality test --- simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc index 0504012022..b974e2ed29 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDirectLaser.cc @@ -173,6 +173,8 @@ PHG4TpcDirectLaser::PHG4TpcDirectLaser(const std::string& name) , PHParameterInterface(name) { InitializeParameters(); + theta_p = 0; + phi_p = 0; } //_____________________________________________________________ @@ -254,7 +256,7 @@ int PHG4TpcDirectLaser::InitRun(PHCompositeNode* topNode) std::cout << "PHG4TpcDirectLaser::InitRun - electrons_per_gev " << electrons_per_gev << std::endl; //TFile * infile1 = TFile::Open("theta_phi_laser.root"); - + std::string LASER_ANGLES_ROOTFILE = std::string(getenv("CALIBRATIONROOT")) + "/TPC/DirectLaser/theta_phi_laser.root"; TFile* infile1 = TFile::Open(LASER_ANGLES_ROOTFILE.c_str()); From be4df10fb3430c2326c6aae6df859fb72ace61f6 Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Mon, 8 May 2023 18:48:05 -0400 Subject: [PATCH 356/468] Updated by adding InitRun function for KFParticle_sPHENIX.cc and add an extra protection to validate the magnetic field value at (0,0,0) --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 81 +++++++++++-------- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 20 ++--- 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 3def12a23b..7a52a03eda 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,20 +29,20 @@ #include #include -#include // for obtaining the B field value -#include // for getting the TTree from the file - // +#include // for getting the TTree from the file +#include // for obtaining the B field value + #include // for KFParticle #include // for Fun4AllBase::VERBOSITY... #include // for SubsysReco -#include // for accessing the field map file from the CDB -#include // for toupper -#include // for sqrt -#include // for size_t, exit -#include // for operator<<, endl, basi... -#include // for map -#include // for tie, tuple +#include // for toupper +#include // for sqrt +#include // for size_t, exit +#include // for operator<<, endl, basi... +#include // for map +#include // for tie, tuple +//#include // for accessing the field map file from the CDB class PHCompositeNode; @@ -94,33 +94,47 @@ int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) int returnCode = 0; if (!m_decayDescriptor.empty()) returnCode = parseDecayDescriptor(); - // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + return returnCode; +} + +int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode){ + + assert(topNode); + + std::cout << "Doing InitRun for KFParticle Now" << std::endl; + /* + //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. char *calibrationsroot = getenv("CALIBRATIONROOT"); std::string m_magField = "sphenix3dtrackingmapxyz.root"; - // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); - m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name + // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING",m_magField); //Joe's New Implementation to get the field map file name if (calibrationsroot != nullptr) { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - - TFile *fin = new TFile(m_magField.c_str()); + + TFile * fin = new TFile(m_magField.c_str()); fin->cd(); - TTree *fieldmap = (TTree *) fin->Get("fieldmap"); - TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10); + TTree * fieldmap = (TTree *) fin->Get("fieldmap"); + TH1F * BzHist = new TH1F("BzHist","",100,0,10); - fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0"); + fieldmap->Project("BzHist","bz","x==0 && y==0 && z==0"); - // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction - m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T + //The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction + m_Bz = BzHist->GetMean() * 10; //Factor of 10 to convert the B field unit from kG to T + + if(BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; + if(abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; + + std::cout << "m_Bz = " << m_Bz << std::endl; fieldmap->Delete(); BzHist->Delete(); fin->Close(); - - return returnCode; + */ + return 0; } int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) @@ -145,7 +159,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) if (Verbosity() >= VERBOSITY_SOME) std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - setBz(m_Bz); + createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity); if (!m_has_intermediates_sPHENIX) intermediates = daughters; @@ -262,34 +276,33 @@ int KFParticle_sPHENIX::parseDecayDescriptor() std::string startIntermediate = "{"; std::string endIntermediate = "}"; - // These tracks require a + or - after their name for TDatabasePDG + //These tracks require a + or - after their name for TDatabasePDG std::string specialTracks[] = {"e", "mu", "pi", "K"}; std::string manipulateDecayDescriptor = m_decayDescriptor; - // Remove all white space before we begin + //Remove all white space before we begin size_t pos; while ((pos = manipulateDecayDescriptor.find(" ")) != std::string::npos) manipulateDecayDescriptor.replace(pos, 1, ""); - // Check for charge conjugate requirement + //Check for charge conjugate requirement std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3); - std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) - { c = ::toupper(c); }); + std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) { c = ::toupper(c); }); - // Remove the CC check if needed + //Remove the CC check if needed if (checkForCC == "[]CC") { manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4); getChargeConjugate(true); } - // Find the initial particle + //Find the initial particle size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow); mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint); if (!findParticle(mother)) ddCanBeParsed = false; manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length()); - // Try and find the intermediates + //Try and find the intermediates while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos) { size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos); @@ -302,7 +315,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() else ddCanBeParsed = false; - // Now find the daughters associated to this intermediate + //Now find the daughters associated to this intermediate int nDaughters = 0; intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length()); while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos) @@ -345,7 +358,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() nTracks += nDaughters; } - // Now find any remaining reconstructable tracks from the mother + //Now find any remaining reconstructable tracks from the mother while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos) { daughter = manipulateDecayDescriptor.substr(0, daughterLocator); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 5eeee2d680..c80fdbbd0d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -33,10 +33,10 @@ #include "KFParticle_DST.h" #include "KFParticle_nTuple.h" -// sPHENIX stuff +//sPHENIX stuff #include -// KFParticle stuff +//KFParticle stuff #include #include // for max @@ -58,6 +58,8 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K virtual ~KFParticle_sPHENIX() {} int Init(PHCompositeNode *topNode); + + int InitRun(PHCompositeNode *topNode); int process_event(PHCompositeNode *topNode); @@ -76,7 +78,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K int parseDecayDescriptor(); - /// Parameters for the user to vary + ///Parameters for the user to vary void setDecayDescriptor(const std::string &decayDescriptor) { m_decayDescriptor = decayDescriptor; } @@ -200,9 +202,9 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void allowZeroMassTracks(bool allow) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate) - { - m_extrapolateTracksToSV = extrapolate; - m_extrapolateTracksToSV_nTuple = extrapolate; + { + m_extrapolateTracksToSV = extrapolate; + m_extrapolateTracksToSV_nTuple = extrapolate; } void constrainIntermediateMasses(bool constrain_int_mass) { m_constrain_int_mass = constrain_int_mass; } @@ -290,10 +292,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void getAllPVInfo(bool pvinfo) { m_get_all_PVs = pvinfo; } - /// Use alternate vertex and track fitters + ///Use alternate vertex and track fitters void setVertexMapNodeName(const std::string &vtx_map_node_name) { m_vtx_map_node_name = m_vtx_map_node_name_nTuple = vtx_map_node_name; } - /// Use alternate vertex and track fitters + ///Use alternate vertex and track fitters void setTrackMapNodeName(const std::string &trk_map_node_name) { m_trk_map_node_name = m_trk_map_node_name_nTuple = trk_map_node_name; } private: @@ -308,4 +310,4 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K std::string m_decayDescriptor; }; -#endif // KFPARTICLESPHENIX_KFPARTICLESPHENIX_H +#endif //KFPARTICLESPHENIX_KFPARTICLESPHENIX_H From d1d5cf62671ee9ec0b2705438d9c6797b8da421e Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Mon, 8 May 2023 18:48:20 -0400 Subject: [PATCH 357/468] Updated by adding InitRun function for KFParticle_sPHENIX.cc and add an extra protection to validate the magnetic field value at (0,0,0) --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 33 ++++++++++--------- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 20 +++++------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 7a52a03eda..0b68a100bb 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,8 +29,8 @@ #include #include +#include // for obtaining the B field value #include // for getting the TTree from the file -#include // for obtaining the B field value #include // for KFParticle #include // for Fun4AllBase::VERBOSITY... @@ -97,13 +97,13 @@ int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) return returnCode; } -int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode){ - +int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) +{ assert(topNode); std::cout << "Doing InitRun for KFParticle Now" << std::endl; /* - //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. char *calibrationsroot = getenv("CALIBRATIONROOT"); std::string m_magField = "sphenix3dtrackingmapxyz.root"; // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); @@ -111,14 +111,14 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode){ if (calibrationsroot != nullptr) { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - + TFile * fin = new TFile(m_magField.c_str()); fin->cd(); TTree * fieldmap = (TTree *) fin->Get("fieldmap"); - TH1F * BzHist = new TH1F("BzHist","",100,0,10); + TH1F * BzHist = new TH1F("BzHist","",100,0,10); fieldmap->Project("BzHist","bz","x==0 && y==0 && z==0"); @@ -276,33 +276,34 @@ int KFParticle_sPHENIX::parseDecayDescriptor() std::string startIntermediate = "{"; std::string endIntermediate = "}"; - //These tracks require a + or - after their name for TDatabasePDG + // These tracks require a + or - after their name for TDatabasePDG std::string specialTracks[] = {"e", "mu", "pi", "K"}; std::string manipulateDecayDescriptor = m_decayDescriptor; - //Remove all white space before we begin + // Remove all white space before we begin size_t pos; while ((pos = manipulateDecayDescriptor.find(" ")) != std::string::npos) manipulateDecayDescriptor.replace(pos, 1, ""); - //Check for charge conjugate requirement + // Check for charge conjugate requirement std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3); - std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) { c = ::toupper(c); }); + std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) + { c = ::toupper(c); }); - //Remove the CC check if needed + // Remove the CC check if needed if (checkForCC == "[]CC") { manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4); getChargeConjugate(true); } - //Find the initial particle + // Find the initial particle size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow); mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint); if (!findParticle(mother)) ddCanBeParsed = false; manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length()); - //Try and find the intermediates + // Try and find the intermediates while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos) { size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos); @@ -315,7 +316,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() else ddCanBeParsed = false; - //Now find the daughters associated to this intermediate + // Now find the daughters associated to this intermediate int nDaughters = 0; intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length()); while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos) @@ -358,7 +359,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() nTracks += nDaughters; } - //Now find any remaining reconstructable tracks from the mother + // Now find any remaining reconstructable tracks from the mother while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos) { daughter = manipulateDecayDescriptor.substr(0, daughterLocator); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index c80fdbbd0d..98f3dd52c7 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -33,10 +33,10 @@ #include "KFParticle_DST.h" #include "KFParticle_nTuple.h" -//sPHENIX stuff +// sPHENIX stuff #include -//KFParticle stuff +// KFParticle stuff #include #include // for max @@ -58,7 +58,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K virtual ~KFParticle_sPHENIX() {} int Init(PHCompositeNode *topNode); - + int InitRun(PHCompositeNode *topNode); int process_event(PHCompositeNode *topNode); @@ -78,7 +78,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K int parseDecayDescriptor(); - ///Parameters for the user to vary + /// Parameters for the user to vary void setDecayDescriptor(const std::string &decayDescriptor) { m_decayDescriptor = decayDescriptor; } @@ -202,9 +202,9 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void allowZeroMassTracks(bool allow) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate) - { - m_extrapolateTracksToSV = extrapolate; - m_extrapolateTracksToSV_nTuple = extrapolate; + { + m_extrapolateTracksToSV = extrapolate; + m_extrapolateTracksToSV_nTuple = extrapolate; } void constrainIntermediateMasses(bool constrain_int_mass) { m_constrain_int_mass = constrain_int_mass; } @@ -292,10 +292,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void getAllPVInfo(bool pvinfo) { m_get_all_PVs = pvinfo; } - ///Use alternate vertex and track fitters + /// Use alternate vertex and track fitters void setVertexMapNodeName(const std::string &vtx_map_node_name) { m_vtx_map_node_name = m_vtx_map_node_name_nTuple = vtx_map_node_name; } - ///Use alternate vertex and track fitters + /// Use alternate vertex and track fitters void setTrackMapNodeName(const std::string &trk_map_node_name) { m_trk_map_node_name = m_trk_map_node_name_nTuple = trk_map_node_name; } private: @@ -310,4 +310,4 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K std::string m_decayDescriptor; }; -#endif //KFPARTICLESPHENIX_KFPARTICLESPHENIX_H +#endif // KFPARTICLESPHENIX_KFPARTICLESPHENIX_H From 01007fa0a4f1d78a8b675feef93d9631bd982959 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 8 May 2023 21:27:44 -0400 Subject: [PATCH 358/468] Diagnostic output change. --- offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index f93ab0a4c6..9bbc118829 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -229,7 +229,7 @@ int HelicalFitter::process_event(PHCompositeNode*) unsigned int side = TpcDefs::getSide(cluskey_vec[ivec]); if(is_tpc_sector_fixed(layer, sector, side)) { - std::cout << " layer " << layer << " sector " << sector << "side " << side << std::endl; + //if(i==0) std::cout << " param " << i << " layer " << layer << " sector " << sector << " side " << side << std::endl; glbl_derivativeX[i] = 0; glbl_derivativeY[i] = 0; } From cf4aa09ec3621addc13a09a547956fbe6a31c46e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 May 2023 21:38:46 -0400 Subject: [PATCH 359/468] Rework alignment defs and implement common methods etc. in both modules --- .../AlignmentDefs.cc | 80 +++++++-- .../TrackerMillepedeAlignment/AlignmentDefs.h | 31 ++-- .../HelicalFitter.cc | 157 ++++-------------- .../TrackerMillepedeAlignment/HelicalFitter.h | 35 ++-- .../MakeMilleFiles.cc | 153 ++--------------- .../MakeMilleFiles.h | 46 ++--- 6 files changed, 160 insertions(+), 342 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc index dc42bd2969..016a957b90 100644 --- a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc +++ b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc @@ -1,16 +1,70 @@ #include "AlignmentDefs.h" - -void AlignmentDefs::getGlobalLabels(Surface surf, int glbl_label[]) +void AlignmentDefs::getSiliconGlobalLabels(Surface surf, int glbl_label[], AlignmentDefs::siliconGrp grp) { Acts::GeometryIdentifier id = surf->geometryId(); - int label_base = getLabelBase(id); // This value depends on how the surfaces are grouped - for(int i=0; igeometryId(); + int group = 0; + switch(grp) { + case AlignmentDefs::tpcGrp::htst: + group = 3; + break; + case AlignmentDefs::tpcGrp::sctr: + group = 4; + break; + case AlignmentDefs::tpcGrp::tp: + group = 5; + break; + } + + int label_base = getLabelBase(id, group); + for(int i=0; igeometryId(); + int group = 0; + switch(grp) { + case AlignmentDefs::mmsGrp::tl: + group = 6; + break; + case AlignmentDefs::mmsGrp::mm: + group = 7; + break; + } + + int label_base = getLabelBase(id, group); + for(int i=0; i 6 && layer < 55) { - if(tpc_grp == tpcGrp::htst) + if(group == 3) { // want every hitset (layer, sector, side) to have a separate label // each group of 12 subsurfaces (sensors) is in a single hitset @@ -63,7 +117,7 @@ int AlignmentDefs::getLabelBase(Acts::GeometryIdentifier id) label_base += layer*1000000 + hitset*10000; return label_base; } - if(tpc_grp == tpcGrp::sctr) + if(group == 4) { // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 @@ -74,7 +128,7 @@ int AlignmentDefs::getLabelBase(Acts::GeometryIdentifier id) label_base += 7*1000000 + (region * 24 + side*12 + sector) *10000; return label_base; } - if(tpc_grp == tpcGrp::tp) + if(group == 5) { // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors label_base += 7*1000000 + 0; @@ -83,14 +137,14 @@ int AlignmentDefs::getLabelBase(Acts::GeometryIdentifier id) } else { - if(mms_grp == mmsGrp::tl) + if(group == 6) { // every tile has different label int tile = sensor; label_base += layer*1000000 + tile*10000+sensor*10; return label_base; } - if(mms_grp == mmsGrp::mm) + if(group == 7) { // assign layer 55 and tile 0 to all label_base += 55*1000000 + 0; diff --git a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.h b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.h index d5b0729710..c29b0b9139 100644 --- a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.h +++ b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.h @@ -8,31 +8,26 @@ namespace AlignmentDefs enum siliconGrp {snsr, stv, brrl}; enum tpcGrp {htst, sctr, tp}; enum mmsGrp {tl, mm}; - + + static constexpr int NGL = 6; + static constexpr int NLC = 5; + //! Map relating Acts::VolumeID to sPHENIX layer - std::map base_layer_map = { {10, 0}, {12,3}, {14,7}, {16,55} }; - int nsensors_stave[7] = {9,9,9,4,4,4,4}; + static const std::map base_layer_map = { {10, 0}, {12,3}, {14,7}, {16,55} }; + static constexpr int nsensors_stave[7] = {9,9,9,4,4,4,4}; int getTpcRegion(int layer); - void getGlobalLabels(Surface surf, int glbl_label[]); - int getLabelBase(Acts::GeometryIdentifier id); + void getSiliconGlobalLabels(Surface surf, int glbl_label[], siliconGrp grp); + void getTpcGlobalLabels(Surface surf, int glbl_label[], tpcGrp grp); + void getMMGlobalLabels(Surface surf, int glbl_label[], mmsGrp grp); + + int getLabelBase(Acts::GeometryIdentifier id, int group); + void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); - std::map m_layerMisalignment; - - void setLayerUncInflation(const unsigned int layer, - const float unc) - { - m_layerMisalignment.insert(std::make_pair(layer, unc)); - } - - static const int NGL = 6; - static const int NLC = 5; - siliconGrp si_grp = siliconGrp::snsr; - tpcGrp tpc_grp = tpcGrp::htst; - mmsGrp mms_grp = mmsGrp::tl; + static std::map layerMisalignment; } diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 332042931a..81df362892 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -204,23 +204,34 @@ int HelicalFitter::process_event(PHCompositeNode*) Acts::Vector2 clus_sigma = getClusterError(cluster, cluskey, global); if(isnan(clus_sigma(0)) || isnan(clus_sigma(1))) { continue; } - int glbl_label[NGL]; - getGlobalLabels(surf, glbl_label); // these depend on the sensor grouping + int glbl_label[AlignmentDefs::NGL]; + if(layer < 7) + { + AlignmentDefs::getSiliconGlobalLabels(surf, glbl_label, si_grp); + } + else if (layer < 55) + { + AlignmentDefs::getTpcGlobalLabels(surf, glbl_label, tpc_grp); + } + else if (layer < 57) + { + AlignmentDefs::getMMGlobalLabels(surf, glbl_label, mms_grp); + } // These derivatives are for the local parameters // The angleDerivs dimensions are [alpha/beta/gamma](x/y/z) //std::vector angleDerivs = getDerivativesAlignmentAngles(global, cluskey, cluster); //std::vector translDerivs = getDerivativesAlignmentTranslations(global, cluskey, cluster); - float lcl_derivativeX[NLC]; - float lcl_derivativeY[NLC]; + float lcl_derivativeX[AlignmentDefs::NLC]; + float lcl_derivativeY[AlignmentDefs::NLC]; getLocalDerivativesXY(surf, global, fitpars, lcl_derivativeX, lcl_derivativeY, layer); - float glbl_derivativeX[NGL]; - float glbl_derivativeY[NGL]; + float glbl_derivativeX[AlignmentDefs::NGL]; + float glbl_derivativeY[AlignmentDefs::NGL]; getGlobalDerivativesXY(surf, global, fitpoint, fitpars, glbl_derivativeX, glbl_derivativeY, layer); - for(unsigned int i = 0; i < NGL; ++i) + for(unsigned int i = 0; i < AlignmentDefs::NGL; ++i) { if(is_layer_param_fixed(layer, i) || is_layer_fixed(layer)) { @@ -263,7 +274,15 @@ int HelicalFitter::process_event(PHCompositeNode*) } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters - { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivativeX, glbl_label, residual(0), _error_inflation*clus_sigma(0));} + { + float errinf = 1.0; + if(AlignmentDefs::layerMisalignment.find(layer) != AlignmentDefs::layerMisalignment.end()) + { + errinf = AlignmentDefs::layerMisalignment.find(layer)->second; + } + + _mille->mille(AlignmentDefs::NLC, lcl_derivativeX, AlignmentDefs::NGL, glbl_derivativeX, glbl_label, residual(0), errinf*clus_sigma(0)); + } // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) @@ -294,7 +313,14 @@ int HelicalFitter::process_event(PHCompositeNode*) } if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) - {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivativeY, glbl_label, residual(1), _error_inflation*clus_sigma(1));} + { + float errinf = 1.0; + if(AlignmentDefs::layerMisalignment.find(layer) != AlignmentDefs::layerMisalignment.end()) + { + errinf = AlignmentDefs::layerMisalignment.find(layer)->second; + } + _mille->mille(AlignmentDefs::NLC, lcl_derivativeY, AlignmentDefs::NGL, glbl_derivativeY, glbl_label, residual(1), errinf*clus_sigma(1)); + } } // close out this track @@ -514,109 +540,8 @@ void HelicalFitter::makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, shor if(_dcc_fluctuation) { global = _distortionCorrection.get_corrected_position( global, _dcc_fluctuation ); } } -void HelicalFitter::getGlobalLabels(Surface surf, int glbl_label[]) -{ - // identify the global alignment parameters for this surface - Acts::GeometryIdentifier id = surf->geometryId(); - int label_base = getLabelBase(id); // This value depends on how the surfaces are grouped - for(int i=0;i 1) - { std::cout << " glbl " << i << " label " << glbl_label[i] << " "; } - } - if(Verbosity() > 1) { std::cout << std::endl; } -} - -int HelicalFitter::getTpcRegion(int layer) -{ - int region = 0; - if(layer > 23 && layer < 39) - region = 1; - if(layer > 38 && layer < 55) - region = 2; - - return region; -} - -int HelicalFitter::getLabelBase(Acts::GeometryIdentifier id) -{ - unsigned int volume = id.volume(); - unsigned int acts_layer = id.layer(); - unsigned int layer = base_layer_map.find(volume)->second + acts_layer / 2 -1; - unsigned int sensor = id.sensitive() - 1; // Acts starts at 1 - - int label_base = 1; // Mille wants to start at 1 - // decide what level of grouping we want - if(layer < 7) - { - if(si_grp == siliconGrp::snsr) - { - // every sensor has a different label - int stave = sensor / nsensors_stave[layer]; - label_base += layer*1000000 + stave*10000 + sensor*10; - return label_base; - } - if(si_grp == siliconGrp::stv) - { - // layer and stave, assign all sensors to the stave number - int stave = sensor / nsensors_stave[layer]; - label_base += layer*1000000 + stave*10000; - return label_base; - } - if(si_grp == siliconGrp::brrl) - // layer only, assign all sensors to sensor 0 - label_base += layer*1000000 + 0; - return label_base; - } - else if(layer > 6 && layer < 55) - { - if(tpc_grp == tpcGrp::htst) - { - // want every hitset (layer, sector, side) to have a separate label - // each group of 12 subsurfaces (sensors) is in a single hitset - int hitset = sensor/12; // 0-11 on side 0, 12-23 on side 1 - label_base += layer*1000000 + hitset*10000; - return label_base; - } - if(tpc_grp == tpcGrp::sctr) - { - // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets - int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 - int sector = (sensor - side *144) / 12; - // for a given layer there are only 12 sectors x 2 sides - // The following gives the sectors in the inner, mid, outer regions unique group labels - int region = getTpcRegion(layer); // inner, mid, outer - label_base += 7*1000000 + (region * 24 + side*12 + sector) *10000; - return label_base; - } - if(tpc_grp == tpcGrp::tp) - { - // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors - label_base += 7*1000000 + 0; - return label_base; - } - } - else - { - if(mms_grp == mmsGrp::tl) - { - // every tile has different label - int tile = sensor; - label_base += layer*1000000 + tile*10000+sensor*10; - return label_base; - } - if(mms_grp == mmsGrp::mm) - { - // assign layer 55 and tile 0 to all - label_base += 55*1000000 + 0; - return label_base; - } - } - return -1; -} // this method to be replaced by calls to TrackFitUtils void HelicalFitter::getTrackletClusters(TrackSeed *tracklet, std::vector& global_vec, std::vector& cluskey_vec) @@ -828,18 +753,6 @@ void HelicalFitter::get_projectionXY(Surface surf, std::pair& fitpars, std::vector& global_vec, std::vector& cluskey_vec) { diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index f42cbd81f1..9370ba0d86 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -3,6 +3,8 @@ #ifndef HELICALFITTER_H #define HELICALFITTER_H +#include "AlignmentDefs.h" + #include #include #include @@ -24,10 +26,6 @@ class TpcDistortionCorrectionContainer; class Mille; class SvtxTrackSeed; -enum siliconGrp {snsr, stv, brrl}; -enum tpcGrp {htst, sctr, tp}; -enum mmsGrp {tl, mm}; - class HelicalFitter : public SubsysReco, public PHParameterInterface { public: @@ -57,16 +55,19 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface void set_datafile_name(const std::string& file) { data_outfilename = file;} void set_steeringfile_name(const std::string& file) { steering_outfilename = file;} - void set_silicon_grouping(int group) {si_grp = (siliconGrp) group;} - void set_tpc_grouping(int group) {tpc_grp = (tpcGrp) group;} - void set_mms_grouping(int group) {mms_grp = (mmsGrp) group;} + void set_silicon_grouping(int group) {si_grp = (AlignmentDefs::siliconGrp) group;} + void set_tpc_grouping(int group) {tpc_grp = (AlignmentDefs::tpcGrp) group;} + void set_mms_grouping(int group) {mms_grp = (AlignmentDefs::mmsGrp) group;} void set_test_output(bool test) {test_output = test;} void set_layer_fixed(unsigned int layer); void set_layer_param_fixed(unsigned int layer, unsigned int param); void set_cluster_version(unsigned int v) { _cluster_version = v; } void set_fitted_subsystems(bool si, bool tpc, bool full) { fitsilicon = si; fittpc = tpc; fitfulltrack = full; } - void set_error_inflation_factor(float factor) {_error_inflation = factor;} - + void set_error_inflation_factor(unsigned int layer, float factor) + { + AlignmentDefs::layerMisalignment.insert(std::make_pair(layer,factor)); + } + // utility functions for analysis modules std::vector fitClusters(std::vector& global_vec, std::vector cluskey_vec); void getTrackletClusters(TrackSeed *_track, std::vector& global_vec, std::vector& cluskey_vec); @@ -89,16 +90,14 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface std::pair get_helix_tangent(const std::vector& fitpars, Acts::Vector3 global); Acts::Vector3 get_helix_surface_intersection(Surface surf, std::vector& fitpars, Acts::Vector3 global); - int getLabelBase(Acts::GeometryIdentifier id); float convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); void makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global); int getTpcRegion(int layer); Acts::Vector2 getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global); - void getGlobalLabels(Surface surf, int glbl_label[]); - void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); + bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); @@ -122,13 +121,10 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface std::set> fixed_layer_params; // set default groups to lowest level - siliconGrp si_grp = siliconGrp::snsr; - tpcGrp tpc_grp = tpcGrp::htst; - mmsGrp mms_grp = mmsGrp::tl; - - int nsensors_stave[7] = {9,9,9,4,4,4,4}; + AlignmentDefs::siliconGrp si_grp = AlignmentDefs::siliconGrp::snsr; + AlignmentDefs::tpcGrp tpc_grp = AlignmentDefs::tpcGrp::htst; + AlignmentDefs::mmsGrp mms_grp = AlignmentDefs::mmsGrp::tl; - std::map base_layer_map = { {10, 0}, {12,3}, {14,7}, {16,55} }; /// tpc distortion correction utility class TpcDistortionCorrection _distortionCorrection; @@ -142,9 +138,6 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface std::string data_outfilename = ("mille_helical_output_data_file.bin"); std::string steering_outfilename = ("steer_helical.txt"); - static const int NLC = 5; - static const int NGL = 6; - bool fitsilicon = true; bool fittpc = false; bool fitfulltrack = false; diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index bfdc030dfa..b68c8924a3 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -194,99 +194,6 @@ Acts::Vector3 MakeMilleFiles::getPCALinePoint(Acts::Vector3 global, SvtxTrackSta return pca; } -int MakeMilleFiles::getTpcRegion(int layer) -{ - int region = 0; - if (layer > 23 && layer < 39) - region = 1; - if (layer > 38 && layer < 55) - region = 2; - - return region; -} - -int MakeMilleFiles::getLabelBase(Acts::GeometryIdentifier id) -{ - unsigned int volume = id.volume(); - unsigned int acts_layer = id.layer(); - unsigned int layer = base_layer_map.find(volume)->second + acts_layer / 2 - 1; - unsigned int sensor = id.sensitive() - 1; // Acts starts at 1 - - int label_base = 1; // Mille wants to start at 1 - - // decide what level of grouping we want - if (layer < 7) - { - if (si_group == siliconGroup::sensor) - { - // every sensor has a different label - int stave = sensor / nsensors_stave[layer]; - label_base += layer * 1000000 + stave * 10000 + sensor * 10; - return label_base; - } - if (si_group == siliconGroup::stave) - { - // layer and stave, assign all sensors to the stave number - int stave = sensor / nsensors_stave[layer]; - label_base += layer * 1000000 + stave * 10000; - return label_base; - } - if (si_group == siliconGroup::barrel) - { - // layer only, assign all sensors to sensor 0 - label_base += layer * 1000000 + 0; - - return label_base; - } - } - else if (layer > 6 && layer < 55) - { - if (tpc_group == tpcGroup::hitset) - { - // want every hitset (layer, sector, side) to have a separate label - // each group of 12 subsurfaces (sensors) is in a single hitset - int hitset = sensor / 12; // hitsets 0-11 on side 0, 12-23 on side 1 - label_base += layer * 1000000 + hitset * 10000; - return label_base; - } - if (tpc_group == tpcGroup::sector) - { - // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets - int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 - int sector = (sensor - side * 144) / 12; - // for a given layer there are only 12 sectors x 2 sides - // The following gives the sectors in the inner, mid, outer regions unique group labels - int region = getTpcRegion(layer); // inner, mid, outer - label_base += 7 * 1000000 + (region * 24 + side * 12 + sector) * 10000; - // std::cout << " layer " << layer << " sensor " << sensor << " region " << region << " side " << side << " sector " << sector << " label_base " << label_base << std::endl; - return label_base; - } - if (tpc_group == tpcGroup::tpc) - { - // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors - label_base += 7 * 1000000 + 0; - return label_base; - } - } - else - { - if (mms_group == mmsGroup::tile) - { - // every tile has different label - int tile = sensor; - label_base += layer * 1000000 + tile * 10000 + sensor * 10; - return label_base; - } - if (mms_group == mmsGroup::mms) - { - // assign layer 55 and tile 0 to all - label_base += 55 * 1000000 + 0; - return label_base; - } - } - - return -1; -} void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec statevec) { @@ -341,18 +248,21 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve continue; } - Acts::GeometryIdentifier id = _tGeometry->maps().getSurface(ckey, cluster)->geometryId(); - int label_base = getLabelBase(id); // This value depends on how the surfaces are grouped - + auto surf = _tGeometry->maps().getSurface(ckey, cluster); + int glbl_label[SvtxAlignmentState::NGL]; - for (int i = 0; i < SvtxAlignmentState::NGL; ++i) - { - glbl_label[i] = label_base + i; - if (Verbosity() > 1) + if(layer < 7) { - std::cout << " glbl " << i << " label " << glbl_label[i] << " "; + AlignmentDefs::getSiliconGlobalLabels(surf, glbl_label,si_group); } + else if( layer < 55) + { + AlignmentDefs::getTpcGlobalLabels(surf, glbl_label, tpc_group); } + else if (layer < 57) + { + AlignmentDefs::getMMGlobalLabels(surf, glbl_label, mms_group); + } if (Verbosity() > 1) { @@ -366,7 +276,6 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve float glbl_derivative[SvtxAlignmentState::NGL]; for (int j = 0; j < SvtxAlignmentState::NGL; ++j) { - /// swap the order to match what is expected from the workflow glbl_derivative[j] = state->get_global_derivative_matrix()(i, j); if (is_layer_fixed(layer) || is_layer_param_fixed(layer, j)) @@ -405,10 +314,14 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve if (Verbosity() > 3) { std::cout << "ckey " << ckey << " and layer " << layer << " buffers:" << std::endl; - printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); + AlignmentDefs::printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); } - - _mille->mille(SvtxAlignmentState::NLOC, lcl_derivative, SvtxAlignmentState::NGL, glbl_derivative, glbl_label, residual(i), clus_sigma(i)); + float errinf = 1.0; + if(AlignmentDefs::layerMisalignment.find(layer) != AlignmentDefs::layerMisalignment.end()) + { + errinf = AlignmentDefs::layerMisalignment.find(layer)->second; + } + _mille->mille(SvtxAlignmentState::NLOC, lcl_derivative, SvtxAlignmentState::NGL, glbl_derivative, glbl_label, residual(i), errinf*clus_sigma(i)); } } } @@ -416,36 +329,6 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve return; } -void MakeMilleFiles::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) -{ - std::cout << " float buffer: " - << " residual " - << " " << residual(index); - for (int il = 0; il < SvtxAlignmentState::NLOC; ++il) - { - if (lcl_derivative[il] != 0) std::cout << " lcl_deriv[" << il << "] " << lcl_derivative[il] << " "; - } - std::cout << " sigma " - << " " << clus_sigma(index) << " "; - for (int ig = 0; ig < SvtxAlignmentState::NGL; ++ig) - { - if (glbl_derivative[ig] != 0) std::cout << " glbl_deriv[" << ig << "] " << glbl_derivative[ig] << " "; - } - std::cout << " int buffer: " - << " 0 " - << " "; - for (int il = 0; il < SvtxAlignmentState::NLOC; ++il) - { - if (lcl_derivative[il] != 0) std::cout << " lcl_label[" << il << "] " << il << " "; - } - std::cout << " 0 " - << " "; - for (int ig = 0; ig < SvtxAlignmentState::NGL; ++ig) - { - if (glbl_derivative[ig] != 0) std::cout << " glbl_label[" << ig << "] " << glbl_label[ig] << " "; - } - std::cout << " end of meas " << std::endl; -} bool MakeMilleFiles::is_layer_fixed(unsigned int layer) { bool ret = false; diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h index 46dd757372..fcd3166a61 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h @@ -10,6 +10,8 @@ #ifndef MAKEMILLEFILES_H #define MAKEMILLEFILES_H +#include "AlignmentDefs.h" + #include #include @@ -32,24 +34,6 @@ class Mille; using Trajectory = ActsExamples::Trajectories; -enum siliconGroup -{ - sensor, - stave, - barrel -}; -enum tpcGroup -{ - hitset, - sector, - tpc -}; -enum mmsGroup -{ - tile, - mms -}; - class MakeMilleFiles : public SubsysReco { public: @@ -63,13 +47,17 @@ class MakeMilleFiles : public SubsysReco void set_datafile_name(const std::string& file) { data_outfilename = file; } void set_steeringfile_name(const std::string& file) { steering_outfilename = file; } - void set_silicon_grouping(int group) { si_group = (siliconGroup) group; } - void set_tpc_grouping(int group) { tpc_group = (tpcGroup) group; } - void set_mms_grouping(int group) { mms_group = (mmsGroup) group; } + void set_silicon_grouping(int group) { si_group = (AlignmentDefs::siliconGrp) group; } + void set_tpc_grouping(int group) { tpc_group = (AlignmentDefs::tpcGrp) group; } + void set_mms_grouping(int group) { mms_group = (AlignmentDefs::mmsGrp) group; } void set_layer_fixed(unsigned int layer); void set_layer_param_fixed(unsigned int layer, unsigned int param); void set_cluster_version(unsigned int v) { _cluster_version = v; } void set_layers_fixed(unsigned int minlayer, unsigned int maxlayer); + void set_error_inflation_factor(unsigned int layer, float factor) + { + AlignmentDefs::layerMisalignment.insert(std::make_pair(layer,factor)); + } private: Mille* _mille; @@ -81,13 +69,9 @@ class MakeMilleFiles : public SubsysReco TrkrCluster* cluster, Surface surface, int crossing); - int getLabelBase(Acts::GeometryIdentifier id); - int getTpcRegion(int layer); - bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); - void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); - + void addTrackToMilleFile(SvtxAlignmentStateMap::StateVec statevec); std::map derivativeGL; @@ -100,17 +84,13 @@ class MakeMilleFiles : public SubsysReco bool m_useAnalytic = true; // set default groups to lowest level - siliconGroup si_group = siliconGroup::sensor; - tpcGroup tpc_group = tpcGroup::hitset; - mmsGroup mms_group = mmsGroup::tile; - - int nsensors_stave[7] = {9, 9, 9, 4, 4, 4, 4}; + AlignmentDefs::siliconGrp si_group = AlignmentDefs::siliconGrp::snsr; + AlignmentDefs::tpcGrp tpc_group = AlignmentDefs::tpcGrp::htst; + AlignmentDefs::mmsGrp mms_group = AlignmentDefs::mmsGrp::tl; std::set fixed_layers; std::set> fixed_layer_params; - std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; - SvtxTrackMap* _track_map{nullptr}; SvtxAlignmentStateMap* _state_map{nullptr}; ActsGeometry* _tGeometry{nullptr}; From 9636fd783a9031de90d6890b53dab661f83eacab Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 8 May 2023 22:43:36 -0400 Subject: [PATCH 360/468] Add different error inflation factors for the four different subsystems. --- .../HelicalFitter.cc | 21 ++++++++++++++----- .../TrackerMillepedeAlignment/HelicalFitter.h | 12 ++++++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index 9bbc118829..f09d923817 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -204,6 +204,16 @@ int HelicalFitter::process_event(PHCompositeNode*) Acts::Vector2 clus_sigma = getClusterError(cluster, cluskey, global); if(isnan(clus_sigma(0)) || isnan(clus_sigma(1))) { continue; } + float inflation_factor = 1; + if(trkrid == TrkrDefs::mvtxId) + inflation_factor = _error_inflation[0]; + else if(trkrid == TrkrDefs::inttId) + inflation_factor = _error_inflation[1]; + else if(trkrid == TrkrDefs::tpcId) + inflation_factor = _error_inflation[2]; + else + inflation_factor = _error_inflation[3]; + int glbl_label[NGL]; getGlobalLabels(surf, glbl_label); // these depend on the sensor grouping @@ -247,7 +257,7 @@ int HelicalFitter::process_event(PHCompositeNode*) { // radius = fitpars[0], X0 = fitpars[1], Y0 = fitpars[2], zslope = fitpars[3], Z0 = fitpars[4] std::cout << "Local residualsX: layer " << layer << " phi " << phi * 180 / M_PI << " beta " << beta * 180.90 / M_PI - << " dxloc " << residual(0) << " error " << clus_sigma(0) + << " dxloc " << residual(0) << " error " << clus_sigma(0) << " inflation_factor " << inflation_factor << " xloc " << xloc << " fitxloc " << fitpoint_local(0) << " zglob " << global(2) << " fitzglob " << fitpoint(2) << " xglob " << global(0) << " fitxglob " << fitpoint(0) @@ -270,7 +280,7 @@ int HelicalFitter::process_event(PHCompositeNode*) } if( !isnan(residual(0)) && clus_sigma(0) < 1.0) // discards crazy clusters - { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivativeX, glbl_label, residual(0), _error_inflation*clus_sigma(0));} + { _mille->mille(NLC, lcl_derivativeX, NGL, glbl_derivativeX, glbl_label, residual(0), inflation_factor*clus_sigma(0));} // provides output that can be grep'ed to make plots of input to mille if(Verbosity() > 1) @@ -278,7 +288,7 @@ int HelicalFitter::process_event(PHCompositeNode*) if(layer < 7) { std::cout << "Local residualsY: layer " << layer << " phi " << phi * 180 / M_PI << " beta " << beta * 180.90 / M_PI - << " dzloc " << residual(1) << " error " << clus_sigma(1) + << " dzloc " << residual(1) << " error " << clus_sigma(1) << " inflation_factor " << inflation_factor << " zloc " << zloc << " fitzloc " << fitpoint_local(1) << " zglob " << global(2) << " fitzglob " << fitpoint(2) << " xglob " << global(0) << " fitxglob " << fitpoint(0) @@ -302,7 +312,7 @@ int HelicalFitter::process_event(PHCompositeNode*) //if(!isnan(residual(1)) && clus_sigma(1) < 1.0 && trkrid != TrkrDefs::inttId) if(!isnan(residual(1)) && clus_sigma(1) < 1.0) - {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivativeY, glbl_label, residual(1), _error_inflation*clus_sigma(1));} + {_mille->mille(NLC, lcl_derivativeY, NGL, glbl_derivativeY, glbl_label, residual(1), inflation_factor*clus_sigma(1));} } // close out this track @@ -835,7 +845,7 @@ void HelicalFitter::get_projectionXY(Surface surf, std::pair& fitpars, std::vector& global_vec, std::vector& cluskey_vec) { diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index 62a2618bd1..7341b0f81e 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -66,7 +66,13 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface void set_layer_param_fixed(unsigned int layer, unsigned int param); void set_cluster_version(unsigned int v) { _cluster_version = v; } void set_fitted_subsystems(bool si, bool tpc, bool full) { fitsilicon = si; fittpc = tpc; fitfulltrack = full; } - void set_error_inflation_factor(float factor) {_error_inflation = factor;} + void set_error_inflation_factor(float mvtx, float intt, float tpc, float tpot) + { + _error_inflation[0] = mvtx; + _error_inflation[1] = intt; + _error_inflation[2] = tpc; + _error_inflation[3] = tpot; + } // utility functions for analysis modules std::vector fitClusters(std::vector& global_vec, std::vector cluskey_vec); @@ -99,7 +105,7 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface Acts::Vector2 getClusterError(TrkrCluster *cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global); void getGlobalLabels(Surface surf, int glbl_label[]); - void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); + // void printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]); bool is_tpc_sector_fixed(unsigned int layer, unsigned int sector, unsigned int side); bool is_layer_fixed(unsigned int layer); bool is_layer_param_fixed(unsigned int layer, unsigned int param); @@ -153,7 +159,7 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface bool fitfulltrack = false; float dca_cut = 0.1; // 1 mm - float _error_inflation = 1.0; + float _error_inflation[4] = {1,1,1,1}; std::string _field; int _fieldDir = -1; From 16a0f90524346e798d970bc139360ae277322b1d Mon Sep 17 00:00:00 2001 From: Shuonli Date: Tue, 9 May 2023 00:11:18 -0400 Subject: [PATCH 361/468] include the delta t cut --- .../g4detectors/PHG4InnerHcalSteppingAction.cc | 7 +++++-- .../g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h | 1 + .../g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc | 1 + .../g4detectors/PHG4OuterHcalSteppingAction.cc | 7 +++++-- .../g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h | 1 + .../g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc | 1 + simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc | 7 +++++-- simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h | 1 + simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc | 1 + simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc | 7 +++++-- simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h | 1 + simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc | 1 + 12 files changed, 28 insertions(+), 8 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc index 5a1d1e1924..8a7af50a0f 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.cc @@ -72,6 +72,7 @@ PHG4InnerHcalSteppingAction::PHG4InnerHcalSteppingAction(PHG4InnerHcalDetector* , m_doG4Hit(m_Params->get_int_param("saveg4hit")) , m_tmin(m_Params->get_double_param("tmin")) , m_tmax(m_Params->get_double_param("tmax")) + , m_dt(m_Params->get_double_param("dt")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -177,8 +178,10 @@ bool PHG4InnerHcalSteppingAction::NoHitSteppingAction(const G4Step* aStep) G4StepPoint* prePoint = aStep->GetPreStepPoint(); G4StepPoint* postPoint = aStep->GetPostStepPoint(); // time window cut - double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); - if (time < m_tmin || time > m_tmax) return false; + double pretime = prePoint->GetGlobalTime() / nanosecond; + double posttime = postPoint->GetGlobalTime() / nanosecond; + if (posttime < m_tmin || pretime > m_tmax) return false; + if ((posttime - pretime) > m_dt) return false; G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; const G4Track* aTrack = aStep->GetTrack(); // we only need visible energy here diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h index 6defe9ff8f..1e0e61f43f 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSteppingAction.h @@ -64,6 +64,7 @@ class PHG4InnerHcalSteppingAction : public PHG4SteppingAction bool m_doG4Hit = true; double m_tmin = -20.; double m_tmax = 60.; + double m_dt = 100.; TowerInfoContainer *m_CaloInfoContainer = nullptr; }; diff --git a/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc index b085bc9578..8a9e749da0 100644 --- a/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4InnerHcalSubsystem.cc @@ -171,6 +171,7 @@ void PHG4InnerHcalSubsystem::SetDefaultParameters() set_default_double_param("scinti_outer_gap", 1.22 * (5.0 / 4.0)); set_default_double_param("tmin", -20.); set_default_double_param("tmax", 60.); + set_default_double_param("dt", 100.); // some math issue in the code subtracts 0.4mm so the scintillator // does not end at 133.09 as per drawing but at 133.05 // adding 0.4mm compensates for this (so 133.13 gives the desired 133.09 diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc index 03115d7129..6fc45716ef 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.cc @@ -86,6 +86,7 @@ PHG4OuterHcalSteppingAction::PHG4OuterHcalSteppingAction(PHG4OuterHcalDetector* , m_doG4Hit(m_Params->get_int_param("saveg4hit")) , m_tmin(m_Params->get_double_param("tmin")) , m_tmax(m_Params->get_double_param("tmax")) + , m_dt(m_Params->get_double_param("dt")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -194,8 +195,10 @@ bool PHG4OuterHcalSteppingAction::NoHitSteppingAction(const G4Step* aStep) G4StepPoint* prePoint = aStep->GetPreStepPoint(); G4StepPoint* postPoint = aStep->GetPostStepPoint(); // time window cut - double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); - if (time < m_tmin || time > m_tmax) return false; + double pretime = prePoint->GetGlobalTime() / nanosecond; + double posttime = postPoint->GetGlobalTime() / nanosecond; + if (posttime < m_tmin || pretime > m_tmax) return false; + if ((posttime - pretime) > m_dt) return false; G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; const G4Track* aTrack = aStep->GetTrack(); // we only need visible energy here diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h index 86dd407d23..e93cd8b333 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSteppingAction.h @@ -69,6 +69,7 @@ class PHG4OuterHcalSteppingAction : public PHG4SteppingAction bool m_doG4Hit = true; double m_tmin = -20.; double m_tmax = 60.; + double m_dt = 100.; TowerInfoContainer *m_CaloInfoContainer = nullptr; }; diff --git a/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc index 3d2239a521..43f472a040 100644 --- a/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4OuterHcalSubsystem.cc @@ -178,6 +178,7 @@ void PHG4OuterHcalSubsystem::SetDefaultParameters() set_default_double_param("rot_z", 0.); set_default_double_param("tmin", -20.); set_default_double_param("tmax", 60.); + set_default_double_param("dt", 100.); set_default_double_param("scinti_eta_coverage", 1.1); set_default_double_param("scinti_gap", 0.85); set_default_double_param("scinti_gap_neighbor", 0.1); diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc index 8c22f61c01..8a2c998c17 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.cc @@ -70,6 +70,7 @@ PHG4IHCalSteppingAction::PHG4IHCalSteppingAction(PHG4IHCalDetector* detector, co , m_doG4Hit(m_Params->get_int_param("saveg4hit")) , m_tmin(m_Params->get_double_param("tmin")) , m_tmax(m_Params->get_double_param("tmax")) + , m_dt(m_Params->get_double_param("dt")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -175,8 +176,10 @@ bool PHG4IHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) G4StepPoint* prePoint = aStep->GetPreStepPoint(); G4StepPoint* postPoint = aStep->GetPostStepPoint(); // time window cut - double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); - if (time < m_tmin || time > m_tmax) return false; + double pretime = prePoint->GetGlobalTime() / nanosecond; + double posttime = postPoint->GetGlobalTime() / nanosecond; + if (posttime < m_tmin || pretime > m_tmax) return false; + if ((posttime - pretime) > m_dt) return false; G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; const G4Track* aTrack = aStep->GetTrack(); // we only need visible energy here diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h index 7918a12c55..79620cb6a5 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h @@ -68,6 +68,7 @@ class PHG4IHCalSteppingAction : public PHG4SteppingAction bool m_doG4Hit = true; double m_tmin = -20.; double m_tmax = 60.; + double m_dt = 100. std::string m_AbsorberNodeName; std::string m_HitNodeName; diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc index c76c39c5ac..67a4a7c30b 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSubsystem.cc @@ -166,6 +166,7 @@ void PHG4IHCalSubsystem::SetDefaultParameters() set_default_double_param("Birk_const", 0.07943); set_default_double_param("tmin", -20.); set_default_double_param("tmax", 60.); + set_default_double_param("dt", 100.); set_default_int_param("light_scint_model", 1); diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc index ca3c663533..57a1b5b613 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.cc @@ -86,6 +86,7 @@ PHG4OHCalSteppingAction::PHG4OHCalSteppingAction(PHG4OHCalDetector* detector, co , m_doG4Hit(m_Params->get_int_param("saveg4hit")) , m_tmin(m_Params->get_double_param("tmin")) , m_tmax(m_Params->get_double_param("tmax")) + , m_dt(m_Params->get_double_param("dt")) { SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm, m_Params->get_double_param("light_balance_inner_corr"), @@ -221,8 +222,10 @@ bool PHG4OHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep) G4StepPoint* prePoint = aStep->GetPreStepPoint(); G4StepPoint* postPoint = aStep->GetPostStepPoint(); // time window cut - double time = 0.5 * (prePoint->GetGlobalTime() / nanosecond + postPoint->GetGlobalTime() / nanosecond); - if (time < m_tmin || time > m_tmax) return false; + double pretime = prePoint->GetGlobalTime() / nanosecond; + double posttime = postPoint->GetGlobalTime() / nanosecond; + if (posttime < m_tmin || pretime > m_tmax) return false; + if ((posttime - pretime) > m_dt) return false; G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; const G4Track* aTrack = aStep->GetTrack(); // we only need visible energy here diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h index 0c5079c9d9..0433f8fd83 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSteppingAction.h @@ -73,6 +73,7 @@ class PHG4OHCalSteppingAction : public PHG4SteppingAction bool m_doG4Hit = true; double m_tmin = -20.; double m_tmax = 60.; + double m_dt = 100.; std::string m_AbsorberNodeName; std::string m_HitNodeName; diff --git a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc index 922b52fe5c..d08147a84a 100644 --- a/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc +++ b/simulation/g4simulation/g4ohcal/PHG4OHCalSubsystem.cc @@ -173,6 +173,7 @@ void PHG4OHCalSubsystem::SetDefaultParameters() set_default_double_param("Birk_const", 0.07943); set_default_double_param("tmin", -20.); set_default_double_param("tmax", 60.); + set_default_double_param("dt", 100.); set_default_int_param("field_check", 0); set_default_int_param("light_scint_model", 1); From 41649ccd51bbbdb2c27a24a258f883088d2dedc0 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 9 May 2023 08:43:35 -0400 Subject: [PATCH 362/468] trigger jenkins From b32f0eeca30beabaff4aa1c27f3c088a9b597070 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 9 May 2023 09:59:37 -0400 Subject: [PATCH 363/468] Check for track map instead of aborting if it doesn't exist --- .../packages/globalvertex/GlobalVertexReco.cc | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index db0b4e6045..893c89b316 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -69,11 +69,6 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) SvtxVertexMap *svtxmap = findNode::getClass(topNode, "SvtxVertexMap"); BbcVertexMap *bbcmap = findNode::getClass(topNode, "BbcVertexMap"); SvtxTrackMap *trackmap = findNode::getClass(topNode, "SvtxTrackMap"); - if (!trackmap) - { - std::cout << PHWHERE << "No track map, can't continue." << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } // we will make 3 different kinds of global vertexes // (1) SVTX+BBC vertexes - we match SVTX vertex to the nearest BBC vertex within 3 sigma in zvertex @@ -157,13 +152,15 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) globalmap->insert(vertex); //! Reset track ids to the new vertex object - for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); - ++iter) + if (trackmap) { - auto track = trackmap->find(*iter)->second; - track->set_vertex_id(vertex->get_id()); + for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } } - global_vertex_id++; if (Verbosity() > 1) @@ -218,13 +215,15 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) used_svtx_vtxids.insert(svtx->get_id()); //! Reset track ids to the new vertex object - for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); - ++iter) + if (trackmap) { - auto track = trackmap->find(*iter)->second; - track->set_vertex_id(vertex->get_id()); + for (auto iter = svtx->begin_tracks(); iter != svtx->end_tracks(); + ++iter) + { + auto track = trackmap->find(*iter)->second; + track->set_vertex_id(vertex->get_id()); + } } - globalmap->insert(vertex); if (Verbosity() > 1) @@ -295,33 +294,35 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } /// Associate any tracks that were not assigned a track-vertex - - for (const auto &[tkey, track] : *trackmap) + if (trackmap) { - //! Check that the vertex hasn't already been assigned - auto trackvtxid = track->get_vertex_id(); - if (globalmap->find(trackvtxid) != globalmap->end()) + for (const auto &[tkey, track] : *trackmap) { - continue; - } + //! Check that the vertex hasn't already been assigned + auto trackvtxid = track->get_vertex_id(); + if (globalmap->find(trackvtxid) != globalmap->end()) + { + continue; + } - float maxdz = std::numeric_limits::max(); - unsigned int vtxid = std::numeric_limits::max(); + float maxdz = std::numeric_limits::max(); + unsigned int vtxid = std::numeric_limits::max(); - for (const auto &[vkey, vertex] : *globalmap) - { - float dz = track->get_z() - vertex->get_z(); - if (fabs(dz) < maxdz) + for (const auto &[vkey, vertex] : *globalmap) { - maxdz = dz; - vtxid = vkey; + float dz = track->get_z() - vertex->get_z(); + if (fabs(dz) < maxdz) + { + maxdz = dz; + vtxid = vkey; + } } - } - track->set_vertex_id(vtxid); - if (Verbosity()) - { - std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; + track->set_vertex_id(vtxid); + if (Verbosity()) + { + std::cout << "Associated track with z " << track->get_z() << " to GlobalVertex id " << track->get_vertex_id() << std::endl; + } } } From 86a0d8afe05bddb6aa3ea1aabea7f0b6ad708cf6 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Tue, 9 May 2023 10:33:37 -0400 Subject: [PATCH 364/468] forgot ; :( --- simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h index 79620cb6a5..aba6140b65 100644 --- a/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h +++ b/simulation/g4simulation/g4ihcal/PHG4IHCalSteppingAction.h @@ -68,7 +68,7 @@ class PHG4IHCalSteppingAction : public PHG4SteppingAction bool m_doG4Hit = true; double m_tmin = -20.; double m_tmax = 60.; - double m_dt = 100. + double m_dt = 100.; std::string m_AbsorberNodeName; std::string m_HitNodeName; From 0fe3e94019185cef900c98d6755e17c9f85db5c8 Mon Sep 17 00:00:00 2001 From: timothyrinn Date: Tue, 9 May 2023 10:45:38 -0400 Subject: [PATCH 365/468] made processing type, and zero suppression a setable quantity --- offline/packages/CaloReco/CaloTowerBuilder.cc | 36 ++++++++++++++++--- offline/packages/CaloReco/CaloTowerBuilder.h | 36 +++++++++++++------ .../packages/CaloReco/CaloWaveformFitting.cc | 2 +- .../CaloReco/CaloWaveformProcessing.cc | 1 - 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index f219bfe507..149968fd3c 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -26,6 +26,19 @@ //____________________________________________________________________________.. CaloTowerBuilder::CaloTowerBuilder(const std::string &name) : SubsysReco(name) + , WaveformProcessing(nullptr) + , m_dettype(CaloTowerBuilder::CEMC) + , m_CaloInfoContainer(nullptr) + , m_detector("CEMC") + , m_packet_low(INT_MIN) + , m_packet_high(INT_MIN) + , m_nsamples(16) + , m_nchannels(192) + , m_nzerosuppsamples(2) + , m_isdata(true) + , _nsoftwarezerosuppression(40) + , _bdosoftwarezerosuppression(false) + , _processingtype(CaloWaveformProcessing::NONE) { WaveformProcessing = new CaloWaveformProcessing(); } @@ -39,16 +52,20 @@ CaloTowerBuilder::~CaloTowerBuilder() //____________________________________________________________________________.. int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); - WaveformProcessing->set_softwarezerosuppression(true,40); + WaveformProcessing->set_processing_type(_processingtype); + WaveformProcessing->set_softwarezerosuppression(_bdosoftwarezerosuppression,_nsoftwarezerosuppression); + if (m_dettype == CaloTowerBuilder::CEMC) { m_detector = "CEMC"; m_packet_low = 6001; m_packet_high = 6128; - // 6001, 60128 m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_cemc_template.root"); + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::HCALIN) { @@ -57,6 +74,10 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_detector = "HCALIN"; m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ihcal_template.root"); + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::HCALOUT) { @@ -65,6 +86,10 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_packet_high = 8008; m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ohcal_template.root"); + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::EPD) { @@ -72,7 +97,10 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_packet_low = 9001; m_packet_high = 9005; m_nchannels = 186; - WaveformProcessing->set_template_file("testbeam_cemc_template.root"); // place holder until we have EPD templates + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); //default the EPD to fast processing + } } WaveformProcessing->initialize_processing(); CreateNodeTree(topNode); diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index 5dfbac3bd8..6947de5a76 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -4,6 +4,7 @@ #define CALOTOWERBUILDER_H #include +#include "CaloWaveformProcessing.h" #include #include @@ -47,17 +48,32 @@ class CaloTowerBuilder : public SubsysReco return; } + void set_processing_type( CaloWaveformProcessing::process processingtype) + { + _processingtype = processingtype; + } + + void set_softwarezerosuppression(bool usezerosuppression,int softwarezerosuppression) + { + _nsoftwarezerosuppression = softwarezerosuppression; + _bdosoftwarezerosuppression = usezerosuppression; + } + private: - CaloWaveformProcessing *WaveformProcessing = nullptr; - CaloTowerBuilder::DetectorSystem m_dettype = CaloTowerBuilder::CEMC; - TowerInfoContainer *m_CaloInfoContainer = nullptr; //! Calo info - std::string m_detector = "CEMC"; - int m_packet_low = INT_MIN; - int m_packet_high = INT_MIN; - int m_nsamples = 16; - int m_nchannels = 192; - int m_nzerosuppsamples = 2; - bool m_isdata = true; + CaloWaveformProcessing *WaveformProcessing; + CaloTowerBuilder::DetectorSystem m_dettype; + TowerInfoContainer *m_CaloInfoContainer; //! Calo info + std::string m_detector; + int m_packet_low; + int m_packet_high; + int m_nsamples; + int m_nchannels; + int m_nzerosuppsamples; + bool m_isdata; + int _nsoftwarezerosuppression; + bool _bdosoftwarezerosuppression; + CaloWaveformProcessing::process _processingtype; + }; #endif // CALOTOWERBUILDER_H diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index e8436f9dc1..cf2f2f51c6 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -54,7 +54,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit if (size1 == _nzerosuppresssamples) { - v.push_back(v.at(0)); + v.push_back(v.at(0) - v.at(1)); //returns peak sample - pedestal sample v.push_back(-1); // set time to -1 to indicate zero suppressed v.push_back(v.at(1)); } diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 4b6ecc47d0..ef120fb246 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -25,7 +25,6 @@ void CaloWaveformProcessing::initialize_processing() if (_bdosoftwarezerosuppression == true) { - //std::cout << "hey zero suppression is on! " << std::endl; m_Fitter->set_softwarezerosuppression(_bdosoftwarezerosuppression,_nsoftwarezerosuppression); } } From 57b14c32aace528460a910849565020be6d34b3a Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Tue, 9 May 2023 11:11:17 -0400 Subject: [PATCH 366/468] Updated with SetBz --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 0b68a100bb..83db73f662 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -36,13 +36,13 @@ #include // for Fun4AllBase::VERBOSITY... #include // for SubsysReco -#include // for toupper -#include // for sqrt -#include // for size_t, exit -#include // for operator<<, endl, basi... -#include // for map -#include // for tie, tuple -//#include // for accessing the field map file from the CDB +#include // for accessing the field map file from the CDB +#include // for toupper +#include // for sqrt +#include // for size_t, exit +#include // for operator<<, endl, basi... +#include // for map +#include // for tie, tuple class PHCompositeNode; @@ -101,39 +101,35 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) { assert(topNode); - std::cout << "Doing InitRun for KFParticle Now" << std::endl; - /* - //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. char *calibrationsroot = getenv("CALIBRATIONROOT"); std::string m_magField = "sphenix3dtrackingmapxyz.root"; - // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); - m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING",m_magField); //Joe's New Implementation to get the field map file name + // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name if (calibrationsroot != nullptr) { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - TFile * fin = new TFile(m_magField.c_str()); + TFile *fin = new TFile(m_magField.c_str()); fin->cd(); - TTree * fieldmap = (TTree *) fin->Get("fieldmap"); - TH1F * BzHist = new TH1F("BzHist","",100,0,10); + TTree *fieldmap = (TTree *) fin->Get("fieldmap"); + TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10); - fieldmap->Project("BzHist","bz","x==0 && y==0 && z==0"); + fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0"); - //The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction - m_Bz = BzHist->GetMean() * 10; //Factor of 10 to convert the B field unit from kG to T + // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction + m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T - if(BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; - if(abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; - - std::cout << "m_Bz = " << m_Bz << std::endl; + if (BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; + if (abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; fieldmap->Delete(); BzHist->Delete(); fin->Close(); - */ + return 0; } @@ -160,6 +156,8 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } + setBz(m_Bz); // Set the Magnetic Field for KFParticle + createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity); if (!m_has_intermediates_sPHENIX) intermediates = daughters; From f1c7e196db8aa2c6f635082b88d3b9d8bbccdb4e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 9 May 2023 12:05:40 -0400 Subject: [PATCH 367/468] use pileupstring to extract base name for G4Hits filename --- offline/framework/frog/CreateFileList.pl | 77 +++++++++++++++--------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 61cf1f4e59..89bc238f44 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -54,7 +54,8 @@ "16" => "HF pythia8 D0 Jets", "17" => "HF pythia8 D0 pi-k Jets ptmin = 5GeV ", "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV", - "19" => "JS pythia8 Jet ptmin = 40GeV" + "19" => "JS pythia8 Jet ptmin = 40GeV", + "20" => "hijing pAu (0-10fm) pileup 0-10fm" ); my %pileupdesc = ( @@ -83,8 +84,10 @@ my %filetypes = (); my %notlike = (); -my $pileupstring; +my $AuAu_pileupstring; my $pp_pileupstring; +my $pAu_pileupstring; +my $pileupstring; if (defined $embed && defined $nopileup) { @@ -93,16 +96,17 @@ } if ($pileup == 1) { - $pileupstring = sprintf("50kHz"); + $AuAu_pileupstring = sprintf("50kHz"); $pp_pileupstring = sprintf("3MHz"); + $pAu_pileupstring = sprintf("500kHz"); } elsif ($pileup == 2) { - $pileupstring = sprintf("25kHz"); + $AuAu_pileupstring = sprintf("25kHz"); } elsif ($pileup == 3) { - $pileupstring = sprintf("10kHz"); + $AuAu_pileupstring = sprintf("10kHz"); } else { @@ -116,13 +120,13 @@ { if ($prodtype == 1) { - $filenamestring = sprintf("sHijing_0_12fm_%s_bkg_0_12fm",$pileupstring); + $filenamestring = sprintf("sHijing_0_12fm_%s_bkg_0_12fm",$AuAu_pileupstring); die "This dataset has been deleted\n"; &commonfiletypes(); } elsif ($prodtype == 2) { - $filenamestring = sprintf("sHijing_0_488fm_%s_bkg_0_12fm",$pileupstring); + $filenamestring = sprintf("sHijing_0_488fm_%s_bkg_0_12fm",$AuAu_pileupstring); die "Dataset $prodtype has been deleted\n"; &commonfiletypes(); } @@ -133,6 +137,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 4) @@ -143,20 +148,22 @@ } else { - $filenamestring = sprintf("sHijing_0_20fm_%s_bkg_0_20fm",$pileupstring); + $filenamestring = sprintf("sHijing_0_20fm_%s_bkg_0_20fm",$AuAu_pileupstring); } $notlike{$filenamestring} = ["pythia8" ,"single", "special"]; + $pileupstring = $AuAu_pileupstring; &commonfiletypes(); } elsif ($prodtype == 5) { - $filenamestring = sprintf("sHijing_0_12fm_%s_bkg_0_20fm",$pileupstring); + $filenamestring = sprintf("sHijing_0_12fm_%s_bkg_0_20fm",$AuAu_pileupstring); die "Dataset $prodtype has been deleted\n"; &commonfiletypes(); } elsif ($prodtype == 6) { - $filenamestring = sprintf("sHijing_0_488fm_%s_bkg_0_20fm",$pileupstring); + $filenamestring = sprintf("sHijing_0_488fm_%s_bkg_0_20fm",$AuAu_pileupstring); + $pileupstring = $AuAu_pileupstring; &commonfiletypes(); } elsif ($prodtype == 7) @@ -166,6 +173,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 8) @@ -175,6 +183,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 9) @@ -184,6 +193,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 10) @@ -193,6 +203,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 11) @@ -203,13 +214,14 @@ { if (defined $embed) { - $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $pileupstring); + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); } else { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 12) @@ -220,13 +232,14 @@ { if (defined $embed) { - $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $pileupstring); + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); } else { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 13) @@ -237,13 +250,14 @@ { if (defined $embed) { - $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $pileupstring); + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); } else { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 14) @@ -309,6 +323,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 17) @@ -318,6 +333,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 18) @@ -327,6 +343,7 @@ { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } + $pileupstring = $pp_pileupstring; &commonfiletypes(); } elsif ($prodtype == 19) @@ -337,13 +354,28 @@ { if (defined $embed) { - $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $pileupstring); + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); } else { $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); } } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 20) + { + if (defined $nopileup) + { + $filenamestring = sprintf("sHijing_pAu_0_10fm"); + } + else + { + $filenamestring = sprintf("sHijing_pAu_0_10fm_%s_bkg_0_10fm",$pAu_pileupstring); + } + $notlike{$filenamestring} = ["pythia8" ,"single", "special"]; + $pileupstring = $pAu_pileupstring; &commonfiletypes(); } else @@ -531,20 +563,9 @@ } else { - my @sp1 = split(/_/,$filenamestring_with_runnumber); - if ($#sp1 == 3 || $#sp1 == 6 ) - { - $newfilenamestring = sprintf("%s_%s_%s\-%010d-",$sp1[0],$sp1[1],$sp1[2],$runnumber); - } - elsif ($#sp1 == 2) - { - $newfilenamestring = sprintf("%s_%s\-%010d-",$sp1[0],$sp1[1],$runnumber); - } - else - { - print "splitting $filenamestring_with_runnumber gave bad number of _: $#sp1\n"; - die; - } + my $splitstring = sprintf("_%s",$pileupstring); + my @sp2 = split(/$splitstring/,$filenamestring_with_runnumber); + $newfilenamestring = sprintf("%s-%010d-",$sp2[0],$runnumber); } my $newgetfilesql = $getfilesql; $newgetfilesql =~ s/$filenamestring_with_runnumber/$newfilenamestring/; From 9b556e085d4c77daf69e69d81f7261b3aa64af8f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 9 May 2023 12:18:54 -0400 Subject: [PATCH 368/468] clang-format --- .../AlignmentDefs.cc | 200 ++++++++++-------- .../TrackerMillepedeAlignment/AlignmentDefs.h | 38 ++-- .../MakeMilleFiles.cc | 49 +++-- .../MakeMilleFiles.h | 6 +- 4 files changed, 163 insertions(+), 130 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc index 016a957b90..a465b9180d 100644 --- a/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc +++ b/offline/packages/TrackerMillepedeAlignment/AlignmentDefs.cc @@ -4,7 +4,8 @@ void AlignmentDefs::getSiliconGlobalLabels(Surface surf, int glbl_label[], Align { Acts::GeometryIdentifier id = surf->geometryId(); int group = 0; - switch(grp) { + switch (grp) + { case AlignmentDefs::siliconGrp::snsr: group = 0; break; @@ -15,19 +16,20 @@ void AlignmentDefs::getSiliconGlobalLabels(Surface surf, int glbl_label[], Align group = 2; break; } - + int label_base = getLabelBase(id, group); - for(int i=0; igeometryId(); int group = 0; - switch(grp) { + switch (grp) + { case AlignmentDefs::tpcGrp::htst: group = 3; break; @@ -38,18 +40,19 @@ void AlignmentDefs::getTpcGlobalLabels(Surface surf, int glbl_label[], Alignment group = 5; break; } - + int label_base = getLabelBase(id, group); - for(int i=0; igeometryId(); int group = 0; - switch(grp) { + switch (grp) + { case AlignmentDefs::mmsGrp::tl: group = 6; break; @@ -57,114 +60,131 @@ void AlignmentDefs::getMMGlobalLabels(Surface surf, int glbl_label[], AlignmentD group = 7; break; } - + int label_base = getLabelBase(id, group); - for(int i=0; i 23 && layer < 39) + if (layer > 23 && layer < 39) region = 1; - if(layer > 38 && layer < 55) + if (layer > 38 && layer < 55) region = 2; - return region; + return region; } int AlignmentDefs::getLabelBase(Acts::GeometryIdentifier id, int group) { - - unsigned int volume = id.volume(); + unsigned int volume = id.volume(); unsigned int acts_layer = id.layer(); - unsigned int layer = base_layer_map.find(volume)->second + acts_layer / 2 -1; + unsigned int layer = base_layer_map.find(volume)->second + acts_layer / 2 - 1; unsigned int sensor = id.sensitive() - 1; // Acts starts at 1 int label_base = 1; // Mille wants to start at 1 // decide what level of grouping we want - if(layer < 7) + if (layer < 7) + { + if (group == 0) + { + // every sensor has a different label + int stave = sensor / nsensors_stave[layer]; + label_base += layer * 1000000 + stave * 10000 + sensor * 10; + return label_base; + } + if (group == 1) + { + // layer and stave, assign all sensors to the stave number + int stave = sensor / nsensors_stave[layer]; + label_base += layer * 1000000 + stave * 10000; + return label_base; + } + if (group == 2) + // layer only, assign all sensors to sensor 0 + label_base += layer * 1000000 + 0; + return label_base; + } + else if (layer > 6 && layer < 55) + { + if (group == 3) { - if(group == 0) - { - // every sensor has a different label - int stave = sensor / nsensors_stave[layer]; - label_base += layer*1000000 + stave*10000 + sensor*10; - return label_base; - } - if(group == 1) - { - // layer and stave, assign all sensors to the stave number - int stave = sensor / nsensors_stave[layer]; - label_base += layer*1000000 + stave*10000; - return label_base; - } - if(group == 2) - // layer only, assign all sensors to sensor 0 - label_base += layer*1000000 + 0; + // want every hitset (layer, sector, side) to have a separate label + // each group of 12 subsurfaces (sensors) is in a single hitset + int hitset = sensor / 12; // 0-11 on side 0, 12-23 on side 1 + label_base += layer * 1000000 + hitset * 10000; return label_base; } - else if(layer > 6 && layer < 55) + if (group == 4) { - if(group == 3) - { - // want every hitset (layer, sector, side) to have a separate label - // each group of 12 subsurfaces (sensors) is in a single hitset - int hitset = sensor/12; // 0-11 on side 0, 12-23 on side 1 - label_base += layer*1000000 + hitset*10000; - return label_base; - } - if(group == 4) - { - // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets - int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 - int sector = (sensor - side *144) / 12; - // for a given layer there are only 12 sectors x 2 sides - // The following gives the sectors in the inner, mid, outer regions unique group labels - int region = getTpcRegion(layer); // inner, mid, outer - label_base += 7*1000000 + (region * 24 + side*12 + sector) *10000; - return label_base; - } - if(group == 5) - { - // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors - label_base += 7*1000000 + 0; - return label_base; - } + // group all tpc layers in each region and sector, assign layer 7 and side and sector number to all layers and hitsets + int side = sensor / 144; // 0-143 on side 0, 144-287 on side 1 + int sector = (sensor - side * 144) / 12; + // for a given layer there are only 12 sectors x 2 sides + // The following gives the sectors in the inner, mid, outer regions unique group labels + int region = getTpcRegion(layer); // inner, mid, outer + label_base += 7 * 1000000 + (region * 24 + side * 12 + sector) * 10000; + return label_base; } + if (group == 5) + { + // all tpc layers and all sectors, assign layer 7 and sensor 0 to all layers and sensors + label_base += 7 * 1000000 + 0; + return label_base; + } + } else + { + if (group == 6) { - if(group == 6) - { - // every tile has different label - int tile = sensor; - label_base += layer*1000000 + tile*10000+sensor*10; - return label_base; - } - if(group == 7) - { - // assign layer 55 and tile 0 to all - label_base += 55*1000000 + 0; - return label_base; - } + // every tile has different label + int tile = sensor; + label_base += layer * 1000000 + tile * 10000 + sensor * 10; + return label_base; } + if (group == 7) + { + // assign layer 55 and tile 0 to all + label_base += 55 * 1000000 + 0; + return label_base; + } + } return -1; } void AlignmentDefs::printBuffers(int index, Acts::Vector2 residual, Acts::Vector2 clus_sigma, float lcl_derivative[], float glbl_derivative[], int glbl_label[]) { - std::cout << " float buffer: " << " residual " << " " << residual(index); - for (int il=0;il base_layer_map = { {10, 0}, {12,3}, {14,7}, {16,55} }; - static constexpr int nsensors_stave[7] = {9,9,9,4,4,4,4}; + //! Map relating Acts::VolumeID to sPHENIX layer + static const std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; + static constexpr int nsensors_stave[7] = {9, 9, 9, 4, 4, 4, 4}; int getTpcRegion(int layer); void getSiliconGlobalLabels(Surface surf, int glbl_label[], siliconGrp grp); void getTpcGlobalLabels(Surface surf, int glbl_label[], tpcGrp grp); void getMMGlobalLabels(Surface surf, int glbl_label[], mmsGrp grp); - + int getLabelBase(Acts::GeometryIdentifier id, int group); - - void printBuffers(int index, Acts::Vector2 residual, - Acts::Vector2 clus_sigma, float lcl_derivative[], - float glbl_derivative[], int glbl_label[]); -} + void printBuffers(int index, Acts::Vector2 residual, + Acts::Vector2 clus_sigma, float lcl_derivative[], + float glbl_derivative[], int glbl_label[]); + +} // namespace AlignmentDefs #endif diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index 9bbd956884..aeff28ab6a 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -194,7 +194,6 @@ Acts::Vector3 MakeMilleFiles::getPCALinePoint(Acts::Vector3 global, SvtxTrackSta return pca; } - void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec statevec) { for (auto state : statevec) @@ -249,20 +248,20 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve } auto surf = _tGeometry->maps().getSurface(ckey, cluster); - + int glbl_label[SvtxAlignmentState::NGL]; - if(layer < 7) - { - AlignmentDefs::getSiliconGlobalLabels(surf, glbl_label,si_group); - } - else if( layer < 55) + if (layer < 7) + { + AlignmentDefs::getSiliconGlobalLabels(surf, glbl_label, si_group); + } + else if (layer < 55) { AlignmentDefs::getTpcGlobalLabels(surf, glbl_label, tpc_group); } else if (layer < 57) - { - AlignmentDefs::getMMGlobalLabels(surf, glbl_label, mms_group); - } + { + AlignmentDefs::getMMGlobalLabels(surf, glbl_label, mms_group); + } if (Verbosity() > 1) { @@ -296,8 +295,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve for (int k = 0; k < SvtxAlignmentState::NGL; k++) { - if(glbl_derivative[k] > 0 || glbl_derivative[k] < 0) - std::cout << "NONZERO GLOBAL DERIVATIVE"< 0 || glbl_derivative[k] < 0) + std::cout << "NONZERO GLOBAL DERIVATIVE" << std::endl; std::cout << glbl_derivative[k] << ", "; } std::cout << std::endl @@ -314,15 +313,15 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve if (Verbosity() > 3) { std::cout << "ckey " << ckey << " and layer " << layer << " buffers:" << std::endl; - AlignmentDefs::printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); + AlignmentDefs::printBuffers(i, residual, clus_sigma, lcl_derivative, glbl_derivative, glbl_label); + } + float errinf = 1.0; + if (m_layerMisalignment.find(layer) != m_layerMisalignment.end()) + { + errinf = m_layerMisalignment.find(layer)->second; } - float errinf = 1.0; - if(m_layerMisalignment.find(layer) != m_layerMisalignment.end()) - { - errinf = m_layerMisalignment.find(layer)->second; - } - - _mille->mille(SvtxAlignmentState::NLOC, lcl_derivative, SvtxAlignmentState::NGL, glbl_derivative, glbl_label, residual(i), errinf*clus_sigma(i)); + + _mille->mille(SvtxAlignmentState::NLOC, lcl_derivative, SvtxAlignmentState::NGL, glbl_derivative, glbl_label, residual(i), errinf * clus_sigma(i)); } } } @@ -340,12 +339,12 @@ bool MakeMilleFiles::is_layer_fixed(unsigned int layer) return ret; } void MakeMilleFiles::set_layers_fixed(unsigned int minlayer, - unsigned int maxlayer) + unsigned int maxlayer) { - for(unsigned int i=minlayer; i derivativeGL; From 346cb1f6f15906b7133b3732218c98722e3fa1bd Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 9 May 2023 16:13:21 -0400 Subject: [PATCH 369/468] add pAu and momentum flag --- offline/framework/frog/CreateFileList.pl | 44 +++++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 89bc238f44..13a16bb972 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -78,8 +78,8 @@ my $pmin; my $pmax; my $production; - -GetOptions('embed' => \$embed, 'l:i' => \$last_segment, 'n:i' => \$nEvents, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); +my $momentum; +GetOptions('embed' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); my $filenamestring; my %filetypes = (); my %notlike = (); @@ -279,7 +279,15 @@ } if (defined $pmin && defined $pmax) { - $filenamestring = sprintf("%s_%s_%d_%dMeV",$filenamestring, $particle, $pmin, $pmax); + if (defined $momentum) + { + $filenamestring = sprintf("%s_%s_%s_%d_%dMeV",$filenamestring, $particle, $momentum, $pmin, $pmax); + } + else + { + $filenamestring = sprintf("%s_%s_%d_%dMeV",$filenamestring, $particle, $pmin, $pmax); + } + if (defined $embed) { $filenamestring = sprintf("%s_sHijing_0_20fm_50kHz_bkg_0_20fm",$filenamestring); @@ -418,6 +426,7 @@ } print "\n Single particle mandatory options:\n"; print "-particle : G4 particle name\n"; + print "-mom : (optional) p or pt\n"; print "-pmin : minimum momentum (in MeV/c)\n"; print "-pmax : maximum momentum (in MeV/c)\n"; @@ -787,17 +796,34 @@ sub print_single_types { if ($name =~ /(\S+)\_(\d+)\_(\d+).*/ ) { - print "CreateFileList.pl -type 14 $types{$name} -run $runnumber -particle $1 -pmin $2 -pmax $3\n"; - } - else - { - print "CreateFileList.pl -type 14 $types{$name} -run $runnumber -particle $name\n"; + my $part = $1; + my $mom; + my $minp = $2; + my $maxp = $3; + if ($part =~ /(\S+)_(\S+)/) + { + $part = $1; + $mom = $2; + } + if (defined $mom) + { + print "CreateFileList.pl -type 14 $types{$name} -run $runnumber -particle $part -mom $mom -pmin $minp -pmax $maxp\n"; + } + else + { + print "CreateFileList.pl -type 14 $types{$name} -run $runnumber -particle $part -pmin $minp -pmax $maxp\n"; + } } + else + { + print "CreateFileList.pl -type 14 $types{$name} -run $runnumber -particle $name\n"; + + } } print "\nDST types:\n"; foreach my $name (sort keys %dsts) { - print "$name\n"; + print "$name\n"; } } From b33b5345d074a42b00e99e1ed81214736d9586e0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 10 May 2023 08:52:56 -0400 Subject: [PATCH 370/468] trigger jenkins From 1de6eb7f89713b6f1b2cd16bbd8bd4385f9cbf3c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 10 May 2023 12:08:36 -0400 Subject: [PATCH 371/468] fix clang build --- offline/packages/TrackerMillepedeAlignment/HelicalFitter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h index 1c880f9a21..d0c12a3d92 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.h @@ -145,7 +145,6 @@ class HelicalFitter : public SubsysReco, public PHParameterInterface bool fitfulltrack = false; float dca_cut = 0.1; // 1 mm - float _error_inflation[4] = {1,1,1,1}; std::string _field; int _fieldDir = -1; From f1958a76bb62ad15d9577bd5cbfa71a81011cffc Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Wed, 10 May 2023 15:31:56 -0400 Subject: [PATCH 372/468] trigger jenkins --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 83db73f662..343dd7d26d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,20 +29,20 @@ #include #include -#include // for obtaining the B field value #include // for getting the TTree from the file +#include // for obtaining the B field value #include // for KFParticle #include // for Fun4AllBase::VERBOSITY... #include // for SubsysReco -#include // for accessing the field map file from the CDB -#include // for toupper -#include // for sqrt -#include // for size_t, exit -#include // for operator<<, endl, basi... -#include // for map -#include // for tie, tuple +#include // for toupper +#include // for sqrt +#include // for size_t, exit +#include // for operator<<, endl, basi... +#include // for map +#include // for tie, tuple +#include // for accessing the field map file from the CDB class PHCompositeNode; @@ -97,39 +97,39 @@ int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) return returnCode; } -int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) -{ +int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode){ + assert(topNode); - - // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + + //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. char *calibrationsroot = getenv("CALIBRATIONROOT"); std::string m_magField = "sphenix3dtrackingmapxyz.root"; - // std::string url = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); - m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name if (calibrationsroot != nullptr) { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - TFile *fin = new TFile(m_magField.c_str()); + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING",m_magField); //Joe's New Implementation to get the field map file name on 05/10/2023 + + TFile * fin = new TFile(m_magField.c_str()); fin->cd(); - TTree *fieldmap = (TTree *) fin->Get("fieldmap"); - TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10); + TTree * fieldmap = (TTree *) fin->Get("fieldmap"); + TH1F * BzHist = new TH1F("BzHist","",100,0,10); - fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0"); + fieldmap->Project("BzHist","bz","x==0 && y==0 && z==0"); - // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction - m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T + //The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction + m_Bz = BzHist->GetMean() * 10; //Factor of 10 to convert the B field unit from kG to T - if (BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; - if (abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; + if(BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; + if(abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; fieldmap->Delete(); BzHist->Delete(); fin->Close(); - + return 0; } @@ -156,7 +156,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - setBz(m_Bz); // Set the Magnetic Field for KFParticle + setBz(m_Bz); //Set the Magnetic Field for KFParticle createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity); @@ -274,34 +274,33 @@ int KFParticle_sPHENIX::parseDecayDescriptor() std::string startIntermediate = "{"; std::string endIntermediate = "}"; - // These tracks require a + or - after their name for TDatabasePDG + //These tracks require a + or - after their name for TDatabasePDG std::string specialTracks[] = {"e", "mu", "pi", "K"}; std::string manipulateDecayDescriptor = m_decayDescriptor; - // Remove all white space before we begin + //Remove all white space before we begin size_t pos; while ((pos = manipulateDecayDescriptor.find(" ")) != std::string::npos) manipulateDecayDescriptor.replace(pos, 1, ""); - // Check for charge conjugate requirement + //Check for charge conjugate requirement std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3); - std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) - { c = ::toupper(c); }); + std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) { c = ::toupper(c); }); - // Remove the CC check if needed + //Remove the CC check if needed if (checkForCC == "[]CC") { manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4); getChargeConjugate(true); } - // Find the initial particle + //Find the initial particle size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow); mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint); if (!findParticle(mother)) ddCanBeParsed = false; manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length()); - // Try and find the intermediates + //Try and find the intermediates while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos) { size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos); @@ -314,7 +313,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() else ddCanBeParsed = false; - // Now find the daughters associated to this intermediate + //Now find the daughters associated to this intermediate int nDaughters = 0; intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length()); while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos) @@ -357,7 +356,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() nTracks += nDaughters; } - // Now find any remaining reconstructable tracks from the mother + //Now find any remaining reconstructable tracks from the mother while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos) { daughter = manipulateDecayDescriptor.substr(0, daughterLocator); From 888be0d02af4d9def92a514ef437a5991f895a60 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 May 2023 17:11:18 -0400 Subject: [PATCH 373/468] move utils from sphenixnpc daughter of nopayloadclient to CDBUtils --- offline/database/sphenixnpc/CDBUtils.cc | 95 +++++++++++++++++++++++ offline/database/sphenixnpc/CDBUtils.h | 36 +++++++++ offline/database/sphenixnpc/Makefile.am | 2 + offline/database/sphenixnpc/sphenixnpc.cc | 3 + offline/database/sphenixnpc/sphenixnpc.h | 2 +- 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 offline/database/sphenixnpc/CDBUtils.cc create mode 100644 offline/database/sphenixnpc/CDBUtils.h diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc new file mode 100644 index 0000000000..305c812ef0 --- /dev/null +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -0,0 +1,95 @@ +#include "CDBUtils.h" + +#include "sphenixnpc.h" + +#include + +#include +#include +CDBUtils::CDBUtils() + : cdbclient(new sphenixnpc()) +{} + +CDBUtils::CDBUtils(const std::string &globaltag) + : cdbclient(new sphenixnpc(globaltag)) +{ +} + + +void CDBUtils::createGlobalTag(const std::string &tagname) +{ + cdbclient->createThisGlobalTag(tagname); +} + +int CDBUtils::deleteGlobalTag(const std::string &tagname) +{ + int iret = cdbclient->deleteThisGlobalTag(tagname); + return iret; +} + + +void CDBUtils::clearCache() +{ + cdbclient->clearCache(); +} + +std::string CDBUtils::getCalibrationFile(const std::string &type, uint64_t iov) +{ + return cdbclient->getCalibrationFile(type, iov); +} + +int CDBUtils::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) +{ + int iret = cdbclient->insertcalib(pl_type, file_url, iov_start); + return iret; +} + +int CDBUtils::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) +{ + int iret = cdbclient->insertcalib(pl_type, file_url, iov_start,iov_end); + return iret; +} + +int CDBUtils::createDomain(const std::string &domain) +{ + cdbclient->createDomain(domain); + int iret = -1; + nlohmann::json resp; + if (m_DomainCache.empty()) + { + resp = cdbclient->getPayloadTypes(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string existent_domain = it.value().at("name"); + m_DomainCache.insert(existent_domain); + } + } + if (m_DomainCache.find(domain) == m_DomainCache.end()) + { + resp = cdbclient->createPayloadType(domain); + iret = resp["code"]; + if (iret == 0) + { + m_DomainCache.insert(domain); + } + } + else + { + iret = 0; + } + return iret; +} + +void CDBUtils::ListGlobalTags() +{ + nlohmann::json resp = cdbclient->getGlobalTags(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_gt = it.value().at("name"); + std::cout << "global tag: " << exist_gt << std::endl; + } + return; +} + diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h new file mode 100644 index 0000000000..21a829c2c6 --- /dev/null +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -0,0 +1,36 @@ +#ifndef SPHENIXNPC_CDBUTILS_H +#define SPHENIXNPC_CDBUTILS_H + +#include +#include +#include +#include + +class sphenixnpc; + +class CDBUtils +{ + public: + + CDBUtils(); + CDBUtils(const std::string &globaltag); + virtual ~CDBUtils() = default; + void createGlobalTag(const std::string &tagname); + int createDomain(const std::string &domain); + std::string getCalibrationFile(const std::string &type, uint64_t iov); + int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); + int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); + int deleteGlobalTag(const std::string &); + void ListGlobalTags(); + void clearCache(); + void Verbosity(int i) { m_Verbosity = i; } + int Verbosity() const { return m_Verbosity; } + + private: + int m_Verbosity = 0; + sphenixnpc *cdbclient = nullptr; + std::string m_CachedGlobalTag; + std::set m_DomainCache; +}; + +#endif // SPHENIXNPC_SPHENIXNPC_H diff --git a/offline/database/sphenixnpc/Makefile.am b/offline/database/sphenixnpc/Makefile.am index b229eb8fd4..80e6b2344f 100644 --- a/offline/database/sphenixnpc/Makefile.am +++ b/offline/database/sphenixnpc/Makefile.am @@ -15,6 +15,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 libsphenixnpc_la_SOURCES = \ + CDBUtils.cc \ sphenixnpc.cc @@ -25,6 +26,7 @@ libsphenixnpc_la_LIBADD = \ # please add new classes in alphabetical order pkginclude_HEADERS = \ + CDBUtils.h \ sphenixnpc.h ################################################ diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index e04d9a7b48..bf7e3d80fa 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -6,6 +6,9 @@ #include #include +sphenixnpc::sphenixnpc() +{} + sphenixnpc::sphenixnpc(const std::string &globaltag) { cache_set_GlobalTag(globaltag); diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 17a75ae945..12c5e8c42d 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -16,7 +16,7 @@ class sphenixnpc : public nopayloadclient::Client using nopayloadclient::Client::createGlobalTag; using nopayloadclient::Client::deleteGlobalTag; using nopayloadclient::Client::setGlobalTag; - + sphenixnpc(); sphenixnpc(const std::string &globaltag); virtual ~sphenixnpc() = default; nlohmann::json getUrlDict(long long iov); From 2d027c2a5e7aebdfe02b55a65555479b89809bb7 Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 10 May 2023 17:24:32 -0400 Subject: [PATCH 374/468] Added a hardcoded, explicitly mapping of Felix ports/channels to ladders. It is an auto-generated switch statement from text files we had been using --- offline/packages/intt/InttFelixMap.cc | 646 ++++++++++++++++++++++++++ offline/packages/intt/InttFelixMap.h | 18 + offline/packages/intt/Makefile.am | 6 +- 3 files changed, 669 insertions(+), 1 deletion(-) create mode 100755 offline/packages/intt/InttFelixMap.cc create mode 100755 offline/packages/intt/InttFelixMap.h diff --git a/offline/packages/intt/InttFelixMap.cc b/offline/packages/intt/InttFelixMap.cc new file mode 100755 index 0000000000..c455f97c79 --- /dev/null +++ b/offline/packages/intt/InttFelixMap.cc @@ -0,0 +1,646 @@ +#include "InttFelixMap.h" + +int INTT_Felix::FelixMap(int const& felix, int const& felix_channel, struct Ladder_s& ladder_struct) +{ + switch(felix) + { + case 0: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 1: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 2: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 3: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 12; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 12; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 13; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 13; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 14; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 14; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 15; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 15; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 4: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 0; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 1; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 2; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 5: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 3; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 5; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 4; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 6: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 6; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 7; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 8; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + case 7: + switch(felix_channel) + { + case 0: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 1: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 9; + return EXIT_SUCCESS; + case 2: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 3: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 12; + return EXIT_SUCCESS; + case 4: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 12; + return EXIT_SUCCESS; + case 5: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 13; + return EXIT_SUCCESS; + case 6: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 13; + return EXIT_SUCCESS; + case 7: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 10; + return EXIT_SUCCESS; + case 8: + ladder_struct.barrel = 0; + ladder_struct.layer = 1; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 9: + ladder_struct.barrel = 0; + ladder_struct.layer = 0; + ladder_struct.ladder = 11; + return EXIT_SUCCESS; + case 10: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 14; + return EXIT_SUCCESS; + case 11: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 14; + return EXIT_SUCCESS; + case 12: + ladder_struct.barrel = 1; + ladder_struct.layer = 1; + ladder_struct.ladder = 15; + return EXIT_SUCCESS; + case 13: + ladder_struct.barrel = 1; + ladder_struct.layer = 0; + ladder_struct.ladder = 15; + return EXIT_SUCCESS; + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + default: + ladder_struct.barrel = -1; + ladder_struct.layer = -1; + ladder_struct.ladder = -1; + return EXIT_FAILURE; + } + return EXIT_FAILURE; +} diff --git a/offline/packages/intt/InttFelixMap.h b/offline/packages/intt/InttFelixMap.h new file mode 100755 index 0000000000..c78a654595 --- /dev/null +++ b/offline/packages/intt/InttFelixMap.h @@ -0,0 +1,18 @@ +#ifndef FELIX_MAP_H +#define FELIX_MAP_H + +#include + +namespace INTT_Felix +{ + struct Ladder_s + { + int barrel; + int layer; + int ladder; + }; + + int FelixMap(int const&, int const&, struct Ladder_s&); +}; + +#endif//FELIX_MAP_H diff --git a/offline/packages/intt/Makefile.am b/offline/packages/intt/Makefile.am index 1c5bef835e..cdd2f87dfa 100644 --- a/offline/packages/intt/Makefile.am +++ b/offline/packages/intt/Makefile.am @@ -19,6 +19,8 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ InttClusterizer.h \ + InttDeadMapHelper.h \ + InttFelixMap.h \ CylinderGeomIntt.h ROOTDICTS = \ @@ -30,7 +32,9 @@ nobase_dist_pcm_DATA = \ # sources for intt library libintt_la_SOURCES = \ - InttClusterizer.cc + InttClusterizer.cc \ + InttDeadMapHelper.cc \ + InttFelixMap.cc libintt_la_LIBADD = \ libintt_io.la \ From 633af7b991f31eaf058347f734aaddab7eadd49b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 May 2023 12:22:56 -0400 Subject: [PATCH 375/468] set global tag in cdbutils --- offline/database/sphenixnpc/CDBUtils.cc | 6 ++++++ offline/database/sphenixnpc/CDBUtils.h | 1 + 2 files changed, 7 insertions(+) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 305c812ef0..fb2bc96176 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -6,6 +6,7 @@ #include #include + CDBUtils::CDBUtils() : cdbclient(new sphenixnpc()) {} @@ -21,6 +22,11 @@ void CDBUtils::createGlobalTag(const std::string &tagname) cdbclient->createThisGlobalTag(tagname); } +void CDBUtils::setGlobalTag(const std::string &tagname) +{ + cdbclient->setGlobalTag(const std::string &tagname); +} + int CDBUtils::deleteGlobalTag(const std::string &tagname) { int iret = cdbclient->deleteThisGlobalTag(tagname); diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 21a829c2c6..3bee5ebf9a 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -16,6 +16,7 @@ class CDBUtils CDBUtils(const std::string &globaltag); virtual ~CDBUtils() = default; void createGlobalTag(const std::string &tagname); + void setGlobalTag(const std::string &tagname); int createDomain(const std::string &domain); std::string getCalibrationFile(const std::string &type, uint64_t iov); int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); From 636007cc3ba0b2024bd8481208ceda767b8831d4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 May 2023 12:46:04 -0400 Subject: [PATCH 376/468] enable online build (just install TrkrDefs.h), clean up Makefile.am --- offline/packages/trackbase/Makefile.am | 41 ++++++++++++++++++------- offline/packages/trackbase/TrkrDefs.h | 6 ++-- offline/packages/trackbase/configure.ac | 10 ++++++ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index cee64707aa..dc01c464da 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -4,9 +4,15 @@ AUTOMAKE_OPTIONS = foreign # list of shared libraries to produce +if USE_ONLINE + +else + lib_LTLIBRARIES = \ libtrack_io.la +endif + AM_CPPFLAGS = \ -I$(includedir) \ -I$(OFFLINE_MAIN)/include \ @@ -18,6 +24,11 @@ AM_LDFLAGS = \ -L$(ROOTSYS)/lib \ -L$(OFFLINE_MAIN)/lib64 +if USE_ONLINE +pkginclude_HEADERS = \ + TrkrDefs.h +else + pkginclude_HEADERS = \ ActsAborter.h \ ActsGeometry.h \ @@ -26,6 +37,7 @@ pkginclude_HEADERS = \ ActsSurfaceMaps.h \ ActsTrackFittingAlgorithm.h \ ActsTrackingGeometry.h \ + alignmentTransformationContainer.h \ AlignmentTransformation.h \ CMFlashCluster.h \ CMFlashClusterContainer.h \ @@ -50,6 +62,7 @@ pkginclude_HEADERS = \ RawHitv1.h \ ResidualOutlierFinder.h \ SpacePoint.h \ + sPHENIXActsDetectorElement.h \ TpcDefs.h \ TpcSeedTrackMap.h \ TpcSeedTrackMapv1.h \ @@ -82,11 +95,11 @@ pkginclude_HEADERS = \ TrkrHitTruthAssoc.h \ TrkrHitTruthAssocv1.h \ TrkrHitv1.h \ - TrkrHitv2.h \ - alignmentTransformationContainer.h \ - sPHENIXActsDetectorElement.h + TrkrHitv2.h + ROOTDICTS = \ + alignmentTransformationContainer_Dict.cc \ CMFlashClusterContainer_Dict.cc \ CMFlashClusterContainerv1_Dict.cc \ CMFlashCluster_Dict.cc \ @@ -133,13 +146,12 @@ ROOTDICTS = \ TrkrHitTruthAssocv1_Dict.cc \ TrkrHit_Dict.cc \ TrkrHitv1_Dict.cc \ - TrkrHitv2_Dict.cc \ - alignmentTransformationContainer_Dict.cc \ - sPHENIXActsDetectorElement.cc + TrkrHitv2_Dict.cc pcmdir = $(libdir) nobase_dist_pcm_DATA = \ + alignmentTransformationContainer_Dict_rdict.pcm \ CMFlashClusterContainer_Dict_rdict.pcm \ CMFlashClusterContainerv1_Dict_rdict.pcm \ CMFlashCluster_Dict_rdict.pcm \ @@ -186,14 +198,14 @@ nobase_dist_pcm_DATA = \ TrkrHitTruthAssocv1_Dict_rdict.pcm \ TrkrHit_Dict_rdict.pcm \ TrkrHitv1_Dict_rdict.pcm \ - TrkrHitv2_Dict_rdict.pcm \ - alignmentTransformationContainer_Dict_rdict.pcm + TrkrHitv2_Dict_rdict.pcm # sources for io library libtrack_io_la_SOURCES = \ $(ROOTDICTS) \ ActsGeometry.cc \ ActsSurfaceMaps.cc \ + alignmentTransformationContainer.cc \ AlignmentTransformation.cc \ CMFlashClusterContainerv1.cc \ CMFlashClusterv1.cc \ @@ -210,6 +222,7 @@ libtrack_io_la_SOURCES = \ RawHitSetv1.cc \ RawHitTpc.cc \ RawHitv1.cc \ + sPHENIXActsDetectorElement.cc \ TpcDefs.cc \ TpcSeedTrackMap.cc \ TpcSeedTrackMapv1.cc \ @@ -241,16 +254,16 @@ libtrack_io_la_SOURCES = \ TrkrHitSetv1.cc \ TrkrHitTruthAssocv1.cc \ TrkrHitv1.cc \ - TrkrHitv2.cc \ - alignmentTransformationContainer.cc + TrkrHitv2.cc libtrack_io_la_LIBADD = \ -lphool \ -lActsCore \ -lActsPluginTGeo \ -lffamodules \ - -lphg4hit + -lphg4hit +endif # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h @@ -264,9 +277,15 @@ libtrack_io_la_LIBADD = \ BUILT_SOURCES = testexternals.cc +if USE_ONLINE + +else + noinst_PROGRAMS = \ testexternals_track_io +endif + #testexternals_track_util_SOURCES = testexternals.cc #testexternals_track_util_LDADD = libtrack_util.la diff --git a/offline/packages/trackbase/TrkrDefs.h b/offline/packages/trackbase/TrkrDefs.h index bc072e5209..e591a41ca9 100644 --- a/offline/packages/trackbase/TrkrDefs.h +++ b/offline/packages/trackbase/TrkrDefs.h @@ -4,8 +4,8 @@ * @date June 2018 * @brief Namespace with Trkr key types and utility functions */ -#ifndef TRACKBASE_TRKRDEFUTIL_H -#define TRACKBASE_TRKRDEFUTIL_H +#ifndef TRACKBASE_TRKRDEFS_H +#define TRACKBASE_TRKRDEFS_H #include #include @@ -104,4 +104,4 @@ namespace TrkrDefs } -#endif //TRACKBASE_TRKRDEFUTIL_H +#endif //TRACKBASE_TRKRDEFS_H diff --git a/offline/packages/trackbase/configure.ac b/offline/packages/trackbase/configure.ac index 2efc6c8e16..19f8ea89d4 100644 --- a/offline/packages/trackbase/configure.ac +++ b/offline/packages/trackbase/configure.ac @@ -21,5 +21,15 @@ esac CINTDEFS=" -noIncludePaths -inlineInputHeader " AC_SUBST(CINTDEFS) +AC_ARG_ENABLE(online, + [ --enable-online build using for online [default=no]], + [case "${enableval}" in + yes) online=true ;; + no) online=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-online) ;; + esac], + online=false) +AM_CONDITIONAL(USE_ONLINE, test "x$online" = xtrue) + AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 5506955c5da16e86630b2acebe8f51bad891649f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 May 2023 17:17:54 -0400 Subject: [PATCH 377/468] compile TrkrDefs.cc into shared libs for online --- offline/packages/trackbase/Makefile.am | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index dc01c464da..41db1bb5ed 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -4,14 +4,17 @@ AUTOMAKE_OPTIONS = foreign # list of shared libraries to produce -if USE_ONLINE - -else - lib_LTLIBRARIES = \ libtrack_io.la -endif +if USE_ONLINE +pkginclude_HEADERS = \ + TrkrDefs.h + +libtrack_io_la_SOURCES = \ + TrkrDefs.cc + +else AM_CPPFLAGS = \ -I$(includedir) \ @@ -24,10 +27,6 @@ AM_LDFLAGS = \ -L$(ROOTSYS)/lib \ -L$(OFFLINE_MAIN)/lib64 -if USE_ONLINE -pkginclude_HEADERS = \ - TrkrDefs.h -else pkginclude_HEADERS = \ ActsAborter.h \ @@ -277,15 +276,9 @@ endif BUILT_SOURCES = testexternals.cc -if USE_ONLINE - -else - noinst_PROGRAMS = \ testexternals_track_io -endif - #testexternals_track_util_SOURCES = testexternals.cc #testexternals_track_util_LDADD = libtrack_util.la From e59487e9a54877ec1267de81ede81678f0ef92ee Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 May 2023 23:14:13 -0400 Subject: [PATCH 378/468] enable online build --- offline/packages/micromegas/Makefile.am | 52 ++++++++++++++++++++---- offline/packages/micromegas/configure.ac | 11 +++++ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/offline/packages/micromegas/Makefile.am b/offline/packages/micromegas/Makefile.am index b049816da3..5c4b0e9b7b 100644 --- a/offline/packages/micromegas/Makefile.am +++ b/offline/packages/micromegas/Makefile.am @@ -3,6 +3,47 @@ AUTOMAKE_OPTIONS = foreign +if USE_ONLINE + +### trimmed version of libmicromegas_io library, for online monitoring +### it only contains MicromegasDefs.h and MicromegasMapping + +lib_LTLIBRARIES = \ + libmicromegas_io.la + +## TODO: check with Chris where headers are installed (TrkrDefs.h) in "online" build +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include + +## TODO: check with Chris where libraries are installed (TrkrDefs.h) in "online" build +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib + +pkginclude_HEADERS = \ + MicromegasDefs.h \ + MicromegasMapping.h + +# sources for io library +libmicromegas_io_la_SOURCES = \ + MicromegasDefs.cc \ + MicromegasMapping.cc + +libmicromegas_io_la_LIBADD = \ + -ltrack_io + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals_micromegas_io + +testexternals_micromegas_io_SOURCES = testexternals.cc +testexternals_micromegas_io_LDADD = libmicromegas_io.la + +else + +### full offline version lib_LTLIBRARIES = \ libmicromegas_io.la \ libmicromegas.la @@ -36,7 +77,6 @@ nobase_dist_pcm_DATA = \ CylinderGeomMicromegas_Dict_rdict.pcm \ MicromegasTile_Dict_rdict.pcm -# sources for io library libmicromegas_io_la_SOURCES = \ $(ROOTDICTS) \ CylinderGeomMicromegas.cc \ @@ -52,7 +92,6 @@ libmicromegas_io_la_LIBADD = \ -ltrack_io \ -ltrackbase_historic_io -# sources for micromegas library libmicromegas_la_SOURCES = \ MicromegasClusterizer.cc \ MicromegasRawDataCalibration.cc \ @@ -63,16 +102,11 @@ libmicromegas_la_LIBADD = \ -lphg4hit \ -lSubsysReco -# Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ -#just to get the dependency %_Dict_rdict.pcm: %_Dict.cc ; -################################################ -# linking tests - BUILT_SOURCES = testexternals.cc noinst_PROGRAMS = \ @@ -85,6 +119,8 @@ testexternals_micromegas_io_LDADD = libmicromegas_io.la testexternals_micromegas_SOURCES = testexternals.cc testexternals_micromegas_LDADD = libmicromegas.la +endif + testexternals.cc: echo "//*** this is a generated file. Do not commit, do not edit" > $@ echo "int main()" >> $@ @@ -92,7 +128,5 @@ testexternals.cc: echo " return 0;" >> $@ echo "}" >> $@ -################################################ - clean-local: rm -f *Dict* $(BUILT_SOURCES) *.pcm diff --git a/offline/packages/micromegas/configure.ac b/offline/packages/micromegas/configure.ac index d31000325a..39a779fa35 100644 --- a/offline/packages/micromegas/configure.ac +++ b/offline/packages/micromegas/configure.ac @@ -21,5 +21,16 @@ esac CINTDEFS=" -noIncludePaths -inlineInputHeader " AC_SUBST(CINTDEFS) +### add "online" build option +AC_ARG_ENABLE(online, + [ --enable-online build using for online [default=no]], + [case "${enableval}" in + yes) online=true ;; + no) online=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-online) ;; + esac], + online=false) +AM_CONDITIONAL(USE_ONLINE, test "x$online" = xtrue) + AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 73ab994f322b4c6f35250c3ec69c264f877db9c2 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 12 May 2023 18:05:10 -0400 Subject: [PATCH 379/468] fixed memory leak Thanks Jin for finding this out ! --- offline/packages/micromegas/MicromegasRawDataCalibration.cc | 3 ++- offline/packages/micromegas/MicromegasRawDataDecoder.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index f0aef020ec..36084056f5 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -24,6 +24,7 @@ #include #include +#include //_________________________________________________________ MicromegasRawDataCalibration::MicromegasRawDataCalibration( const std::string& name ): @@ -87,7 +88,7 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) * To be fixed at a later stage. * check with Martin Purschke */ - auto packet = event->getPacket(MicromegasDefs::m_packet_id); + std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); if( !packet ) { // no data diff --git a/offline/packages/micromegas/MicromegasRawDataDecoder.cc b/offline/packages/micromegas/MicromegasRawDataDecoder.cc index 40e1360077..d83c33a1b6 100644 --- a/offline/packages/micromegas/MicromegasRawDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasRawDataDecoder.cc @@ -22,6 +22,7 @@ #include #include +#include //_________________________________________________________ MicromegasRawDataDecoder::MicromegasRawDataDecoder( const std::string& name ): @@ -97,7 +98,7 @@ int MicromegasRawDataDecoder::process_event(PHCompositeNode *topNode) * To be fixed at a later stage. * check with Martin Purschke */ - auto packet = event->getPacket(MicromegasDefs::m_packet_id); + std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); if( !packet ) { // no data From 6436049b9fe147830c58b9bb0d2eccacbff021d3 Mon Sep 17 00:00:00 2001 From: rosstom Date: Fri, 12 May 2023 18:08:00 -0400 Subject: [PATCH 380/468] Adding the TPC pedestal calibration module Includes a README file to explain how to run all steps of processing from PRDF-ROOT file conversion to displaying the pedestal average and rms information for all channels in the TPC --- .../tpc/pedestalcalibration/README.md | 22 +++ .../TPCPedestalCalibration.C | 142 ++++++++++++++++++ .../run_TPCPedestalCalibration.sh | 12 ++ 3 files changed, 176 insertions(+) create mode 100644 calibrations/tpc/pedestalcalibration/README.md create mode 100644 calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C create mode 100644 calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh diff --git a/calibrations/tpc/pedestalcalibration/README.md b/calibrations/tpc/pedestalcalibration/README.md new file mode 100644 index 0000000000..23236c2cab --- /dev/null +++ b/calibrations/tpc/pedestalcalibration/README.md @@ -0,0 +1,22 @@ +Procedure for processing PRDF pedestal run files: + +* Make sure you have locally installed the TPCRawDataTree module located at analysis/TPC/DAQ/TPCRawDataTree/ +* Edit the `Fun4All_TPC_UnpackPRDF.C` macro to point the outDir variable to whichever directory you'd like to store the output root files in. The macro is located in the `analysis/TPC/DAQ/macros/` directory +* Run the `run_UnpackPRDF.sh` shell script with all files you want to process as an argument, making sure to set the number of events variable in the shell script to be however many events you need. An example of running the script for all TPC sectors in run 10151: + +``` +source run_UnpackPRDF.sh /sphenix/user/jinhuang/TPC/commissioning/pedestal/TPC_ebdc*_pedestal-00010151-0000.prdf +``` + +Procedure for creating plots of each sectors dead channels, pedestal mean, and pedestal rms: +* Edit the `TPC_Channel_QA.C` macro to have the `runNumber` string be the name of the file run you want to process and edit the `fileName` to match wherever you have stored the output root files from processing the PRDFs using TPCRawDataTree as above. Also edit the `saveName` variable at the end of the file to point to wherever you'd like the png images to be stored instead of just an `images` directory wherever you're running the macro +* Run `TPC_Channel_QA.C` with `root -l TPC_Channel_QA.C` and you'll generate 24 pngs, one for each sector in the TPC + +Procedure for making root file containing channel averaged pedestal info: +* Run the `run_TPCPedestalCalibration.sh` script from the command line with all root files (output from converting the PRDF files) you want to process as an argument. Example for processing all TPC sectors from run 10151: +``` +source run_TPCPedestalCalibration.sh /sphenix/user/rosstom/test/testFiles/TPC_ebdc*_pedestal-00010151-0000.prdf_TPCRawDataTree.root +``` +* Should produce a new root file for each sector's channels with information about each channel's alive/dead status, pedestal mean, and pedestal rms + +If you have any questions, send Thomas Marshall (@rosstom, rosstom@ucla.edu) or Aditya Dash (@adityadash, adityaprasaddash55@gmail.com) a message on mattermost or over email diff --git a/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C b/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C new file mode 100644 index 0000000000..590f10bad7 --- /dev/null +++ b/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "TChain.h" +#include "TFile.h" +#include "TTree.h" +#include "TString.h" +#include "TObjString.h" +#include "TSystem.h" +#include "TROOT.h" +#include "TTreeReader.h" +#include "TTreeReaderValue.h" +#include "TTreeReaderArray.h" + + +void TPCPedestalCalibration(vector inputFiles = {"/sphenix/user/rosstom/test/testFiles/TPC_ebdc00_pedestal-00010131-0000.prdf_TPCRawDataTree.root"}){ + for (int fileNum = 0; fileNum < inputFiles.size(); fileNum++){ + string sectorNum = inputFiles[fileNum]; + size_t pos = sectorNum.find("ebdc"); + sectorNum.erase(pos+6); + sectorNum.erase(sectorNum.begin(),sectorNum.begin()+pos+4); + Int_t sector; + if (sectorNum.substr(0,1) == "0") + { + sectorNum.erase(sectorNum.begin(),sectorNum.end()-1); + sector = std::stoi(sectorNum); + } + else sector = std::stoi(sectorNum); + + Int_t mod_arr[26]={2,2,1,1,1,3,3,3,3,3,3,2,2,1,2,2,1,1,2,2,3,3,3,3,3,3}; + Int_t slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; + + TFile *pedestalInput = TFile::Open(inputFiles[fileNum].c_str()); + TTreeReader myReader("SampleTree", pedestalInput); + + TTreeReaderValue nSamples_in(myReader, "nSamples"); + TTreeReaderValue fee_in(myReader, "fee"); + TTreeReaderArray adcSamples_in(myReader, "adcSamples"); + TTreeReaderValue Channel_in(myReader, "Channel"); + +//Adding the output tree + TString* outputfilename=new TString("pedestalCalibration_TPC_ebdc"+sectorNum+".root"); + TFile* outputfile=new TFile(outputfilename->Data(),"recreate"); + TTree* outputTree=new TTree("outputTree","outputTree"); + Int_t isAlive=1; // 1 if the channel is working properly, 0 if no signal(number of samples is 0, adc value is 0 or nan), pedestal above 200 or below 10 + Float_t pedMean; // average pedestal value over all samples + Float_t pedStd; // pedestal standard deviation over all samples + Int_t chan; // channel number + Int_t fee; // fee number + Int_t module; // module number (e.g. R1, R2, R3) + Int_t slot; // slot number + outputTree->Branch("isAlive",&isAlive,"isAlive/I"); + outputTree->Branch("pedMean",&pedMean,"pedMean/F"); + outputTree->Branch("pedStd",&pedStd,"pedStd/F"); + outputTree->Branch("sector",§or,"sector/I"); + outputTree->Branch("fee",&fee,"fee/I"); + outputTree->Branch("chan",&chan,"chan/I"); + outputTree->Branch("module",&module,"module/I"); + outputTree->Branch("slot",&slot,"slot/I"); + + Float_t ave_adc_fee_channel[26][256]; + Float_t std_adc_fee_channel[26][256]; + Float_t counts_adc_fee_channel[26][256]; + Int_t alive_array_fee_channel[26][256]; + for(int fee_no=0;fee_no<26;fee_no++){ + for(int channel_no=0;channel_no<256;channel_no++) + { + ave_adc_fee_channel[fee_no][channel_no]=0.0; + std_adc_fee_channel[fee_no][channel_no]=0.0; + counts_adc_fee_channel[fee_no][channel_no]=0.0; + alive_array_fee_channel[fee_no][channel_no]=1; + } + } + + while(myReader.Next()) + { + if(*nSamples_in==0) + { + alive_array_fee_channel[*fee_in][*Channel_in]=0; + continue; + } + + bool dead = false; + for(int adc_sam_no=0;adc_sam_no<*nSamples_in;adc_sam_no++) + { + if (adcSamples_in[adc_sam_no] == 0 || TMath::IsNaN(float(adcSamples_in[adc_sam_no]))) + { + alive_array_fee_channel[*fee_in][*Channel_in]=0; + } + } + if (dead) {continue;} + + for(int adc_sam_no=0;adc_sam_no<*nSamples_in;adc_sam_no++){ + ave_adc_fee_channel[*fee_in][*Channel_in]+=adcSamples_in[adc_sam_no]; + std_adc_fee_channel[*fee_in][*Channel_in]+=pow(adcSamples_in[adc_sam_no],2); + counts_adc_fee_channel[*fee_in][*Channel_in]+=1.0; + } + + } + + for(int fee_no=0;fee_no<26;fee_no++) + { + for(int channel_no=0;channel_no<256;channel_no++) + { + if(counts_adc_fee_channel[fee_no][channel_no] != 0.0) + { + float temp1 = ave_adc_fee_channel[fee_no][channel_no]/counts_adc_fee_channel[fee_no][channel_no]; + float temp2 = std_adc_fee_channel[fee_no][channel_no]/counts_adc_fee_channel[fee_no][channel_no]; + ave_adc_fee_channel[fee_no][channel_no] = temp1; + std_adc_fee_channel[fee_no][channel_no] = temp2; + } + else + { + ave_adc_fee_channel[fee_no][channel_no] = 0.0; + std_adc_fee_channel[fee_no][channel_no] = 0.0; + alive_array_fee_channel[fee_no][channel_no]=0; + } + + if(ave_adc_fee_channel[fee_no][channel_no] > 200 || ave_adc_fee_channel[fee_no][channel_no] < 10) + { + alive_array_fee_channel[fee_no][channel_no]=0; + } + + pedMean=ave_adc_fee_channel[fee_no][channel_no]; + pedStd=sqrt(std_adc_fee_channel[fee_no][channel_no] - pow(ave_adc_fee_channel[fee_no][channel_no],2)); + isAlive=alive_array_fee_channel[fee_no][channel_no]; + chan=channel_no; + fee=fee_no; + module=mod_arr[fee_no]; + slot=slot_arr[fee_no]; + outputTree->Fill(); + } + } + outputfile->cd(); + outputTree->Write(); + outputfile->Close(); + pedestalInput->Close(); + } +} diff --git a/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh b/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh new file mode 100644 index 0000000000..b7d9aab7ee --- /dev/null +++ b/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh @@ -0,0 +1,12 @@ +source /opt/sphenix/core/bin/sphenix_setup.sh -n new + +inputFiles="{" +for fileList in $@ +do + inputFiles+="\"${fileList}\"," +done +inputFiles=${inputFiles::-1} +inputFiles+="}" +echo running: run_TPCPedestalCalibration.sh $* +root.exe -q -b TPCPedestalCalibration.C\(${inputFiles}\) +echo Script done From f99bbfaca9ef01317e1173a6a7b4ddec026ca8ab Mon Sep 17 00:00:00 2001 From: rosstom Date: Fri, 12 May 2023 18:14:33 -0400 Subject: [PATCH 381/468] Forgot to add names --- .../tpc/pedestalcalibration/TPCPedestalCalibration.C | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C b/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C index 590f10bad7..a2ad9f89a2 100644 --- a/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C +++ b/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C @@ -15,6 +15,11 @@ #include "TTreeReaderValue.h" #include "TTreeReaderArray.h" +/*************************************************************/ +/* TPC Pedestal Calibration */ +/* Thomas Marshall,Aditya Dash */ +/* rosstom@ucla.edu,aditya55@physics.ucla.edu */ +/*************************************************************/ void TPCPedestalCalibration(vector inputFiles = {"/sphenix/user/rosstom/test/testFiles/TPC_ebdc00_pedestal-00010131-0000.prdf_TPCRawDataTree.root"}){ for (int fileNum = 0; fileNum < inputFiles.size(); fileNum++){ From 1f610d984c9c16cade2959648c1e1cb215f81d1c Mon Sep 17 00:00:00 2001 From: MYOMAO Date: Mon, 15 May 2023 10:57:12 -0400 Subject: [PATCH 382/468] A check to validate exactly 1 B field value at (0,0,0) in the field map --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 343dd7d26d..9c311334c8 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,20 +29,20 @@ #include #include +#include // for obtaining the B field value #include // for getting the TTree from the file -#include // for obtaining the B field value #include // for KFParticle #include // for Fun4AllBase::VERBOSITY... #include // for SubsysReco -#include // for toupper -#include // for sqrt -#include // for size_t, exit -#include // for operator<<, endl, basi... -#include // for map -#include // for tie, tuple -#include // for accessing the field map file from the CDB +#include // for accessing the field map file from the CDB +#include // for toupper +#include // for sqrt +#include // for size_t, exit +#include // for operator<<, endl, basi... +#include // for map +#include // for tie, tuple class PHCompositeNode; @@ -97,39 +97,43 @@ int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) return returnCode; } -int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode){ - +int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) +{ assert(topNode); - - //Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. + + // Load the official offline B-field map that is also used in tracking, basically copying the codes from: https://github.com/sPHENIX-Collaboration/coresoftware/blob/master/offline/packages/trackreco/MakeActsGeometry.cc#L478-L483, provide by Joe Osborn. char *calibrationsroot = getenv("CALIBRATIONROOT"); std::string m_magField = "sphenix3dtrackingmapxyz.root"; if (calibrationsroot != nullptr) { - m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; + m_magField = std::string(calibrationsroot) + std::string("/Field/Map/") + m_magField; } - m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING",m_magField); //Joe's New Implementation to get the field map file name on 05/10/2023 + m_magField = CDBInterface::instance()->getUrl("FIELDMAPTRACKING", m_magField); // Joe's New Implementation to get the field map file name on 05/10/2023 - TFile * fin = new TFile(m_magField.c_str()); + TFile *fin = new TFile(m_magField.c_str()); fin->cd(); - TTree * fieldmap = (TTree *) fin->Get("fieldmap"); - TH1F * BzHist = new TH1F("BzHist","",100,0,10); + TTree *fieldmap = (TTree *) fin->Get("fieldmap"); - fieldmap->Project("BzHist","bz","x==0 && y==0 && z==0"); + TH1F *BzHist = new TH1F("BzHist", "", 100, 0, 10); - //The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction - m_Bz = BzHist->GetMean() * 10; //Factor of 10 to convert the B field unit from kG to T + int NBFieldEntries = fieldmap->Project("BzHist", "bz", "x==0 && y==0 && z==0"); - if(BzHist->Integral() == 0) std::cout << "No entry for Bz at (0,0,0)" << std::endl; - if(abs(m_Bz - 14.0) > 2) std::cout << "Bad magnetic field detected: deviation from 1.4 T for more than 0.2 T, probably due to the shift of the magnetic field map" << std::endl; + if (NBFieldEntries != 1) + { // Validate exactly 1 B field value at (0,0,0) in the field map + std::cout << "Not a single B field value at (0,0,0) in the field map, need to check why" << std::endl; + exit(1); + } + + // The actual unit of KFParticle is in kilo Gauss (kG), which is equivalent to 0.1 T, instead of Tesla (T). The positive value indicates the B field is in the +z direction + m_Bz = BzHist->GetMean() * 10; // Factor of 10 to convert the B field unit from kG to T fieldmap->Delete(); BzHist->Delete(); fin->Close(); - + return 0; } @@ -156,7 +160,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - setBz(m_Bz); //Set the Magnetic Field for KFParticle + setBz(m_Bz); // Set the Magnetic Field for KFParticle createDecay(topNode, mother, vertex, daughters, intermediates, nPVs, multiplicity); @@ -274,33 +278,34 @@ int KFParticle_sPHENIX::parseDecayDescriptor() std::string startIntermediate = "{"; std::string endIntermediate = "}"; - //These tracks require a + or - after their name for TDatabasePDG + // These tracks require a + or - after their name for TDatabasePDG std::string specialTracks[] = {"e", "mu", "pi", "K"}; std::string manipulateDecayDescriptor = m_decayDescriptor; - //Remove all white space before we begin + // Remove all white space before we begin size_t pos; while ((pos = manipulateDecayDescriptor.find(" ")) != std::string::npos) manipulateDecayDescriptor.replace(pos, 1, ""); - //Check for charge conjugate requirement + // Check for charge conjugate requirement std::string checkForCC = manipulateDecayDescriptor.substr(0, 1) + manipulateDecayDescriptor.substr(manipulateDecayDescriptor.size() - 3, 3); - std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) { c = ::toupper(c); }); + std::for_each(checkForCC.begin(), checkForCC.end(), [](char &c) + { c = ::toupper(c); }); - //Remove the CC check if needed + // Remove the CC check if needed if (checkForCC == "[]CC") { manipulateDecayDescriptor = manipulateDecayDescriptor.substr(1, manipulateDecayDescriptor.size() - 4); getChargeConjugate(true); } - //Find the initial particle + // Find the initial particle size_t findMotherEndPoint = manipulateDecayDescriptor.find(decayArrow); mother = manipulateDecayDescriptor.substr(0, findMotherEndPoint); if (!findParticle(mother)) ddCanBeParsed = false; manipulateDecayDescriptor.erase(0, findMotherEndPoint + decayArrow.length()); - //Try and find the intermediates + // Try and find the intermediates while ((pos = manipulateDecayDescriptor.find(startIntermediate)) != std::string::npos) { size_t findIntermediateStartPoint = manipulateDecayDescriptor.find(startIntermediate, pos); @@ -313,7 +318,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() else ddCanBeParsed = false; - //Now find the daughters associated to this intermediate + // Now find the daughters associated to this intermediate int nDaughters = 0; intermediateDecay.erase(0, intermediateDecay.find(decayArrow) + decayArrow.length()); while ((daughterLocator = intermediateDecay.find(chargeIndicator)) != std::string::npos) @@ -356,7 +361,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() nTracks += nDaughters; } - //Now find any remaining reconstructable tracks from the mother + // Now find any remaining reconstructable tracks from the mother while ((daughterLocator = manipulateDecayDescriptor.find(chargeIndicator)) != std::string::npos) { daughter = manipulateDecayDescriptor.substr(0, daughterLocator); From 31f69d948272a4d01eee9625f098003c2396b6b5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 16 May 2023 08:48:25 -0400 Subject: [PATCH 383/468] unit bug --- offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index aeff28ab6a..27a9468574 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -237,8 +237,8 @@ void MakeMilleFiles::addTrackToMilleFile(SvtxAlignmentStateMap::StateVec stateve auto para_errors = _ClusErrPara.get_clusterv5_modified_error(clusterv5, clusRadius, ckey); double phierror = sqrt(para_errors.first); double zerror = sqrt(para_errors.second); - clus_sigma(1) = zerror; - clus_sigma(0) = phierror; + clus_sigma(1) = zerror * Acts::UnitConstants::cm; + clus_sigma(0) = phierror * Acts::UnitConstants::cm; } if (std::isnan(clus_sigma(0)) || From 22b8eab48d5d39d15eceae27ec2f75473babc7f9 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Tue, 16 May 2023 13:52:25 -0400 Subject: [PATCH 384/468] Updated DecayFinder and HFTrackEfficiency to handle G4Particle better --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 42 +++++++++++++------ offline/packages/decayfinder/DecayFinder.cc | 9 +++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 9867be931d..4e3019d217 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -81,7 +81,7 @@ int HFTrackEfficiency::process_event(PHCompositeNode *topNode) if (Verbosity() >= VERBOSITY_MORE) std::cout << __FILE__ << ": Missing node G4TruthInfo" << std::endl; } - if (m_decay_descriptor.empty()) + if (m_decay_descriptor.empty() && !m_decayMap->empty()) { getDecayDescriptor(); getNDaughters(); @@ -140,27 +140,32 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) std::vector selectedTracks; CLHEP::HepLorentzVector motherRecoLV; + CLHEP::HepLorentzVector *motherTrueLV = new CLHEP::HepLorentzVector(); + CLHEP::HepLorentzVector *daughterTrueLV = new CLHEP::HepLorentzVector(); - m_genevt = m_geneventmap->get(decay[0].first.first); - assert(m_genevt); + HepMC::GenEvent *theEvent = nullptr; + if (m_geneventmap) + { + m_genevt = m_geneventmap->get(decay[0].first.first); + assert(m_genevt); - HepMC::GenEvent *theEvent = m_genevt->getEvent(); - HepMC::GenParticle *mother = theEvent->barcode_to_particle(decay[0].first.second); - assert(mother); - if (Verbosity() >= VERBOSITY_MORE) mother->print(); + theEvent = m_genevt->getEvent(); + HepMC::GenParticle *mother = theEvent->barcode_to_particle(decay[0].first.second); + assert(mother); + if (Verbosity() >= VERBOSITY_MORE) mother->print(); - m_true_mother_pT = mother->momentum().perp(); - m_true_mother_eta = mother->momentum().eta(); + m_true_mother_pT = mother->momentum().perp(); + m_true_mother_eta = mother->momentum().eta(); + } for (unsigned int i = 1; i < decay.size(); ++i) { if (std::find(std::begin(trackableParticles), std::end(trackableParticles), std::abs(decay[i].second)) != std::end(trackableParticles)) { - HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second); - CLHEP::HepLorentzVector *daughterTrueLV = new CLHEP::HepLorentzVector(); - if (daughterHepMC) + if (theEvent && decay[i].first.second > -1) { + HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second); if (Verbosity() >= VERBOSITY_MORE) daughterHepMC->print(); daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterHepMC->momentum().px(), daughterHepMC->momentum().py(), daughterHepMC->momentum().pz()), getParticleMass(decay[i].second)); @@ -185,6 +190,10 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) { if (Verbosity() >= VERBOSITY_MORE) daughterG4->identify(); + motherTrueLV->setVectM(CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz()), getParticleMass(decay[0].second)); + m_true_mother_pT = motherTrueLV->perp(); + m_true_mother_eta = motherTrueLV->pseudoRapidity(); + daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterG4->get_px(), daughterG4->get_py(), daughterG4->get_pz()), getParticleMass(decay[i].second)); m_true_track_PID[i - 1] = daughterG4->get_pid(); @@ -213,7 +222,14 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_reco_track_exists[i - 1] = true; m_reco_track_pT[i - 1] = m_dst_track->get_pt(); m_reco_track_chi2nDoF[i - 1] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); - m_reco_track_silicon_seeds[i - 1] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); + if (m_dst_track->get_silicon_seed()) + { + m_reco_track_silicon_seeds[i - 1] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); + } + else + { + m_reco_track_silicon_seeds[i - 1] = 0; + } m_reco_track_tpc_seeds[i - 1] = static_cast(m_dst_track->get_tpc_seed()->size_cluster_keys()); m_min_reco_track_pT = std::min(m_reco_track_pT[i - 1], m_min_reco_track_pT); m_max_reco_track_pT = std::max(m_reco_track_pT[i - 1], m_max_reco_track_pT); diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index c1fb96587f..188254165e 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -581,7 +581,14 @@ void DecayFinder::searchGeant4Record(int barcode, int pid, std::vector deca { if (Verbosity() >= VERBOSITY_MAX) std::cout << "This is a child you were looking for" << std::endl; actualDecayProducts.push_back(particleID); - decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(),g4particle->get_barcode()), particleID)); + if (m_geneventmap) + { + decayChain.push_back(std::make_pair(std::make_pair(m_genevt->get_embedding_id(),g4particle->get_barcode()), particleID)); + } + else + { + decayChain.push_back(std::make_pair(std::make_pair(g4particle->get_primary_id(),g4particle->get_barcode()), particleID)); + } } } //Now check if it's part of the other resonance list else if (m_allowPhotons && particleID == 22) continue; From fa65e0da75bb30d952437a67e8f905696fec952b Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 16 May 2023 14:43:43 -0400 Subject: [PATCH 385/468] Updated method to identify diffuse laser flash with high occupancy. Also modified noise subtraction for CM meta-clustering to be more robust with high occupancy --- .../PHTpcCentralMembraneClusterizer.cc | 72 ++++++++++++++++--- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 36 +++++++--- .../tpccalib/PHTpcCentralMembraneMatcher.h | 3 +- 3 files changed, 92 insertions(+), 19 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc index 4559d4a44c..6ce2370f0d 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneClusterizer.cc @@ -111,6 +111,9 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vectorenergy;//vector for energy values of clusters std::vectorisAcrossGap; int nTpcClust = 0; + + double mean_z_content_plus = 0.0; + double mean_z_content_minus = 0.0; //first loop over clusters to make mod phi histograms of each layer and each pair of layers for(const auto& hitsetkey:_cluster_map->getHitSetKeys(TrkrDefs::TrkrId::tpcId)) @@ -140,6 +143,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) hz_pos->Fill(tmp_pos.Z()); + //mean_z_content_plus += tmp_pos.Z(); + hrPhi_reco_petalModulo_pos->Fill(phiMod, tmp_pos.Perp()); hphi_reco_pos[layer-7]->Fill(phiMod); //for layer pairs, if last layer can only go in layer 53-54 pair, if first layer can only go in layer 7-8 pair @@ -149,6 +154,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) hz_neg->Fill(tmp_pos.Z()); + //mean_z_content_minus += tmp_pos.Z(); + hrPhi_reco_petalModulo_neg->Fill(phiMod, tmp_pos.Perp()); hphi_reco_neg[layer-7]->Fill(phiMod); //for layer pairs, if last layer can only go in layer 53-54 pair, if first layer can only go in layer 7-8 pair @@ -159,20 +166,31 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) } } + for(int i=1; iGetNbinsX(); i++){ + mean_z_content_plus += hz_pos->GetBinContent(i); + } + for(int i=1; iGetNbinsX(); i++){ + mean_z_content_minus += hz_neg->GetBinContent(i); + } + + mean_z_content_plus = mean_z_content_plus/hz_pos->GetNbinsX(); + mean_z_content_minus = mean_z_content_minus/hz_neg->GetNbinsX(); + + //use peak in z distributions to identify if there is a CM Flash. Peak should be >20% of entries (needs to be tuned) - if(hz_pos->GetMaximum() < 0.2*hz_pos->GetEntries() || hz_neg->GetMaximum() < 0.2*hz_neg->GetEntries()) return Fun4AllReturnCodes::EVENT_OK; + if(hz_pos->GetMaximum() < 5*mean_z_content_plus || hz_neg->GetMaximum() < 5*mean_z_content_minus) return Fun4AllReturnCodes::EVENT_OK; //loop over histos for each pair of layers, count number of bins above threshold //for a given layer, layer pair with higher average value above threshold will be better match for meta-clustering for(int i=0; i<47; i++){ for(int j=1; jGetNbinsX(); j++){ - if(hphi_reco_pair_pos[i]->GetBinContent(j) > m_metaClusterThreshold){ + if(hphi_reco_pair_pos[i]->GetBinContent(j) > (m_metaClusterThreshold + (mean_z_content_plus/18.0))){ nPairAbove_pos[i]++; - pairAboveContent_pos[i] += (hphi_reco_pair_pos[i]->GetBinContent(j)-m_metaClusterThreshold); + pairAboveContent_pos[i] += (hphi_reco_pair_pos[i]->GetBinContent(j)-(m_metaClusterThreshold + (mean_z_content_plus/18.0))); } - if(hphi_reco_pair_neg[i]->GetBinContent(j) > m_metaClusterThreshold){ + if(hphi_reco_pair_neg[i]->GetBinContent(j) > (m_metaClusterThreshold + (mean_z_content_minus/18.0))){ nPairAbove_neg[i]++; - pairAboveContent_neg[i] += (hphi_reco_pair_neg[i]->GetBinContent(j)-m_metaClusterThreshold); + pairAboveContent_neg[i] += (hphi_reco_pair_neg[i]->GetBinContent(j)-(m_metaClusterThreshold + (mean_z_content_minus/18.0))); } } } @@ -398,6 +416,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) std::vector avepos; std::vector nclusters; std::vector isREdge; + std::vector > pairNums; // int nR2 = 0; //int nR3 = 0; @@ -405,6 +424,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) // double R2AveE = 0.0; //double R3AveE = 0.0; + std::pair tmp_pair; + for (int i=0;iFill(energy[i]); @@ -476,23 +497,33 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) if(isAcrossGap[i] && isAcrossGap[i_pair[i]]) isREdge.push_back(true); else isREdge.push_back(false); + tmp_pair.first = i; + tmp_pair.second = i_pair[i]; + pairNums.push_back(tmp_pair); + + if(Verbosity() > 0) std::cout << " layer i " << layer[i] << " energy " << energy[i] << " pos i " << pos[i].X() << " " << pos[i].Y() << " " << pos[i].Z() << " layer i_pair " << layer[i_pair[i]] << " energy i_pair " << energy[i_pair[i]] << " pos i_pair " << pos[i_pair[i]].X() << " " << pos[i_pair[i]].Y() << " " << pos[i_pair[i]].Z() - << " reco pos " << temppos.x() << " " << temppos.Y() << " " << temppos.Z() - << std::endl; + << " reco pos " << temppos.X() << " " << temppos.Y() << " " << temppos.Z() + << std::endl; } } else { if(_histos) hClustE[2]->Fill(energy[i]); // These single cluster cases have good phi, but do not have a good radius centroid estimate - may want to skip them, record nclusters and identify if across gap // if(layer[i] == 7) isAcrossGap[i] = true; + aveenergy.push_back(energy[i]); avepos.push_back(pos[i]); nclusters.push_back(1); isREdge.push_back(isAcrossGap[i]); + tmp_pair.first = i; + tmp_pair.second = -1; + pairNums.push_back(tmp_pair); + } } @@ -503,7 +534,8 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) for(unsigned int iv = 0; iv setX(avepos[iv].X()); cmfc->setY(avepos[iv].Y()); cmfc->setZ(avepos[iv].Z()); @@ -511,6 +543,28 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) cmfc->setNclusters(nclusters[iv]); cmfc->setIsRGap(isREdge[iv]); + int pair1 = pairNums[iv].first; + int pair2 = pairNums[iv].second; + + cmfc->setX1(pos[pair1].X()); + cmfc->setY1(pos[pair1].Y()); + cmfc->setZ1(pos[pair1].Z()); + cmfc->setLayer1(layer[pair1]); + cmfc->setAdc1(energy[pair1]); + if(pair2 != -1){ + cmfc->setX2(pos[pair2].X()); + cmfc->setY2(pos[pair2].Y()); + cmfc->setZ2(pos[pair2].Z()); + cmfc->setLayer2(layer[pair2]); + cmfc->setAdc2(energy[pair2]); + }else{ + cmfc->setX2(0); + cmfc->setY2(0); + cmfc->setZ2(0); + cmfc->setLayer2(0); + cmfc->setAdc2(0); + } + _corrected_CMcluster_map->addClusterSpecifyKey(iv, cmfc); ++m_cm_clusters; @@ -535,7 +589,7 @@ int PHTpcCentralMembraneClusterizer::process_event(PHCompositeNode *topNode) << " x " << cmclus->getX() << " y " << cmclus->getY() << " z " << cmclus->getZ() << " nclusters " << cmclus->getNclusters() << std::endl; - + if(_histos) { henergy->Fill(cmclus->getAdc()); diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 846805e6fa..59c6e9fa61 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -411,14 +411,25 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) // Do the static + average distortion corrections if the container was found Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); - if( m_dcc_in) pos = m_distortionCorrection.get_corrected_position( pos, m_dcc_in ); + Acts::Vector3 apos1(cmclus->getX1(), cmclus->getY1(), cmclus->getZ1()); + Acts::Vector3 apos2(cmclus->getX2(), cmclus->getY2(), cmclus->getZ2()); + if( m_dcc_in_static){ + pos = m_distortionCorrection.get_corrected_position( pos, m_dcc_in_static ); + apos1 = m_distortionCorrection.get_corrected_position( apos1, m_dcc_in_static ); + apos2 = m_distortionCorrection.get_corrected_position( apos2, m_dcc_in_static ); + } + if( m_dcc_in_average){ + pos = m_distortionCorrection.get_corrected_position( pos, m_dcc_in_average ); + apos1 = m_distortionCorrection.get_corrected_position( apos1, m_dcc_in_average ); + apos2 = m_distortionCorrection.get_corrected_position( apos2, m_dcc_in_average ); + } + + TVector3 tmp_pos(pos[0], pos[1], pos[2]); + TVector3 tmp_pos1(apos1[0], apos1[1], apos1[2]); + TVector3 tmp_pos2(apos2[0], apos2[1], apos2[2]); - TVector3 tmp_pos1(cmclus->getX1(), cmclus->getY1(), cmclus->getZ1()); - TVector3 tmp_pos2(cmclus->getX2(), cmclus->getY2(), cmclus->getZ2()); - - if(nclus == 1 && isRGap) continue; @@ -834,11 +845,18 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } - // input tpc distortion correction - m_dcc_in = findNode::getClass(topNode,"TpcDistortionCorrectionContainerStatic"); - if( m_dcc_in ) + // input tpc distortion correction static + m_dcc_in_static = findNode::getClass(topNode,"TpcDistortionCorrectionContainerStatic"); + if( m_dcc_in_static ) + { + std::cout << "PHTpcCentralMembraneMatcher: found TPC distortion correction container static" << std::endl; + } + + // input tpc distortion correction average + m_dcc_in_average = findNode::getClass(topNode,"TpcDistortionCorrectionContainerAverage"); + if( m_dcc_in_average ) { - std::cout << "PHTpcCentralMembraneMatcher: found TPC distortion correction container" << std::endl; + std::cout << "PHTpcCentralMembraneMatcher: found TPC distortion correction container average" << std::endl; } // create node for results of matching diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h index 4f7ede5593..6d2d4f1308 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.h @@ -78,7 +78,8 @@ class PHTpcCentralMembraneMatcher : public SubsysReco /// static distortion container /** used in input to correct CM clusters before calculating residuals */ - TpcDistortionCorrectionContainer* m_dcc_in{nullptr}; + TpcDistortionCorrectionContainer* m_dcc_in_static{nullptr}; + TpcDistortionCorrectionContainer* m_dcc_in_average{nullptr}; /// fluctuation distortion container /** used in output to write fluctuation distortions */ From 73b2943960379c5f1f5829dc460391f6c6ab6097 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 16 May 2023 16:45:17 -0400 Subject: [PATCH 386/468] clean up interface --- offline/database/sphenixnpc/CDBUtils.cc | 143 +++++++++++++++++++--- offline/database/sphenixnpc/CDBUtils.h | 15 ++- offline/database/sphenixnpc/sphenixnpc.cc | 105 ++++++++++++---- offline/database/sphenixnpc/sphenixnpc.h | 16 ++- 4 files changed, 224 insertions(+), 55 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index fb2bc96176..c3c236578f 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -19,41 +19,53 @@ CDBUtils::CDBUtils(const std::string &globaltag) void CDBUtils::createGlobalTag(const std::string &tagname) { - cdbclient->createThisGlobalTag(tagname); -} - -void CDBUtils::setGlobalTag(const std::string &tagname) -{ - cdbclient->setGlobalTag(const std::string &tagname); + cdbclient->createGlobalTag(tagname); } int CDBUtils::deleteGlobalTag(const std::string &tagname) { - int iret = cdbclient->deleteThisGlobalTag(tagname); + nlohmann::json resp = cdbclient->deleteGlobalTag(tagname); + int iret = resp["code"]; + if (iret != 0) + { + nlohmann::json msgcont = resp["msg"]; + std::cout << "message: " << msgcont << std::endl; + } return iret; } - -void CDBUtils::clearCache() +void CDBUtils::lockGlobalTag(const std::string &tagname) { - cdbclient->clearCache(); + nlohmann::json resp = cdbclient->lockGlobalTag(tagname); + int iret = resp["code"]; + if (iret != 0) + { + nlohmann::json msgcont = resp["msg"]; + std::cout << "message: " << msgcont << std::endl; + } + return; } -std::string CDBUtils::getCalibrationFile(const std::string &type, uint64_t iov) +void CDBUtils::unlockGlobalTag(const std::string &tagname) { - return cdbclient->getCalibrationFile(type, iov); + nlohmann::json resp = cdbclient->unlockGlobalTag(tagname); + int iret = resp["code"]; + if (iret != 0) + { + nlohmann::json msgcont = resp["msg"]; + std::cout << "message: " << msgcont << std::endl; + } + return; } -int CDBUtils::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) +void CDBUtils::clearCache() { - int iret = cdbclient->insertcalib(pl_type, file_url, iov_start); - return iret; + cdbclient->clearCache(); } -int CDBUtils::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) +std::string CDBUtils::getUrl(const std::string &type, uint64_t iov) { - int iret = cdbclient->insertcalib(pl_type, file_url, iov_start,iov_end); - return iret; + return cdbclient->getUrl(type, iov); } int CDBUtils::createDomain(const std::string &domain) @@ -87,7 +99,7 @@ int CDBUtils::createDomain(const std::string &domain) return iret; } -void CDBUtils::ListGlobalTags() +void CDBUtils::listGlobalTags() { nlohmann::json resp = cdbclient->getGlobalTags(); nlohmann::json msgcont = resp["msg"]; @@ -99,3 +111,96 @@ void CDBUtils::ListGlobalTags() return; } +void CDBUtils::listPayloadTypes() +{ + nlohmann::json resp = cdbclient->getPayloadTypes(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_pl = it.value().at("name"); + std::cout << "payload type: " << exist_pl << std::endl; + } + return; +} + +int CDBUtils::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) +{ + if (!isGlobalTagSet()) + { + std::cout << "No Global Tag set" << std::endl; + return -1; + } + nlohmann::json resp = cdbclient->insertPayload(pl_type,file_url,iov_start); + int iret = resp["code"]; + if (iret != 0) + { + std::cout << "Error inserting payload " << file_url << ", msg: " << resp["msg"] << std::endl; + } + else + { + std::cout << resp << std::endl; + } + return iret; +} + +int CDBUtils::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) +{ + if (!isGlobalTagSet()) + { + std::cout << "No Global Tag set" << std::endl; + return -1; + } + nlohmann::json resp = cdbclient->insertPayload(pl_type, file_url, iov_start, iov_end); + int iret = resp["code"]; + if (iret != 0) + { + std::cout << "Error inserting payload " << file_url << ", msg: " << resp["msg"] << std::endl; + } + else + { + std::cout << resp << std::endl; + } + return iret; +} + +int CDBUtils::setGlobalTag(const std::string &tagname) +{ + nlohmann::json resp = cdbclient->setGlobalTag(tagname); + int iret = resp["code"]; + if (iret != 0) + { + std::cout << "Error setting global tag, msg: " << resp["msg"] << std::endl; + } + std::cout << "message: " << resp["msg"] << std::endl; + return iret; +} + +bool CDBUtils::isGlobalTagSet() +{ + return cdbclient->isGlobalTagSet(); +} + +int CDBUtils::createPayloadType(const std::string& pl_type) +{ + if (! isGlobalTagSet()) + { + std::cout << "No Global Tag Set to add payload " << pl_type << " to" << std::endl; + return -1; + } + nlohmann::json resp = cdbclient->createPayloadType(pl_type); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::cout << it.value() << std::endl; + // std::string exist_pl = it.value().at("name"); + // std::cout << "payload type: " << exist_pl << std::endl; + } + + int iret = 0;//resp["code"]; + if (iret != 0) + { + std::cout << "Error setting global tag, msg: " << resp["msg"] << std::endl; + } + return iret; +} +// nlohmann::json ret = insertPayload(pl_type, file_url, 0, iov_start); diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 3bee5ebf9a..df9e55fdf8 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -16,14 +16,19 @@ class CDBUtils CDBUtils(const std::string &globaltag); virtual ~CDBUtils() = default; void createGlobalTag(const std::string &tagname); - void setGlobalTag(const std::string &tagname); + int setGlobalTag(const std::string &tagname); + void lockGlobalTag(const std::string &tagname); + void unlockGlobalTag(const std::string &tagname); int createDomain(const std::string &domain); - std::string getCalibrationFile(const std::string &type, uint64_t iov); - int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); - int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); + std::string getUrl(const std::string &type, uint64_t iov); + int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); + int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); int deleteGlobalTag(const std::string &); - void ListGlobalTags(); + void listGlobalTags(); + void listPayloadTypes(); void clearCache(); + bool isGlobalTagSet(); + int createPayloadType(const std::string& pl_type); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index bf7e3d80fa..7ba789ed87 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -15,10 +15,33 @@ sphenixnpc::sphenixnpc(const std::string &globaltag) } -int sphenixnpc::createThisGlobalTag(const std::string &tagname) +nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) { - setGlobalTag(tagname); - nlohmann::json resp = nopayloadclient::Client::createGlobalTag(); + if (tagname == m_CachedGlobalTag) // global tag already set + { + std::string message = "global tag already set to " + tagname; + return {{"code", 0}, {"msg", message}}; + } +// check if the global tag exists already + bool found_gt = false; + nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_gt = it.value().at("name"); + std::cout << "global tag: " << exist_gt << std::endl; + if (exist_gt == tagname) + { + found_gt = true; + break; + } + } + if (found_gt) + { + std::string message = "global tag " + tagname + " already exists"; + return {{"code", 0}, {"msg", message}}; + } + resp = nopayloadclient::Client::createGlobalTag(tagname); int iret = resp["code"]; if (iret != 0) { @@ -26,20 +49,12 @@ int sphenixnpc::createThisGlobalTag(const std::string &tagname) } else { + nopayloadclient::Client::setGlobalTag(tagname); + m_CachedGlobalTag = tagname; + clearCache(); std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; } - return iret; -} - -int sphenixnpc::deleteThisGlobalTag(const std::string &tagname) -{ - setGlobalTag(tagname); - nlohmann::json result = nopayloadclient::Client::deleteGlobalTag(); - if (Verbosity()) - { - std::cout << result << std::endl; - } - return 0; + return resp; } nlohmann::json sphenixnpc::getUrlDict(long long iov) @@ -73,6 +88,37 @@ nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) return makeResp(url_dict_[pl_type]); } +nlohmann::json sphenixnpc::setGlobalTag(const std::string &tagname) +{ + if (tagname == m_CachedGlobalTag) // global tag already set + { + std::string message = "global tag already set to " + tagname; + return {{"code", 0}, {"msg", message}}; + } + url_dict_ = nlohmann::json{}; + bool found_gt = false; + nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_gt = it.value().at("name"); + std::cout << "global tag: " << exist_gt << std::endl; + if (exist_gt == tagname) + { + found_gt = true; + break; + } + } + if (found_gt) + { + m_CachedGlobalTag = tagname; + resp = nopayloadclient::Client::setGlobalTag(tagname); + return resp; + } +std::string message = "global tag " + tagname + " does not exist"; + return {{"code", -1}, {"msg", message}}; +} + int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) { int iret = 0; @@ -118,8 +164,13 @@ nlohmann::json sphenixnpc::clearCache() return nopayloadclient::Client::clearCache(); } -std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov) +std::string sphenixnpc::getUrl(const std::string &type, uint64_t iov) { + if (iov != m_CachedIOV) + { + clearCache(); + m_CachedIOV = iov; + } nlohmann::json result = get(type, iov); std::string fullUrl = result.at("msg"); if (fullUrl.find("Exception") != std::string::npos) @@ -133,24 +184,24 @@ std::string sphenixnpc::getCalibrationFile(const std::string &type, uint64_t iov return fullUrl; } -int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) +nlohmann::json sphenixnpc::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) { - nlohmann::json ret = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); + nlohmann::json resp = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); if (Verbosity()) { - std::cout << ret << std::endl; + std::cout << resp << std::endl; } - return 0; + return resp; } -int sphenixnpc::insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) +nlohmann::json sphenixnpc::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) { nlohmann::json ret = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); if (Verbosity()) { std::cout << ret << std::endl; } - return 0; + return ret; } int sphenixnpc::createDomain(const std::string &domain) @@ -182,3 +233,13 @@ int sphenixnpc::createDomain(const std::string &domain) } return iret; } + +bool sphenixnpc::isGlobalTagSet() +{ + if (m_CachedGlobalTag.empty()) + { + return false; + } + return true; +} + diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 12c5e8c42d..5cdb5daef3 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -13,29 +13,27 @@ class sphenixnpc : public nopayloadclient::Client { public: - using nopayloadclient::Client::createGlobalTag; - using nopayloadclient::Client::deleteGlobalTag; - using nopayloadclient::Client::setGlobalTag; sphenixnpc(); sphenixnpc(const std::string &globaltag); virtual ~sphenixnpc() = default; nlohmann::json getUrlDict(long long iov); nlohmann::json getUrlDict(long long iov1, long long iov2) override; - int createThisGlobalTag(const std::string &tagname); + nlohmann::json createGlobalTag(const std::string &tagname) override; int createDomain(const std::string &domain); + nlohmann::json setGlobalTag(const std::string &tagname) override; nlohmann::json get(const std::string &pl_type, long long iov); int cache_set_GlobalTag(const std::string &name); nlohmann::json clearCache() override; - std::string getCalibrationFile(const std::string &type, uint64_t iov); - int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); - int insertcalib(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); - int deleteThisGlobalTag(const std::string &); - + std::string getUrl(const std::string &type, uint64_t iov); + nlohmann::json insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); + nlohmann::json insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); + bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } private: int m_Verbosity = 0; + uint64_t m_CachedIOV = 0; nlohmann::json url_dict_; // valid until global tag is switched std::string m_CachedGlobalTag; std::set m_DomainCache; From f3edc3d68779e25000511bddf3b4026eccf2df1a Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 16 May 2023 17:22:11 -0400 Subject: [PATCH 387/468] Creating TPCPedestalCalibration module Reads info directly from PRDF files and converts it into root file containing channel-wise alive/dead information and pedestal mean and rms values --- .../tpc/TPCPedestalCalibration/Makefile.am | 42 ++++ .../TPCPedestalCalibration.cc | 201 ++++++++++++++++++ .../TPCPedestalCalibration.h | 69 ++++++ .../tpc/TPCPedestalCalibration/autogen.sh | 8 + .../tpc/TPCPedestalCalibration/configure.ac | 16 ++ 5 files changed, 336 insertions(+) create mode 100644 calibrations/tpc/TPCPedestalCalibration/Makefile.am create mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc create mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h create mode 100755 calibrations/tpc/TPCPedestalCalibration/autogen.sh create mode 100644 calibrations/tpc/TPCPedestalCalibration/configure.ac diff --git a/calibrations/tpc/TPCPedestalCalibration/Makefile.am b/calibrations/tpc/TPCPedestalCalibration/Makefile.am new file mode 100644 index 0000000000..0b48126b8f --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/Makefile.am @@ -0,0 +1,42 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -I$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + TPCPedestalCalibration.h + +lib_LTLIBRARIES = \ + libTPCPedestalCalibration.la + +libTPCPedestalCalibration_la_SOURCES = \ + TPCPedestalCalibration.cc + +libTPCPedestalCalibration_la_LIBADD = \ + -lphool \ + -lSubsysReco + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libTPCPedestalCalibration.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc new file mode 100644 index 0000000000..2a3a0ad06b --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc @@ -0,0 +1,201 @@ +#include "TPCPedestalCalibration.h" + +#include +#include +#include // for PHIODataNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/*************************************************************/ +/* TPC Pedestal Calibration */ +/* Thomas Marshall,Aditya Dash */ +/* rosstom@ucla.edu,aditya55@physics.ucla.edu */ +/*************************************************************/ + +TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) + :SubsysReco(name) + , m_fname(name) +{ + std::cout << "TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) Calling ctor" << std::endl; + // reserve memory for max ADC samples + m_adcSamples.resize(1024, 0); +} + +int TPCPedestalCalibration::InitRun(PHCompositeNode *topNode) +{ + m_file = TFile::Open(m_fname.c_str(), "recreate"); + assert(m_file->IsOpen()); + + TTree* m_pedestalTree=new TTree("pedestalTree","Each entry is one TPC Channel"); + + m_pedestalTree->Branch("isAlive",&m_isAlive,"isAlive/I"); + m_pedestalTree->Branch("pedMean",&m_pedMean,"pedMean/F"); + m_pedestalTree->Branch("pedStd",&m_pedStd,"pedStd/F"); + m_pedestalTree->Branch("sector",&m_sector,"sector/I"); + m_pedestalTree->Branch("fee",&m_outFEE,"fee/I"); + m_pedestalTree->Branch("channel",&m_chan,"channel/I"); + m_pedestalTree->Branch("module",&m_module,"module/I"); + m_pedestalTree->Branch("slot",&m_slot,"slot/I"); + + for(int fee_no=0;fee_no<26;fee_no++) + { + for(int channel_no=0;channel_no<256;channel_no++) + { + m_aveADCFeeChannel[fee_no][channel_no]=0.0; + m_stdADCFeeChannel[fee_no][channel_no]=0.0; + m_countsADCFeeChannel[fee_no][channel_no]=0.0; + m_aliveArrayFeeChannel[fee_no][channel_no]=1; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) +{ + std::cout << "TPCPedestalCalibration::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + + Event *_event = findNode::getClass(topNode, "PRDF"); + if (_event == nullptr) + { + std::cout << "TPCRawDataTree::Process_Event - Event not found" << std::endl; + return -1; + } + if (_event->getEvtType() >= 8) /// special events + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + + for (int packet : m_packets) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : decoding packet " << packet << std::endl; + } + + m_packet = packet; + + Packet *p = _event->getPacket(m_packet); + if (!p) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : missing packet " << packet << std::endl; + } + + assert(p); + + continue; + } + + m_nWaveormInFrame = p->iValue(0, "NR_WF"); + + for (int wf = 0; wf < m_nWaveormInFrame; wf++) + { + m_nSamples = p->iValue(wf, "SAMPLES"); + m_fee = p->iValue(wf, "FEE"); + m_Channel = p->iValue(wf, "CHANNEL"); + + if(m_nSamples==0) + { + m_aliveArrayFeeChannel[m_fee][m_Channel]=0; + continue; + } + + assert(m_nSamples < (int) m_adcSamples.size()); // no need for movements in memory allocation + for (int s = 0; s < m_nSamples; s++) + { + m_adcSamples[s] = p->iValue(wf, s); + } + + bool dead = false; + for(int adc_sam_no=0;adc_sam_no 200 || m_aveADCFeeChannel[fee_no][channel_no] < 10) + { + m_aliveArrayFeeChannel[fee_no][channel_no]=0; + } + + m_pedMean=m_aveADCFeeChannel[fee_no][channel_no]; + m_pedStd=sqrt(m_stdADCFeeChannel[fee_no][channel_no] - pow(m_aveADCFeeChannel[fee_no][channel_no],2)); + m_isAlive=m_aliveArrayFeeChannel[fee_no][channel_no]; + m_chan=channel_no; + m_outFEE=fee_no; + m_module=mod_arr[fee_no]; + m_slot=slot_arr[fee_no]; + m_pedestalTree->Fill(); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TPCPedestalCalibration::End(PHCompositeNode *topNode) +{ + std::cout << "TPCPedestalCalibration::End(PHCompositeNode *topNode) This is the End..." << std::endl; + + m_file->Write(); + + std::cout << __PRETTY_FUNCTION__ << " : completed saving to " << m_file->GetName() << std::endl; + m_file->ls(); + + m_file->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h new file mode 100644 index 0000000000..4c7d9882ad --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h @@ -0,0 +1,69 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TPCPEDESTALCALIBRATION_H +#define TPCPEDESTALCALIBRATION_H + +#include + +#include +#include + +class PHCompositeNode; +class TFile; +class TTree; + +class TPCPedestalCalibration : public SubsysReco +{ + public: + explicit TPCPedestalCalibration(const std::string &name = "TPCPedestalCalibration.root"); + + ~TPCPedestalCalibration() override {}; + + int InitRun(PHCompositeNode *topNode) override; + + int process_event(PHCompositeNode *topNode) override; + + int EndRun(const int runnumber) override; + + int End(PHCompositeNode *topNode) override; + + void AddPacket(int packet) + { + m_packets.push_back(packet); + } + + protected: + //! which packet to decode + std::vector m_packets{1001}; + + private: + std::string m_fname; + TFile * m_file = nullptr; + TTree * m_pedestalTree = nullptr; + + int m_packet = 0; + int m_nWaveormInFrame = 0; + int m_nSamples = 0; + int m_fee = 0; + int m_Channel = 0; + std::vector m_adcSamples; + + float m_aveADCFeeChannel[26][256]; + float m_stdADCFeeChannel[26][256]; + float m_countsADCFeeChannel[26][256]; + int m_aliveArrayFeeChannel[26][256]; + + int m_isAlive = 1; + float m_pedMean = 0; + float m_pedStd = 0; + int m_sector = 0; + int m_outFEE = 99; + int m_chan = 999; + int m_module = 9; + int m_slot = 99; + + int mod_arr[26]={2,2,1,1,1,3,3,3,3,3,3,2,2,1,2,2,1,1,2,2,3,3,3,3,3,3}; + int slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; +}; + +#endif // TPCPEDESTALCALIBRATION_H diff --git a/calibrations/tpc/TPCPedestalCalibration/autogen.sh b/calibrations/tpc/TPCPedestalCalibration/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/tpc/TPCPedestalCalibration/configure.ac b/calibrations/tpc/TPCPedestalCalibration/configure.ac new file mode 100644 index 0000000000..a3d4486d54 --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(tpcpedestalcalibration,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT From c2973c8f4a7f7a3b8f7ef6e3474a943a0648662f Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 16 May 2023 17:56:41 -0400 Subject: [PATCH 388/468] Fixed a couple minor issues in the .cc and .h files --- .../TPCPedestalCalibration.cc | 15 +++++---------- .../TPCPedestalCalibration.h | 8 ++++---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc index 2a3a0ad06b..836e28bfad 100644 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc @@ -12,9 +12,9 @@ #include #include +#include #include #include -#include #include #include @@ -27,20 +27,19 @@ /*************************************************************/ TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) - :SubsysReco(name) + :SubsysReco("TPCPedestalCalibration") , m_fname(name) { - std::cout << "TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) Calling ctor" << std::endl; // reserve memory for max ADC samples m_adcSamples.resize(1024, 0); } -int TPCPedestalCalibration::InitRun(PHCompositeNode *topNode) +int TPCPedestalCalibration::InitRun(PHCompositeNode *) { m_file = TFile::Open(m_fname.c_str(), "recreate"); assert(m_file->IsOpen()); - TTree* m_pedestalTree=new TTree("pedestalTree","Each entry is one TPC Channel"); + m_pedestalTree = new TTree("pedestalTree", "Each entry is one TPC Channel"); m_pedestalTree->Branch("isAlive",&m_isAlive,"isAlive/I"); m_pedestalTree->Branch("pedMean",&m_pedMean,"pedMean/F"); @@ -68,8 +67,6 @@ int TPCPedestalCalibration::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) { - std::cout << "TPCPedestalCalibration::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; - Event *_event = findNode::getClass(topNode, "PRDF"); if (_event == nullptr) { @@ -90,7 +87,7 @@ int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) m_packet = packet; - Packet *p = _event->getPacket(m_packet); + std::unique_ptr p (_event->getPacket(m_packet)); if (!p) { if (Verbosity()) @@ -98,8 +95,6 @@ int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) std::cout << __PRETTY_FUNCTION__ << " : missing packet " << packet << std::endl; } - assert(p); - continue; } diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h index 4c7d9882ad..fd11c4facf 100644 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef TPCPEDESTALCALIBRATION_H -#define TPCPEDESTALCALIBRATION_H +#ifndef TPCPedestalCalibration_H +#define TPCPedestalCalibration_H #include @@ -17,7 +17,7 @@ class TPCPedestalCalibration : public SubsysReco public: explicit TPCPedestalCalibration(const std::string &name = "TPCPedestalCalibration.root"); - ~TPCPedestalCalibration() override {}; + ~TPCPedestalCalibration() override {} int InitRun(PHCompositeNode *topNode) override; @@ -66,4 +66,4 @@ class TPCPedestalCalibration : public SubsysReco int slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; }; -#endif // TPCPEDESTALCALIBRATION_H +#endif // TPCPedestalCalibration_H From 27edb665133770bb33beafd155b0ee387f680969 Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 16 May 2023 18:07:01 -0400 Subject: [PATCH 389/468] Revert "Adding the TPC pedestal calibration module" This reverts commit 6436049b9fe147830c58b9bb0d2eccacbff021d3. --- .../tpc/pedestalcalibration/README.md | 22 --- .../TPCPedestalCalibration.C | 147 ------------------ .../run_TPCPedestalCalibration.sh | 12 -- 3 files changed, 181 deletions(-) delete mode 100644 calibrations/tpc/pedestalcalibration/README.md delete mode 100644 calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C delete mode 100644 calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh diff --git a/calibrations/tpc/pedestalcalibration/README.md b/calibrations/tpc/pedestalcalibration/README.md deleted file mode 100644 index 23236c2cab..0000000000 --- a/calibrations/tpc/pedestalcalibration/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Procedure for processing PRDF pedestal run files: - -* Make sure you have locally installed the TPCRawDataTree module located at analysis/TPC/DAQ/TPCRawDataTree/ -* Edit the `Fun4All_TPC_UnpackPRDF.C` macro to point the outDir variable to whichever directory you'd like to store the output root files in. The macro is located in the `analysis/TPC/DAQ/macros/` directory -* Run the `run_UnpackPRDF.sh` shell script with all files you want to process as an argument, making sure to set the number of events variable in the shell script to be however many events you need. An example of running the script for all TPC sectors in run 10151: - -``` -source run_UnpackPRDF.sh /sphenix/user/jinhuang/TPC/commissioning/pedestal/TPC_ebdc*_pedestal-00010151-0000.prdf -``` - -Procedure for creating plots of each sectors dead channels, pedestal mean, and pedestal rms: -* Edit the `TPC_Channel_QA.C` macro to have the `runNumber` string be the name of the file run you want to process and edit the `fileName` to match wherever you have stored the output root files from processing the PRDFs using TPCRawDataTree as above. Also edit the `saveName` variable at the end of the file to point to wherever you'd like the png images to be stored instead of just an `images` directory wherever you're running the macro -* Run `TPC_Channel_QA.C` with `root -l TPC_Channel_QA.C` and you'll generate 24 pngs, one for each sector in the TPC - -Procedure for making root file containing channel averaged pedestal info: -* Run the `run_TPCPedestalCalibration.sh` script from the command line with all root files (output from converting the PRDF files) you want to process as an argument. Example for processing all TPC sectors from run 10151: -``` -source run_TPCPedestalCalibration.sh /sphenix/user/rosstom/test/testFiles/TPC_ebdc*_pedestal-00010151-0000.prdf_TPCRawDataTree.root -``` -* Should produce a new root file for each sector's channels with information about each channel's alive/dead status, pedestal mean, and pedestal rms - -If you have any questions, send Thomas Marshall (@rosstom, rosstom@ucla.edu) or Aditya Dash (@adityadash, adityaprasaddash55@gmail.com) a message on mattermost or over email diff --git a/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C b/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C deleted file mode 100644 index a2ad9f89a2..0000000000 --- a/calibrations/tpc/pedestalcalibration/TPCPedestalCalibration.C +++ /dev/null @@ -1,147 +0,0 @@ -#include -#include -#include -#include -#include - -#include "TChain.h" -#include "TFile.h" -#include "TTree.h" -#include "TString.h" -#include "TObjString.h" -#include "TSystem.h" -#include "TROOT.h" -#include "TTreeReader.h" -#include "TTreeReaderValue.h" -#include "TTreeReaderArray.h" - -/*************************************************************/ -/* TPC Pedestal Calibration */ -/* Thomas Marshall,Aditya Dash */ -/* rosstom@ucla.edu,aditya55@physics.ucla.edu */ -/*************************************************************/ - -void TPCPedestalCalibration(vector inputFiles = {"/sphenix/user/rosstom/test/testFiles/TPC_ebdc00_pedestal-00010131-0000.prdf_TPCRawDataTree.root"}){ - for (int fileNum = 0; fileNum < inputFiles.size(); fileNum++){ - string sectorNum = inputFiles[fileNum]; - size_t pos = sectorNum.find("ebdc"); - sectorNum.erase(pos+6); - sectorNum.erase(sectorNum.begin(),sectorNum.begin()+pos+4); - Int_t sector; - if (sectorNum.substr(0,1) == "0") - { - sectorNum.erase(sectorNum.begin(),sectorNum.end()-1); - sector = std::stoi(sectorNum); - } - else sector = std::stoi(sectorNum); - - Int_t mod_arr[26]={2,2,1,1,1,3,3,3,3,3,3,2,2,1,2,2,1,1,2,2,3,3,3,3,3,3}; - Int_t slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; - - TFile *pedestalInput = TFile::Open(inputFiles[fileNum].c_str()); - TTreeReader myReader("SampleTree", pedestalInput); - - TTreeReaderValue nSamples_in(myReader, "nSamples"); - TTreeReaderValue fee_in(myReader, "fee"); - TTreeReaderArray adcSamples_in(myReader, "adcSamples"); - TTreeReaderValue Channel_in(myReader, "Channel"); - -//Adding the output tree - TString* outputfilename=new TString("pedestalCalibration_TPC_ebdc"+sectorNum+".root"); - TFile* outputfile=new TFile(outputfilename->Data(),"recreate"); - TTree* outputTree=new TTree("outputTree","outputTree"); - Int_t isAlive=1; // 1 if the channel is working properly, 0 if no signal(number of samples is 0, adc value is 0 or nan), pedestal above 200 or below 10 - Float_t pedMean; // average pedestal value over all samples - Float_t pedStd; // pedestal standard deviation over all samples - Int_t chan; // channel number - Int_t fee; // fee number - Int_t module; // module number (e.g. R1, R2, R3) - Int_t slot; // slot number - outputTree->Branch("isAlive",&isAlive,"isAlive/I"); - outputTree->Branch("pedMean",&pedMean,"pedMean/F"); - outputTree->Branch("pedStd",&pedStd,"pedStd/F"); - outputTree->Branch("sector",§or,"sector/I"); - outputTree->Branch("fee",&fee,"fee/I"); - outputTree->Branch("chan",&chan,"chan/I"); - outputTree->Branch("module",&module,"module/I"); - outputTree->Branch("slot",&slot,"slot/I"); - - Float_t ave_adc_fee_channel[26][256]; - Float_t std_adc_fee_channel[26][256]; - Float_t counts_adc_fee_channel[26][256]; - Int_t alive_array_fee_channel[26][256]; - for(int fee_no=0;fee_no<26;fee_no++){ - for(int channel_no=0;channel_no<256;channel_no++) - { - ave_adc_fee_channel[fee_no][channel_no]=0.0; - std_adc_fee_channel[fee_no][channel_no]=0.0; - counts_adc_fee_channel[fee_no][channel_no]=0.0; - alive_array_fee_channel[fee_no][channel_no]=1; - } - } - - while(myReader.Next()) - { - if(*nSamples_in==0) - { - alive_array_fee_channel[*fee_in][*Channel_in]=0; - continue; - } - - bool dead = false; - for(int adc_sam_no=0;adc_sam_no<*nSamples_in;adc_sam_no++) - { - if (adcSamples_in[adc_sam_no] == 0 || TMath::IsNaN(float(adcSamples_in[adc_sam_no]))) - { - alive_array_fee_channel[*fee_in][*Channel_in]=0; - } - } - if (dead) {continue;} - - for(int adc_sam_no=0;adc_sam_no<*nSamples_in;adc_sam_no++){ - ave_adc_fee_channel[*fee_in][*Channel_in]+=adcSamples_in[adc_sam_no]; - std_adc_fee_channel[*fee_in][*Channel_in]+=pow(adcSamples_in[adc_sam_no],2); - counts_adc_fee_channel[*fee_in][*Channel_in]+=1.0; - } - - } - - for(int fee_no=0;fee_no<26;fee_no++) - { - for(int channel_no=0;channel_no<256;channel_no++) - { - if(counts_adc_fee_channel[fee_no][channel_no] != 0.0) - { - float temp1 = ave_adc_fee_channel[fee_no][channel_no]/counts_adc_fee_channel[fee_no][channel_no]; - float temp2 = std_adc_fee_channel[fee_no][channel_no]/counts_adc_fee_channel[fee_no][channel_no]; - ave_adc_fee_channel[fee_no][channel_no] = temp1; - std_adc_fee_channel[fee_no][channel_no] = temp2; - } - else - { - ave_adc_fee_channel[fee_no][channel_no] = 0.0; - std_adc_fee_channel[fee_no][channel_no] = 0.0; - alive_array_fee_channel[fee_no][channel_no]=0; - } - - if(ave_adc_fee_channel[fee_no][channel_no] > 200 || ave_adc_fee_channel[fee_no][channel_no] < 10) - { - alive_array_fee_channel[fee_no][channel_no]=0; - } - - pedMean=ave_adc_fee_channel[fee_no][channel_no]; - pedStd=sqrt(std_adc_fee_channel[fee_no][channel_no] - pow(ave_adc_fee_channel[fee_no][channel_no],2)); - isAlive=alive_array_fee_channel[fee_no][channel_no]; - chan=channel_no; - fee=fee_no; - module=mod_arr[fee_no]; - slot=slot_arr[fee_no]; - outputTree->Fill(); - } - } - outputfile->cd(); - outputTree->Write(); - outputfile->Close(); - pedestalInput->Close(); - } -} diff --git a/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh b/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh deleted file mode 100644 index b7d9aab7ee..0000000000 --- a/calibrations/tpc/pedestalcalibration/run_TPCPedestalCalibration.sh +++ /dev/null @@ -1,12 +0,0 @@ -source /opt/sphenix/core/bin/sphenix_setup.sh -n new - -inputFiles="{" -for fileList in $@ -do - inputFiles+="\"${fileList}\"," -done -inputFiles=${inputFiles::-1} -inputFiles+="}" -echo running: run_TPCPedestalCalibration.sh $* -root.exe -q -b TPCPedestalCalibration.C\(${inputFiles}\) -echo Script done From 406bc5b6129848c93e616a78080a9c20242c6f74 Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 16 May 2023 18:09:39 -0400 Subject: [PATCH 390/468] Revert "Creating TPCPedestalCalibration module" This reverts commit f3edc3d68779e25000511bddf3b4026eccf2df1a. --- .../tpc/TPCPedestalCalibration/Makefile.am | 42 ---- .../TPCPedestalCalibration.cc | 196 ------------------ .../TPCPedestalCalibration.h | 69 ------ .../tpc/TPCPedestalCalibration/autogen.sh | 8 - .../tpc/TPCPedestalCalibration/configure.ac | 16 -- 5 files changed, 331 deletions(-) delete mode 100644 calibrations/tpc/TPCPedestalCalibration/Makefile.am delete mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc delete mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h delete mode 100755 calibrations/tpc/TPCPedestalCalibration/autogen.sh delete mode 100644 calibrations/tpc/TPCPedestalCalibration/configure.ac diff --git a/calibrations/tpc/TPCPedestalCalibration/Makefile.am b/calibrations/tpc/TPCPedestalCalibration/Makefile.am deleted file mode 100644 index 0b48126b8f..0000000000 --- a/calibrations/tpc/TPCPedestalCalibration/Makefile.am +++ /dev/null @@ -1,42 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = \ - -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include - -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 - -pkginclude_HEADERS = \ - TPCPedestalCalibration.h - -lib_LTLIBRARIES = \ - libTPCPedestalCalibration.la - -libTPCPedestalCalibration_la_SOURCES = \ - TPCPedestalCalibration.cc - -libTPCPedestalCalibration_la_LIBADD = \ - -lphool \ - -lSubsysReco - -BUILT_SOURCES = testexternals.cc - -noinst_PROGRAMS = \ - testexternals - -testexternals_SOURCES = testexternals.cc -testexternals_LDADD = libTPCPedestalCalibration.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ - -clean-local: - rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc deleted file mode 100644 index 836e28bfad..0000000000 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc +++ /dev/null @@ -1,196 +0,0 @@ -#include "TPCPedestalCalibration.h" - -#include -#include -#include // for PHIODataNode -#include // for PHNodeIterator -#include // for PHObject -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -/*************************************************************/ -/* TPC Pedestal Calibration */ -/* Thomas Marshall,Aditya Dash */ -/* rosstom@ucla.edu,aditya55@physics.ucla.edu */ -/*************************************************************/ - -TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) - :SubsysReco("TPCPedestalCalibration") - , m_fname(name) -{ - // reserve memory for max ADC samples - m_adcSamples.resize(1024, 0); -} - -int TPCPedestalCalibration::InitRun(PHCompositeNode *) -{ - m_file = TFile::Open(m_fname.c_str(), "recreate"); - assert(m_file->IsOpen()); - - m_pedestalTree = new TTree("pedestalTree", "Each entry is one TPC Channel"); - - m_pedestalTree->Branch("isAlive",&m_isAlive,"isAlive/I"); - m_pedestalTree->Branch("pedMean",&m_pedMean,"pedMean/F"); - m_pedestalTree->Branch("pedStd",&m_pedStd,"pedStd/F"); - m_pedestalTree->Branch("sector",&m_sector,"sector/I"); - m_pedestalTree->Branch("fee",&m_outFEE,"fee/I"); - m_pedestalTree->Branch("channel",&m_chan,"channel/I"); - m_pedestalTree->Branch("module",&m_module,"module/I"); - m_pedestalTree->Branch("slot",&m_slot,"slot/I"); - - for(int fee_no=0;fee_no<26;fee_no++) - { - for(int channel_no=0;channel_no<256;channel_no++) - { - m_aveADCFeeChannel[fee_no][channel_no]=0.0; - m_stdADCFeeChannel[fee_no][channel_no]=0.0; - m_countsADCFeeChannel[fee_no][channel_no]=0.0; - m_aliveArrayFeeChannel[fee_no][channel_no]=1; - } - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) -{ - Event *_event = findNode::getClass(topNode, "PRDF"); - if (_event == nullptr) - { - std::cout << "TPCRawDataTree::Process_Event - Event not found" << std::endl; - return -1; - } - if (_event->getEvtType() >= 8) /// special events - { - return Fun4AllReturnCodes::DISCARDEVENT; - } - - for (int packet : m_packets) - { - if (Verbosity()) - { - std::cout << __PRETTY_FUNCTION__ << " : decoding packet " << packet << std::endl; - } - - m_packet = packet; - - std::unique_ptr p (_event->getPacket(m_packet)); - if (!p) - { - if (Verbosity()) - { - std::cout << __PRETTY_FUNCTION__ << " : missing packet " << packet << std::endl; - } - - continue; - } - - m_nWaveormInFrame = p->iValue(0, "NR_WF"); - - for (int wf = 0; wf < m_nWaveormInFrame; wf++) - { - m_nSamples = p->iValue(wf, "SAMPLES"); - m_fee = p->iValue(wf, "FEE"); - m_Channel = p->iValue(wf, "CHANNEL"); - - if(m_nSamples==0) - { - m_aliveArrayFeeChannel[m_fee][m_Channel]=0; - continue; - } - - assert(m_nSamples < (int) m_adcSamples.size()); // no need for movements in memory allocation - for (int s = 0; s < m_nSamples; s++) - { - m_adcSamples[s] = p->iValue(wf, s); - } - - bool dead = false; - for(int adc_sam_no=0;adc_sam_no 200 || m_aveADCFeeChannel[fee_no][channel_no] < 10) - { - m_aliveArrayFeeChannel[fee_no][channel_no]=0; - } - - m_pedMean=m_aveADCFeeChannel[fee_no][channel_no]; - m_pedStd=sqrt(m_stdADCFeeChannel[fee_no][channel_no] - pow(m_aveADCFeeChannel[fee_no][channel_no],2)); - m_isAlive=m_aliveArrayFeeChannel[fee_no][channel_no]; - m_chan=channel_no; - m_outFEE=fee_no; - m_module=mod_arr[fee_no]; - m_slot=slot_arr[fee_no]; - m_pedestalTree->Fill(); - } - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int TPCPedestalCalibration::End(PHCompositeNode *topNode) -{ - std::cout << "TPCPedestalCalibration::End(PHCompositeNode *topNode) This is the End..." << std::endl; - - m_file->Write(); - - std::cout << __PRETTY_FUNCTION__ << " : completed saving to " << m_file->GetName() << std::endl; - m_file->ls(); - - m_file->Close(); - - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h deleted file mode 100644 index fd11c4facf..0000000000 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h +++ /dev/null @@ -1,69 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef TPCPedestalCalibration_H -#define TPCPedestalCalibration_H - -#include - -#include -#include - -class PHCompositeNode; -class TFile; -class TTree; - -class TPCPedestalCalibration : public SubsysReco -{ - public: - explicit TPCPedestalCalibration(const std::string &name = "TPCPedestalCalibration.root"); - - ~TPCPedestalCalibration() override {} - - int InitRun(PHCompositeNode *topNode) override; - - int process_event(PHCompositeNode *topNode) override; - - int EndRun(const int runnumber) override; - - int End(PHCompositeNode *topNode) override; - - void AddPacket(int packet) - { - m_packets.push_back(packet); - } - - protected: - //! which packet to decode - std::vector m_packets{1001}; - - private: - std::string m_fname; - TFile * m_file = nullptr; - TTree * m_pedestalTree = nullptr; - - int m_packet = 0; - int m_nWaveormInFrame = 0; - int m_nSamples = 0; - int m_fee = 0; - int m_Channel = 0; - std::vector m_adcSamples; - - float m_aveADCFeeChannel[26][256]; - float m_stdADCFeeChannel[26][256]; - float m_countsADCFeeChannel[26][256]; - int m_aliveArrayFeeChannel[26][256]; - - int m_isAlive = 1; - float m_pedMean = 0; - float m_pedStd = 0; - int m_sector = 0; - int m_outFEE = 99; - int m_chan = 999; - int m_module = 9; - int m_slot = 99; - - int mod_arr[26]={2,2,1,1,1,3,3,3,3,3,3,2,2,1,2,2,1,1,2,2,3,3,3,3,3,3}; - int slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; -}; - -#endif // TPCPedestalCalibration_H diff --git a/calibrations/tpc/TPCPedestalCalibration/autogen.sh b/calibrations/tpc/TPCPedestalCalibration/autogen.sh deleted file mode 100755 index dea267bbfd..0000000000 --- a/calibrations/tpc/TPCPedestalCalibration/autogen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) - -$srcdir/configure "$@" diff --git a/calibrations/tpc/TPCPedestalCalibration/configure.ac b/calibrations/tpc/TPCPedestalCalibration/configure.ac deleted file mode 100644 index a3d4486d54..0000000000 --- a/calibrations/tpc/TPCPedestalCalibration/configure.ac +++ /dev/null @@ -1,16 +0,0 @@ -AC_INIT(tpcpedestalcalibration,[1.00]) -AC_CONFIG_SRCDIR([configure.ac]) - -AM_INIT_AUTOMAKE -AC_PROG_CXX(CC g++) - -LT_INIT([disable-static]) - -dnl no point in suppressing warnings people should -dnl at least see them, so here we go for g++: -Wall -if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Werror" -fi - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT From 4082bd04c441ff13a5b63329dc404c6947495590 Mon Sep 17 00:00:00 2001 From: rosstom Date: Tue, 16 May 2023 18:13:34 -0400 Subject: [PATCH 391/468] Creating TPCPedestalCalibration module Reads info directly from PRDF files and converts it into root file containing channel-wise alive/dead information and pedestal mean and rms values --- .../tpc/TPCPedestalCalibration/Makefile.am | 42 ++++ .../TPCPedestalCalibration.cc | 196 ++++++++++++++++++ .../TPCPedestalCalibration.h | 69 ++++++ .../tpc/TPCPedestalCalibration/autogen.sh | 8 + .../tpc/TPCPedestalCalibration/configure.ac | 16 ++ 5 files changed, 331 insertions(+) create mode 100644 calibrations/tpc/TPCPedestalCalibration/Makefile.am create mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc create mode 100644 calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h create mode 100755 calibrations/tpc/TPCPedestalCalibration/autogen.sh create mode 100644 calibrations/tpc/TPCPedestalCalibration/configure.ac diff --git a/calibrations/tpc/TPCPedestalCalibration/Makefile.am b/calibrations/tpc/TPCPedestalCalibration/Makefile.am new file mode 100644 index 0000000000..0b48126b8f --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/Makefile.am @@ -0,0 +1,42 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -I$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + TPCPedestalCalibration.h + +lib_LTLIBRARIES = \ + libTPCPedestalCalibration.la + +libTPCPedestalCalibration_la_SOURCES = \ + TPCPedestalCalibration.cc + +libTPCPedestalCalibration_la_LIBADD = \ + -lphool \ + -lSubsysReco + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libTPCPedestalCalibration.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc new file mode 100644 index 0000000000..836e28bfad --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc @@ -0,0 +1,196 @@ +#include "TPCPedestalCalibration.h" + +#include +#include +#include // for PHIODataNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/*************************************************************/ +/* TPC Pedestal Calibration */ +/* Thomas Marshall,Aditya Dash */ +/* rosstom@ucla.edu,aditya55@physics.ucla.edu */ +/*************************************************************/ + +TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) + :SubsysReco("TPCPedestalCalibration") + , m_fname(name) +{ + // reserve memory for max ADC samples + m_adcSamples.resize(1024, 0); +} + +int TPCPedestalCalibration::InitRun(PHCompositeNode *) +{ + m_file = TFile::Open(m_fname.c_str(), "recreate"); + assert(m_file->IsOpen()); + + m_pedestalTree = new TTree("pedestalTree", "Each entry is one TPC Channel"); + + m_pedestalTree->Branch("isAlive",&m_isAlive,"isAlive/I"); + m_pedestalTree->Branch("pedMean",&m_pedMean,"pedMean/F"); + m_pedestalTree->Branch("pedStd",&m_pedStd,"pedStd/F"); + m_pedestalTree->Branch("sector",&m_sector,"sector/I"); + m_pedestalTree->Branch("fee",&m_outFEE,"fee/I"); + m_pedestalTree->Branch("channel",&m_chan,"channel/I"); + m_pedestalTree->Branch("module",&m_module,"module/I"); + m_pedestalTree->Branch("slot",&m_slot,"slot/I"); + + for(int fee_no=0;fee_no<26;fee_no++) + { + for(int channel_no=0;channel_no<256;channel_no++) + { + m_aveADCFeeChannel[fee_no][channel_no]=0.0; + m_stdADCFeeChannel[fee_no][channel_no]=0.0; + m_countsADCFeeChannel[fee_no][channel_no]=0.0; + m_aliveArrayFeeChannel[fee_no][channel_no]=1; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TPCPedestalCalibration::process_event(PHCompositeNode *topNode) +{ + Event *_event = findNode::getClass(topNode, "PRDF"); + if (_event == nullptr) + { + std::cout << "TPCRawDataTree::Process_Event - Event not found" << std::endl; + return -1; + } + if (_event->getEvtType() >= 8) /// special events + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + + for (int packet : m_packets) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : decoding packet " << packet << std::endl; + } + + m_packet = packet; + + std::unique_ptr p (_event->getPacket(m_packet)); + if (!p) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : missing packet " << packet << std::endl; + } + + continue; + } + + m_nWaveormInFrame = p->iValue(0, "NR_WF"); + + for (int wf = 0; wf < m_nWaveormInFrame; wf++) + { + m_nSamples = p->iValue(wf, "SAMPLES"); + m_fee = p->iValue(wf, "FEE"); + m_Channel = p->iValue(wf, "CHANNEL"); + + if(m_nSamples==0) + { + m_aliveArrayFeeChannel[m_fee][m_Channel]=0; + continue; + } + + assert(m_nSamples < (int) m_adcSamples.size()); // no need for movements in memory allocation + for (int s = 0; s < m_nSamples; s++) + { + m_adcSamples[s] = p->iValue(wf, s); + } + + bool dead = false; + for(int adc_sam_no=0;adc_sam_no 200 || m_aveADCFeeChannel[fee_no][channel_no] < 10) + { + m_aliveArrayFeeChannel[fee_no][channel_no]=0; + } + + m_pedMean=m_aveADCFeeChannel[fee_no][channel_no]; + m_pedStd=sqrt(m_stdADCFeeChannel[fee_no][channel_no] - pow(m_aveADCFeeChannel[fee_no][channel_no],2)); + m_isAlive=m_aliveArrayFeeChannel[fee_no][channel_no]; + m_chan=channel_no; + m_outFEE=fee_no; + m_module=mod_arr[fee_no]; + m_slot=slot_arr[fee_no]; + m_pedestalTree->Fill(); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TPCPedestalCalibration::End(PHCompositeNode *topNode) +{ + std::cout << "TPCPedestalCalibration::End(PHCompositeNode *topNode) This is the End..." << std::endl; + + m_file->Write(); + + std::cout << __PRETTY_FUNCTION__ << " : completed saving to " << m_file->GetName() << std::endl; + m_file->ls(); + + m_file->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h new file mode 100644 index 0000000000..fd11c4facf --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h @@ -0,0 +1,69 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TPCPedestalCalibration_H +#define TPCPedestalCalibration_H + +#include + +#include +#include + +class PHCompositeNode; +class TFile; +class TTree; + +class TPCPedestalCalibration : public SubsysReco +{ + public: + explicit TPCPedestalCalibration(const std::string &name = "TPCPedestalCalibration.root"); + + ~TPCPedestalCalibration() override {} + + int InitRun(PHCompositeNode *topNode) override; + + int process_event(PHCompositeNode *topNode) override; + + int EndRun(const int runnumber) override; + + int End(PHCompositeNode *topNode) override; + + void AddPacket(int packet) + { + m_packets.push_back(packet); + } + + protected: + //! which packet to decode + std::vector m_packets{1001}; + + private: + std::string m_fname; + TFile * m_file = nullptr; + TTree * m_pedestalTree = nullptr; + + int m_packet = 0; + int m_nWaveormInFrame = 0; + int m_nSamples = 0; + int m_fee = 0; + int m_Channel = 0; + std::vector m_adcSamples; + + float m_aveADCFeeChannel[26][256]; + float m_stdADCFeeChannel[26][256]; + float m_countsADCFeeChannel[26][256]; + int m_aliveArrayFeeChannel[26][256]; + + int m_isAlive = 1; + float m_pedMean = 0; + float m_pedStd = 0; + int m_sector = 0; + int m_outFEE = 99; + int m_chan = 999; + int m_module = 9; + int m_slot = 99; + + int mod_arr[26]={2,2,1,1,1,3,3,3,3,3,3,2,2,1,2,2,1,1,2,2,3,3,3,3,3,3}; + int slot_arr[26] = {5,6,1,3,2,12,10,11,9,8,7,1,2,4,8,7,6,5,4,3,1,3,2,4,6,5}; +}; + +#endif // TPCPedestalCalibration_H diff --git a/calibrations/tpc/TPCPedestalCalibration/autogen.sh b/calibrations/tpc/TPCPedestalCalibration/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/tpc/TPCPedestalCalibration/configure.ac b/calibrations/tpc/TPCPedestalCalibration/configure.ac new file mode 100644 index 0000000000..a3d4486d54 --- /dev/null +++ b/calibrations/tpc/TPCPedestalCalibration/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(tpcpedestalcalibration,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT From b1e3dddc3ec0a549555a3f2de932365a751027db Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 16 May 2023 21:07:08 -0400 Subject: [PATCH 392/468] fix vtx type assignment --- offline/packages/globalvertex/GlobalVertexReco.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 893c89b316..9b47883714 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -126,7 +126,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a matching pair - GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX_BBC); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::VTXTYPE::SVTX_BBC); for (unsigned int i = 0; i < 3; ++i) { @@ -194,7 +194,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a standalone SVTX vertex - GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::SVTX); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::VTXTYPE::SVTX); vertex->set_id(global_vertex_id); global_vertex_id++; @@ -256,7 +256,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::UNDEFINED); + GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::VTXTYPE::BBC); vertex->set_id(global_vertex_id); global_vertex_id++; From c1cdc2dd75ef9354829ef277275094d7814f4bcf Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 16 May 2023 22:06:41 -0400 Subject: [PATCH 393/468] add vertices with id based on vertexmap size --- .../packages/globalvertex/GlobalVertexReco.cc | 16 +++++------- .../packages/globalvertex/GlobalVertexv1.cc | 26 +------------------ 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 9b47883714..0cfb383619 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -88,8 +88,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) std::set used_svtx_vtxids; std::set used_bbc_vtxids; - int global_vertex_id = 0; - + if (svtxmap && bbcmap) { if (Verbosity()) @@ -147,7 +146,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) used_svtx_vtxids.insert(svtx->get_id()); vertex->insert_vtxids(GlobalVertex::BBC, bbc_best->get_id()); used_bbc_vtxids.insert(bbc_best->get_id()); - vertex->set_id(global_vertex_id); + vertex->set_id(globalmap->size()); globalmap->insert(vertex); @@ -161,7 +160,6 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) track->set_vertex_id(vertex->get_id()); } } - global_vertex_id++; if (Verbosity() > 1) { @@ -196,8 +194,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) // we have a standalone SVTX vertex GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::VTXTYPE::SVTX); - vertex->set_id(global_vertex_id); - global_vertex_id++; + vertex->set_id(globalmap->size()); for (unsigned int i = 0; i < 3; ++i) { @@ -232,7 +229,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } } - + // okay now loop over all unused BBC vertexes (3rd class)... if (bbcmap) { @@ -257,8 +254,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } GlobalVertex *vertex = new GlobalVertexv1(GlobalVertex::VTXTYPE::BBC); - vertex->set_id(global_vertex_id); - global_vertex_id++; + vertex->set_id(globalmap->size()); // nominal beam location // could be replaced with a beam spot some day @@ -292,7 +288,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } } } - + /// Associate any tracks that were not assigned a track-vertex if (trackmap) { diff --git a/offline/packages/globalvertex/GlobalVertexv1.cc b/offline/packages/globalvertex/GlobalVertexv1.cc index 88d90170a5..b79f8acf75 100644 --- a/offline/packages/globalvertex/GlobalVertexv1.cc +++ b/offline/packages/globalvertex/GlobalVertexv1.cc @@ -13,31 +13,7 @@ void GlobalVertexv1::identify(std::ostream& os) const { os << "---GlobalVertexv1-----------------------" << std::endl; os << "vertexid: " << get_id(); - switch (get_id()) - { - case GlobalVertex::UNDEFINED: - os << ", type GlobalVertex::UNDEFINED" << std::endl; - break; - case GlobalVertex::TRUTH: - os << ", type GlobalVertex::TRUTH" << std::endl; - break; - case GlobalVertex::SMEARED: - os << ", type GlobalVertex::SMEARED" << std::endl; - break; - case GlobalVertex::BBC: - os << ", type GlobalVertex::BBC" << std::endl; - break; - case GlobalVertex::SVTX: - os << ", type GlobalVertex::SVTX" << std::endl; - break; - case GlobalVertex::SVTX_BBC: - os << ", type GlobalVertex::SVTX_BBC" << std::endl; - break; - default: - os << "unknown type of GlobalVertex:" << get_id() << std::endl; - break; - } - + os << " t = " << get_t() << std::endl; os << " (x,y,z) = (" << get_position(0); From 292a4b4cdca1f81642381a4d914354d42e41180a Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 17 May 2023 08:47:20 -0400 Subject: [PATCH 394/468] Added deletes for new objects --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 4e3019d217..0fa6857fe2 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -264,6 +264,9 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) selectedTracks.clear(); + delete motherTrueLV; + delete daughterTrueLV; + return foundDecay; } From 06732cc5585b7d83d4f95d5c16d3dc8dd8db05cb Mon Sep 17 00:00:00 2001 From: Shuonli Date: Thu, 18 May 2023 01:11:13 -0400 Subject: [PATCH 395/468] initial commit for the EMCAL new stepping action that does not save G4Hit --- .../g4detectors/LightCollectionModel.cc | 126 +++++ .../g4detectors/LightCollectionModel.h | 54 ++ .../g4simulation/g4detectors/Makefile.am | 2 + .../g4detectors/PHG4SpacalSteppingAction.cc | 491 ++++++++++++++++-- .../g4detectors/PHG4SpacalSteppingAction.h | 40 +- .../g4detectors/PHG4SpacalSubsystem.cc | 9 +- .../g4detectors/PHG4SpacalSubsystem.h | 4 +- 7 files changed, 688 insertions(+), 38 deletions(-) create mode 100644 simulation/g4simulation/g4detectors/LightCollectionModel.cc create mode 100644 simulation/g4simulation/g4detectors/LightCollectionModel.h diff --git a/simulation/g4simulation/g4detectors/LightCollectionModel.cc b/simulation/g4simulation/g4detectors/LightCollectionModel.cc new file mode 100644 index 0000000000..ab5bfe2b15 --- /dev/null +++ b/simulation/g4simulation/g4detectors/LightCollectionModel.cc @@ -0,0 +1,126 @@ +#include "LightCollectionModel.h" + +#include + +#include + +#include + +#include // for TAxis +#include +#include +#include +#include // for TObject +#include + +#include +#include + +LightCollectionModel::LightCollectionModel() +{ + data_grid_light_guide_efficiency_verify = new TH2F("data_grid_light_guide_efficiency_verify", + "light collection efficiency as used in LightCollectionModel;x positio fraction;y position fraction", // + 100, 0., 1., 100, 0., 1.); + + data_grid_fiber_trans_verify = new TH1F("data_grid_fiber_trans", + "SCSF-78 Fiber Transmission as used in LightCollectionModel;position in fiber (cm);Effective transmission", + 100, -15, 15); + + // register histograms + Fun4AllServer *se = Fun4AllServer::instance(); + + se->registerHisto(data_grid_light_guide_efficiency_verify); + se->registerHisto(data_grid_fiber_trans_verify); +} + +LightCollectionModel::~LightCollectionModel() +{ + delete data_grid_light_guide_efficiency; + delete data_grid_fiber_trans; +} + +void LightCollectionModel::load_data_from_CDB( + const std::string &domain, + const std::string &histogram_light_guide_model, + const std::string &histogram_fiber_model) +{ + recoConsts *rc = recoConsts::instance(); + std::string url = CDBInterface::instance()->getUrl(domain); + if (url.empty()) + { + std::cout << "No calibration for domain " << domain << " for timestamp " << rc->get_uint64Flag("TIMESTAMP") << std::endl; + gSystem->Exit(1); + } + TFile *fin = TFile::Open(url.c_str()); + if (!fin) + { + std::cout << "could not open " << url << std::endl; + gSystem->Exit(1); + } + if (data_grid_light_guide_efficiency) delete data_grid_light_guide_efficiency; + data_grid_light_guide_efficiency = dynamic_cast(fin->Get(histogram_light_guide_model.c_str())); + assert(data_grid_light_guide_efficiency); + data_grid_light_guide_efficiency->SetDirectory(nullptr); + if (data_grid_fiber_trans) delete data_grid_fiber_trans; + data_grid_fiber_trans = dynamic_cast(fin->Get(histogram_fiber_model.c_str())); + assert(data_grid_fiber_trans); + data_grid_fiber_trans->SetDirectory(nullptr); + delete fin; +} + +void LightCollectionModel::load_data_file( + const std::string &input_file, + const std::string &histogram_light_guide_model, + const std::string &histogram_fiber_model) +{ + TFile *fin = TFile::Open(input_file.c_str()); + + assert(fin); + assert(fin->IsOpen()); + + if (data_grid_light_guide_efficiency) delete data_grid_light_guide_efficiency; + data_grid_light_guide_efficiency = dynamic_cast(fin->Get(histogram_light_guide_model.c_str())); + assert(data_grid_light_guide_efficiency); + data_grid_light_guide_efficiency->SetDirectory(nullptr); + + if (data_grid_fiber_trans) delete data_grid_fiber_trans; + data_grid_fiber_trans = dynamic_cast(fin->Get(histogram_fiber_model.c_str())); + assert(data_grid_fiber_trans); + data_grid_fiber_trans->SetDirectory(nullptr); + + delete fin; +} + +double LightCollectionModel::get_light_guide_efficiency(const double x_fraction, const double y_fraction) +{ + assert(data_grid_light_guide_efficiency); + assert(x_fraction >= 0); + assert(x_fraction <= 1); + assert(y_fraction >= 0); + assert(y_fraction <= 1); + + const double eff = data_grid_light_guide_efficiency->Interpolate(x_fraction, + y_fraction); + + data_grid_light_guide_efficiency_verify->SetBinContent( // + data_grid_light_guide_efficiency_verify->GetXaxis()->FindBin(x_fraction), // + data_grid_light_guide_efficiency_verify->GetYaxis()->FindBin(y_fraction), // + eff // + ); + + return eff; +} + +double LightCollectionModel::get_fiber_transmission(const double z_distance) +{ + assert(data_grid_fiber_trans); + + const double eff = data_grid_fiber_trans->Interpolate(z_distance); + + data_grid_fiber_trans_verify->SetBinContent( // + data_grid_fiber_trans_verify->GetXaxis()->FindBin(z_distance), // + eff // + ); + + return eff; +} diff --git a/simulation/g4simulation/g4detectors/LightCollectionModel.h b/simulation/g4simulation/g4detectors/LightCollectionModel.h new file mode 100644 index 0000000000..8fe43ce3c8 --- /dev/null +++ b/simulation/g4simulation/g4detectors/LightCollectionModel.h @@ -0,0 +1,54 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef G4DETECTORS_LIGHTCOLLECTIONMODEL_H +#define G4DETECTORS_LIGHTCOLLECTIONMODEL_H +#include + +class TH2; +class TH1; + +class LightCollectionModel +{ + public: + LightCollectionModel(); + + //! delete copy ctor and assignment opertor (cppcheck) + explicit LightCollectionModel(const LightCollectionModel &) = delete; + LightCollectionModel &operator=(const LightCollectionModel &) = delete; + + virtual ~LightCollectionModel(); + + //! input data file + void load_data_file(const std::string &input_file, const std::string &histogram_light_guide_model, const std::string &histogram_fiber_model); + + //! load from CDB + void load_data_from_CDB(const std::string &domain, const std::string &histogram_light_guide_model, const std::string &histogram_fiber_model); + + //! Whether use light collection model + bool use_light_guide_model() const { return data_grid_light_guide_efficiency != nullptr; } + + //! Whether use Light Transmission Efficiency model for the fiber + bool use_fiber_model() const { return data_grid_fiber_trans != nullptr; } + + //! get Light Collection Efficiency for the light guide as function of x,y position in fraction of tower width + double get_light_guide_efficiency(const double x_fraction, const double y_fraction); + + //! get Light Transmission Efficiency for the fiber as function of z position (cm) in the fiber. Z=0 is at the middle of the fiber + double get_fiber_transmission(const double z_distance); + + private: + //! 2-D data grid for Light Collection Efficiency for the light guide as function of x,y position in fraction of tower width + TH2 *data_grid_light_guide_efficiency = nullptr; + + //! 1-D data grid for the light transmission efficiency in the fiber as function of distance to location in the fiber. Z=0 is at the middle of the fiber + TH1 *data_grid_fiber_trans = nullptr; + + // These two histograms are handed off to Fun4All and will be deleted there + // this suppresses the cppcheck warning + // cppcheck-suppress unsafeClassCanLeak + TH2 *data_grid_light_guide_efficiency_verify = nullptr; + // cppcheck-suppress unsafeClassCanLeak + TH1 *data_grid_fiber_trans_verify = nullptr; +}; + +#endif \ No newline at end of file diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index 13d90a89bf..cc307c68fe 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -43,6 +43,7 @@ libg4detectors_la_LIBADD = \ pkginclude_HEADERS = \ BeamLineMagnetSubsystem.h \ + LightCollectionModel.h \ PHG4BbcSubsystem.h \ PHG4BlockCellGeom.h \ PHG4BlockCellGeomContainer.h \ @@ -202,6 +203,7 @@ libg4detectors_la_SOURCES = \ BeamLineMagnetDisplayAction.cc \ BeamLineMagnetSubsystem.cc \ BeamLineMagnetSteppingAction.cc \ + LightCollectionModel.cc \ PHG4GDMLDetector.cc \ PHG4GDMLSubsystem.cc \ PHG4BbcDetector.cc \ diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc index 66de630953..70a4b2130e 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc @@ -10,6 +10,19 @@ #include "PHG4CylinderGeom_Spacalv3.h" #include "PHG4SpacalDetector.h" +#include "PHG4CellDefs.h" +#include "PHG4CylinderCellGeom.h" +#include "PHG4CylinderCellGeomContainer.h" +#include "PHG4CylinderCellGeom_Spacalv1.h" +#include "PHG4CylinderGeom.h" // for PHG4CylinderGeom +#include "PHG4CylinderGeomContainer.h" +#include "PHG4CylinderGeom_Spacalv1.h" // for PHG4CylinderGeom_Spaca... + +#include +#include +#include +#include + #include // for PHG4Hit #include #include @@ -17,39 +30,51 @@ #include // for PHG4SteppingAction #include +#include +#include +#include // for PHNode +#include +#include // for PHObject #include +#include // for PHWHERE +#include + +#include -#include // for G4IonisParamMat -#include // for G4Material +#include // for G4IonisParamMat +#include // for G4Material #include -#include // for G4ParticleDefinition +#include // for G4ParticleDefinition +#include // for G4ReferenceCountedHandle #include -#include // for G4StepPoint -#include // for fGeomBoundary, fAtRestD... -#include // for G4String +#include // for G4StepPoint +#include // for fGeomBoundary, fAtRestD... +#include // for G4String #include -#include // for G4ThreeVector -#include // for G4TouchableHandle -#include // for G4Track -#include // for fStopAndKill -#include // for G4double -#include // for G4VTouchable -#include // for G4VUserTrackInformation +#include // for G4ThreeVector +#include // for G4TouchableHandle +#include // for G4Track +#include // for fStopAndKill +#include +#include // for G4double +#include // for G4VTouchable +#include // for G4VUserTrackInformation #include #include // for isfinite #include // for exit #include -#include // for operator<<, char_traits +#include // for operator<<, char_traits class G4VPhysicalVolume; class PHCompositeNode; //____________________________________________________________________________.. -PHG4SpacalSteppingAction::PHG4SpacalSteppingAction(PHG4SpacalDetector* detector) - : PHG4SteppingAction(detector->GetName()) - , m_Detector(detector) +PHG4SpacalSteppingAction::PHG4SpacalSteppingAction(PHG4SpacalDetector *indetector) + : PHG4SteppingAction(indetector->GetName()) + , PHParameterInterface(indetector->GetName()) + , m_Detector(indetector) { } @@ -62,17 +87,405 @@ PHG4SpacalSteppingAction::~PHG4SpacalSteppingAction() delete m_Hit; } +int PHG4SpacalSteppingAction::InitWithNode(PHCompositeNode *topNode) +{ + UpdateParametersWithMacro(); + m_doG4Hit = get_int_param("saveg4hit"); + m_tmin = get_double_param("tmin"); + m_tmax = get_double_param("tmax"); + m_dt = get_double_param("dt"); + if (m_doG4Hit) return 0; + PHNodeIterator iter(topNode); + detector = m_Detector->SuperDetector(); + // Looking for the DST node + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + exit(1); + } + + geonodename = "CYLINDERGEOM_" + detector; + PHG4CylinderGeomContainer *geo = findNode::getClass(topNode, geonodename); + if (!geo) + { + std::cout << "PHG4SpacalSteppingAction::InitWithNode - Could not locate geometry node " + << geonodename << std::endl; + topNode->print(); + exit(1); + } + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalSteppingAction::InitWithNode - incoming geometry:" + << std::endl; + geo->identify(); + } + seggeonodename = "CYLINDERCELLGEOM_" + detector; + PHG4CylinderCellGeomContainer *seggeo = findNode::getClass(topNode, seggeonodename); + if (!seggeo) + { + seggeo = new PHG4CylinderCellGeomContainer(); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + PHIODataNode *newNode = new PHIODataNode(seggeo, seggeonodename, "PHObject"); + runNode->addNode(newNode); + } + + const PHG4CylinderGeom *layergeom_raw = geo->GetFirstLayerGeom(); + assert(layergeom_raw); + + // a special implimentation of PHG4CylinderGeom is required here. + const PHG4CylinderGeom_Spacalv3 *layergeom = + dynamic_cast(layergeom_raw); + + if (!layergeom) + { + std::cout << "PHG4SpacalSteppingAction::InitWithNode - Fatal Error -" + << " require to work with a version of SPACAL geometry of PHG4CylinderGeom_Spacalv3 or higher. " + << "However the incoming geometry has version " + << layergeom_raw->ClassName() << std::endl; + exit(1); + } + if (Verbosity() > 1) + { + layergeom->identify(); + } + + layergeom->subtower_consistency_check(); + + // int layer = layergeom->get_layer(); + + // create geo object and fill with variables common to all binning methods + PHG4CylinderCellGeom_Spacalv1 *layerseggeo = new PHG4CylinderCellGeom_Spacalv1(); + layerseggeo->set_layer(layergeom->get_layer()); + layerseggeo->set_radius(layergeom->get_radius()); + layerseggeo->set_thickness(layergeom->get_thickness()); + layerseggeo->set_binning(PHG4CellDefs::spacalbinning); + + // construct a map to convert tower_ID into the older eta bins. + + const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeom->get_sector_tower_map(); + const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeom->get_sector_map(); + const int nphibin = layergeom->get_azimuthal_n_sec() // sector + * layergeom->get_max_phi_bin_in_sec() // blocks per sector + * layergeom->get_n_subtower_phi(); // subtower per block + const double deltaphi = 2. * M_PI / nphibin; + + using map_z_tower_z_ID_t = std::map; + map_z_tower_z_ID_t map_z_tower_z_ID; + double phi_min = NAN; + + for (const auto &tower_pair : tower_map) + { + const int &tower_ID = tower_pair.first; + const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; + + // inspect index in sector 0 + std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); + + const int &tower_ID_z = tower_z_phi_ID.first; + const int &tower_ID_phi = tower_z_phi_ID.second; + + if (tower_ID_phi == 0) + { + // assign phi min according phi bin 0 + phi_min = M_PI_2 - deltaphi * (layergeom->get_max_phi_bin_in_sec() * layergeom->get_n_subtower_phi() / 2) // shift of first tower in sector + + sector_map.begin()->second; + } + + if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) + { + // assign eta min according phi bin 0 + map_z_tower_z_ID[tower.centralZ] = tower_ID_z; + } + // ... + } // const auto &tower_pair: tower_map + + assert(!std::isnan(phi_min)); + layerseggeo->set_phimin(phi_min); + layerseggeo->set_phistep(deltaphi); + layerseggeo->set_phibins(nphibin); + + PHG4CylinderCellGeom_Spacalv1::tower_z_ID_eta_bin_map_t tower_z_ID_eta_bin_map; + int eta_bin = 0; + for (auto &z_tower_z_ID : map_z_tower_z_ID) + { + tower_z_ID_eta_bin_map[z_tower_z_ID.second] = eta_bin; + eta_bin++; + } + layerseggeo->set_tower_z_ID_eta_bin_map(tower_z_ID_eta_bin_map); + layerseggeo->set_etabins(eta_bin * layergeom->get_n_subtower_eta()); + layerseggeo->set_etamin(NAN); + layerseggeo->set_etastep(NAN); + + // build eta bin maps + for (const auto &tower_pair : tower_map) + { + const int &tower_ID = tower_pair.first; + const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; + + // inspect index in sector 0 + std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); + const int &tower_ID_z = tower_z_phi_ID.first; + const int &tower_ID_phi = tower_z_phi_ID.second; + const int &etabin = tower_z_ID_eta_bin_map[tower_ID_z]; + + if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) + { + // half z-range + const double dz = fabs(0.5 * (tower.pDy1 + tower.pDy2) / sin(tower.pRotationAngleX)); + const double tower_radial = layergeom->get_tower_radial_position(tower); + + auto z_to_eta = [&tower_radial](const double &z) + { return -log(tan(0.5 * atan2(tower_radial, z))); }; + + const double eta_central = z_to_eta(tower.centralZ); + // half eta-range + const double deta = (z_to_eta(tower.centralZ + dz) - z_to_eta(tower.centralZ - dz)) / 2; + assert(deta > 0); + + for (int sub_tower_ID_y = 0; sub_tower_ID_y < tower.NSubtowerY; + ++sub_tower_ID_y) + { + assert(tower.NSubtowerY <= layergeom->get_n_subtower_eta()); + // do not overlap to the next bin. + const int sub_tower_etabin = etabin * layergeom->get_n_subtower_eta() + sub_tower_ID_y; + + const std::pair etabounds(eta_central - deta + sub_tower_ID_y * 2 * deta / tower.NSubtowerY, + eta_central - deta + (sub_tower_ID_y + 1) * 2 * deta / tower.NSubtowerY); + + const std::pair zbounds(tower.centralZ - dz + sub_tower_ID_y * 2 * dz / tower.NSubtowerY, + tower.centralZ - dz + (sub_tower_ID_y + 1) * 2 * dz / tower.NSubtowerY); + + layerseggeo->set_etabounds(sub_tower_etabin, etabounds); + layerseggeo->set_zbounds(sub_tower_etabin, zbounds); + } + } + // ... + } // const auto &tower_pair: tower_map + + // add geo object filled by different binning methods + seggeo->AddLayerCellGeom(layerseggeo); + + // save this to the run wise tree to store on DST + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(detector); + runNode->addNode(RunDetNode); + } + std::string paramnodename = "G4CELLPARAM_" + detector; + SaveToNodeTree(RunDetNode, paramnodename); + // save this to the parNode for use + PHNodeIterator parIter(parNode); + PHCompositeNode *ParDetNode = dynamic_cast(parIter.findFirst("PHCompositeNode", detector)); + if (!ParDetNode) + { + ParDetNode = new PHCompositeNode(detector); + parNode->addNode(ParDetNode); + } + std::string cellgeonodename = "G4CELLGEO_" + detector; + PutOnParNode(ParDetNode, cellgeonodename); + + // get the private layergeo + _layergeo = findNode::getClass(topNode, geonodename); + if (!_layergeo) + { + std::cout << "PHG4SpacalSteppingAction::InitWithNode - Fatal Error - Could not locate sim geometry node " + << geonodename << std::endl; + exit(1); + } + + _seggeo = findNode::getClass(topNode, seggeonodename); + if (!_seggeo) + { + std::cout << "PHG4FullProjSpacalCellReco::process_event - Fatal Error - could not locate cell geometry node " + << seggeonodename << std::endl; + exit(1); + } + PHG4CylinderCellGeom *_geo_raw = _seggeo->GetFirstLayerCellGeom(); + _geo = dynamic_cast(_geo_raw); + assert(_geo); + const PHG4CylinderGeom *_layergeom_raw = _layergeo->GetFirstLayerGeom(); + assert(_layergeom_raw); + // a special implimentation of PHG4CylinderGeom is required here. + _layergeom = dynamic_cast(_layergeom_raw); + assert(_layergeom); + + // add towerinfo here + PHNodeIterator dstiter(dstNode); + PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", detector)); + if (!DetNode) + { + DetNode = new PHCompositeNode(detector); + dstNode->addNode(DetNode); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::EMCAL); + PHIODataNode *towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + detector, "PHObject"); + DetNode->addNode(towerNode); + + return 0; +} + +bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) +{ + // get volume of the current step + G4VPhysicalVolume *volume = aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume(); + int isactive = m_Detector->IsInCylinderActive(volume); + if (isactive > PHG4SpacalDetector::INACTIVE) + { + G4StepPoint *prePoint = aStep->GetPreStepPoint(); + G4StepPoint *postPoint = aStep->GetPostStepPoint(); + // time window cut + double pretime = prePoint->GetGlobalTime() / nanosecond; + double posttime = postPoint->GetGlobalTime() / nanosecond; + if (posttime < m_tmin || pretime > m_tmax) return false; + if ((posttime - pretime) > m_dt) return false; + + int scint_id = -1; + + if ( // + m_Detector->get_geom()->get_config() == PHG4SpacalDetector::SpacalGeom_t::kFullProjective_2DTaper || + m_Detector->get_geom()->get_config() == PHG4SpacalDetector::SpacalGeom_t::kFullProjective_2DTaper_SameLengthFiberPerTower || + m_Detector->get_geom()->get_config() == PHG4SpacalDetector::SpacalGeom_t::kFullProjective_2DTaper_Tilted || + m_Detector->get_geom()->get_config() == PHG4SpacalDetector::SpacalGeom_t::kFullProjective_2DTaper_Tilted_SameLengthFiberPerTower // + ) + { + // SPACAL ID that is associated with towers + int sector_ID = 0; + int tower_ID = 0; + int fiber_ID = 0; + + if (isactive == PHG4SpacalDetector::FIBER_CORE) + { + fiber_ID = prePoint->GetTouchable()->GetReplicaNumber(1); + tower_ID = prePoint->GetTouchable()->GetReplicaNumber(2); + sector_ID = prePoint->GetTouchable()->GetReplicaNumber(3); + } + + else + { + return false; + } + + // compact the tower/sector/fiber ID into 32 bit scint_id, so we could save some space for SPACAL hits + scint_id = PHG4CylinderGeom_Spacalv3::scint_id_coder(sector_ID, tower_ID, fiber_ID).scint_ID; + } + else + { + // other configuraitons + if (isactive == PHG4SpacalDetector::FIBER_CORE) + { + scint_id = prePoint->GetTouchable()->GetReplicaNumber(2); + } + else + { + return false; + } + } + // decode scint_id + PHG4CylinderGeom_Spacalv3::scint_id_coder decoder(scint_id); + + // convert to z_ID, phi_ID + std::pair tower_z_phi_ID = _layergeom->get_tower_z_phi_ID(decoder.tower_ID, decoder.sector_ID); + const int &tower_ID_z = tower_z_phi_ID.first; + const int &tower_ID_phi = tower_z_phi_ID.second; + + PHG4CylinderGeom_Spacalv3::tower_map_t::const_iterator it_tower = + _layergeom->get_sector_tower_map().find(decoder.tower_ID); + assert(it_tower != _layergeom->get_sector_tower_map().end()); + + // convert tower_ID_z to to eta bin number + int etabin = -1; + try + { + etabin = _geo->get_etabin_block(tower_ID_z); // block eta bin + } + catch (std::exception &e) + { + std::cout << "Print cell geometry:" << std::endl; + _geo->identify(); + std::cout << "Print scint_id_coder:" << std::endl; + decoder.identify(); + std::cout << "PHG4SpacalSteppingAction::UserSteppingAction::" + << " - Fatal Error - " << e.what() << std::endl; + exit(1); + } + + const int sub_tower_ID_x = it_tower->second.get_sub_tower_ID_x(decoder.fiber_ID); + const int sub_tower_ID_y = it_tower->second.get_sub_tower_ID_y(decoder.fiber_ID); + unsigned short etabinshort = etabin * _layergeom->get_n_subtower_eta() + sub_tower_ID_y; + unsigned short phibin = tower_ID_phi * _layergeom->get_n_subtower_phi() + sub_tower_ID_x; + + // get light yield + double light_yield = GetVisibleEnergyDeposition(aStep); + if (light_collection_model.use_fiber_model()) + { + const G4TouchableHandle &theTouchable0 = prePoint->GetTouchableHandle(); + const G4ThreeVector &worldPosition0 = prePoint->GetPosition(); + G4ThreeVector localPosition = theTouchable0->GetHistory()->GetTopTransform().TransformPoint(worldPosition0); + const double localz0 = localPosition.z(); + // post point + const G4TouchableHandle &theTouchable1 = postPoint->GetTouchableHandle(); + const G4ThreeVector &worldPosition1 = postPoint->GetPosition(); + localPosition = theTouchable1->GetHistory()->GetTopTransform().TransformPoint(worldPosition1); + const double localz1 = localPosition.z(); + + const double z = 0.5 * (localz0 + localz1); + assert(not std::isnan(z)); + + light_yield *= light_collection_model.get_fiber_transmission(z); + } + // light yield correction from light guide collection efficiency: + if (light_collection_model.use_fiber_model()) + { + const double x = it_tower->second.get_position_fraction_x_in_sub_tower(decoder.fiber_ID); + const double y = it_tower->second.get_position_fraction_y_in_sub_tower(decoder.fiber_ID); + + light_yield *= light_collection_model.get_light_guide_efficiency(x, y); + } + unsigned int tower_key = TowerInfoDefs::encode_emcal(etabinshort, phibin); + m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield); + + // set keep for the track + const G4Track *aTrack = aStep->GetTrack(); + if (light_yield > 0) + { + if (G4VUserTrackInformation *p = aTrack->GetUserInformation()) + { + if (PHG4TrackUserInfoV1 *pp = dynamic_cast(p)) + { + pp->SetKeep(1); // we want to keep the track + } + } + } + return true; + } + else + { + return false; + } +} + //____________________________________________________________________________.. -bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) +bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step *aStep, bool) { + if (!m_doG4Hit) + { + return NoHitSteppingAction(aStep); + } + // get volume of the current step - G4VPhysicalVolume* volume = aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume(); + G4VPhysicalVolume *volume = aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume(); // collect energy and track length step by step G4double edep = aStep->GetTotalEnergyDeposit() / GeV; G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV; - const G4Track* aTrack = aStep->GetTrack(); + const G4Track *aTrack = aStep->GetTrack(); int layer_id = m_Detector->get_Layer(); // make sure we are in a volume @@ -89,8 +502,8 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { geantino = true; } - G4StepPoint* prePoint = aStep->GetPreStepPoint(); - G4StepPoint* postPoint = aStep->GetPostStepPoint(); + G4StepPoint *prePoint = aStep->GetPreStepPoint(); + G4StepPoint *postPoint = aStep->GetPostStepPoint(); int scint_id = -1; if ( // @@ -100,7 +513,7 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) m_Detector->get_geom()->get_config() == PHG4SpacalDetector::SpacalGeom_t::kFullProjective_2DTaper_Tilted_SameLengthFiberPerTower // ) { - //SPACAL ID that is associated with towers + // SPACAL ID that is associated with towers int sector_ID = 0; int tower_ID = 0; int fiber_ID = 0; @@ -169,17 +582,17 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) } m_Hit->set_layer((unsigned int) layer_id); m_Hit->set_scint_id(scint_id); // isactive contains the scintillator slat id - //here we set the entrance values in cm + // here we set the entrance values in cm m_Hit->set_x(0, prePoint->GetPosition().x() / cm); m_Hit->set_y(0, prePoint->GetPosition().y() / cm); m_Hit->set_z(0, prePoint->GetPosition().z() / cm); // time in ns m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond); - //set the track ID + // set the track ID m_Hit->set_trkid(aTrack->GetTrackID()); m_SaveTrackid = aTrack->GetTrackID(); - //set the initial energy deposit + // set the initial energy deposit m_Hit->set_edep(0); // Now add the hit if (isactive == PHG4SpacalDetector::FIBER_CORE) // the slat ids start with zero @@ -194,9 +607,9 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) { m_CurrentHitContainer = m_AbsorberHitContainer; } - if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + if (G4VUserTrackInformation *p = aTrack->GetUserInformation()) { - if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + if (PHG4TrackUserInfoV1 *pp = dynamic_cast(p)) { m_Hit->set_trkid(pp->GetUserTrackId()); m_Hit->set_shower_id(pp->GetShower()->get_id()); @@ -241,7 +654,7 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) m_Hit->set_z(1, postPoint->GetPosition().z() / cm); m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond); - //sum up the energy to get total deposited + // sum up the energy to get total deposited m_Hit->set_edep(m_Hit->get_edep() + edep); if (isactive == PHG4SpacalDetector::FIBER_CORE) // only for active areas @@ -295,9 +708,9 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) } if (edep > 0) { - if (G4VUserTrackInformation* p = aTrack->GetUserInformation()) + if (G4VUserTrackInformation *p = aTrack->GetUserInformation()) { - if (PHG4TrackUserInfoV1* pp = dynamic_cast(p)) + if (PHG4TrackUserInfoV1 *pp = dynamic_cast(p)) { pp->SetKeep(1); // we want to keep the track } @@ -344,14 +757,14 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step* aStep, bool) } //____________________________________________________________________________.. -void PHG4SpacalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode) +void PHG4SpacalSteppingAction::SetInterfacePointers(PHCompositeNode *topNode) { m_HitContainer = findNode::getClass(topNode, m_HitNodeName); m_AbsorberHitContainer = findNode::getClass(topNode, m_AbsorberNodeName); // if we do not find the node it's messed up. if (!m_HitContainer) { - std::cout << "PHG4ZDCSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl; + std::cout << "PHG4SpacalSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl; gSystem->Exit(1); } // this is perfectly fine if absorber hits are disabled @@ -390,7 +803,7 @@ PHG4SpacalSteppingAction::get_zmax() const } } -void PHG4SpacalSteppingAction::SetHitNodeName(const std::string& type, const std::string& name) +void PHG4SpacalSteppingAction::SetHitNodeName(const std::string &type, const std::string &name) { if (type == "G4HIT") { @@ -406,3 +819,13 @@ void PHG4SpacalSteppingAction::SetHitNodeName(const std::string& type, const std gSystem->Exit(1); return; } + +// not using is one, just to make the compiler happy +void PHG4SpacalSteppingAction::SetDefaultParameters() +{ + set_default_double_param("tmax", 60.0); + set_default_double_param("tmin", -20.0); + set_default_double_param("dt", 100.0); + set_default_int_param("saveg4hit", 1); + return; +} diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h index 5111c81734..689d9cd336 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h @@ -11,16 +11,27 @@ #ifndef G4DETECTORS_PHG4SPACALSTEPPINGACTION_H #define G4DETECTORS_PHG4SPACALSTEPPINGACTION_H +#include "LightCollectionModel.h" + +#include + #include class G4Step; +class LightCollectionModel; class PHCompositeNode; +class PHG4CylinderCellGeomContainer; +class PHG4CylinderCellGeom_Spacalv1; +class PHG4CylinderGeomContainer; +class PHG4CylinderGeom_Spacalv3; class PHG4SpacalDetector; class PHG4Hit; class PHG4HitContainer; class PHG4Shower; +class PHParameters; +class TowerInfoContainer; -class PHG4SpacalSteppingAction : public PHG4SteppingAction +class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterInterface { public: //! ctor @@ -32,6 +43,8 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction //! stepping action bool UserSteppingAction(const G4Step *, bool) override; + int InitWithNode(PHCompositeNode *topNode) override; + //! reimplemented from base class void SetInterfacePointers(PHCompositeNode *) override; @@ -41,7 +54,12 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction void SetHitNodeName(const std::string &type, const std::string &name) override; + void SetDefaultParameters() override; + + LightCollectionModel &get_light_collection_model() { return light_collection_model; } + private: + bool NoHitSteppingAction(const G4Step *aStep); //! pointer to the detector PHG4SpacalDetector *m_Detector = nullptr; @@ -51,11 +69,31 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction PHG4Hit *m_Hit = nullptr; PHG4HitContainer *m_CurrentHitContainer = nullptr; PHG4Shower *m_CurrentShower = nullptr; + const PHParameters *m_Params = nullptr; int m_SaveTrackid = -1; int m_SavePostStepStatus = -1; + bool m_doG4Hit = true; + double m_tmin = -20.; + double m_tmax = 60.; + double m_dt = 100.; std::string m_AbsorberNodeName; std::string m_HitNodeName; + std::string detector; + std::string geonodename; + std::string seggeonodename; + + TowerInfoContainer *m_CaloInfoContainer = nullptr; + + PHG4CylinderCellGeomContainer *_seggeo = nullptr; + + PHG4CylinderGeomContainer *_layergeo = nullptr; + + PHG4CylinderCellGeom_Spacalv1 *_geo = nullptr; + + const PHG4CylinderGeom_Spacalv3 *_layergeom = nullptr; + + LightCollectionModel light_collection_model; }; #endif // PHG4VHcalSteppingAction_h diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc index f83b784a66..a25b9ee74f 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc @@ -16,7 +16,7 @@ #include -#include // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include // for PHG4SteppingAction @@ -29,6 +29,7 @@ #include +#include #include // for operator<<, basic_ostream #include @@ -138,8 +139,13 @@ int PHG4SpacalSubsystem::InitRunSubsystem(PHCompositeNode* topNode) } steppingAction_ = new PHG4SpacalSteppingAction(detector_); + steppingAction_->set_int_param("saveg4hit", GetParams()->get_int_param("saveg4hit")); + steppingAction_->get_light_collection_model().load_data_file( + std::string(getenv("CALIBRATIONROOT")) + std::string("/CEMC/LightCollection/Prototype3Module.xml"), + "data_grid_light_guide_efficiency", "data_grid_fiber_trans"); steppingAction_->SetHitNodeName("G4HIT", m_HitNodeName); steppingAction_->SetHitNodeName("G4HIT_ABSORBER", m_AbsorberNodeName); + steppingAction_->InitWithNode(topNode); } return 0; } @@ -185,6 +191,7 @@ void PHG4SpacalSubsystem::SetDefaultParameters() set_default_int_param("azimuthal_seg_visible", 0.); set_default_int_param("virualize_fiber", 0.); set_default_int_param("config", static_cast(PHG4CylinderGeom_Spacalv1::kNonProjective)); + set_default_int_param("saveg4hit", 1); set_default_double_param("divider_width", 0); // radial size of the divider between blocks. <=0 means no dividers set_default_string_param("divider_mat", "G4_AIR"); // materials of the divider. G4_AIR is equivalent to not installing one in the term of material distribution diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h index 87a1fe7ffb..243c12a8f6 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h @@ -12,6 +12,7 @@ #define G4DETECTORS_PHG4SPACALSUBSYSTEM_H #include "PHG4DetectorSubsystem.h" +#include "PHG4SpacalSteppingAction.h" #include // for string @@ -19,7 +20,6 @@ class PHCompositeNode; class PHG4Detector; class PHG4DisplayAction; class PHG4SpacalDetector; -class PHG4SteppingAction; class PHG4SpacalSubsystem : public PHG4DetectorSubsystem { @@ -69,7 +69,7 @@ class PHG4SpacalSubsystem : public PHG4DetectorSubsystem //! particle tracking "stepping" action /*! derives from PHG4SteppingActions */ - PHG4SteppingAction *steppingAction_ = nullptr; + PHG4SpacalSteppingAction *steppingAction_ = nullptr; //! display attribute setting /*! derives from PHG4DisplayAction */ From 48edeb3b0a992d599e82c3a340cb77c50675a108 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 18 May 2023 11:38:23 -0400 Subject: [PATCH 396/468] add alignment state derivatives --- .../TrackingDiagnostics/TrackResiduals.cc | 113 ++++++++++++++++-- .../TrackingDiagnostics/TrackResiduals.h | 28 ++++- 2 files changed, 130 insertions(+), 11 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 674d704604..95da333010 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -78,6 +80,32 @@ int TrackResiduals::InitRun(PHCompositeNode*) } void TrackResiduals::clearClusterStateVectors() { + m_statelxglobderivdx.clear(); + m_statelxglobderivdy.clear(); + m_statelxglobderivdz.clear(); + m_statelxglobderivdalpha.clear(); + m_statelxglobderivdbeta.clear(); + m_statelxglobderivdgamma.clear(); + + m_statelxlocderivd0.clear(); + m_statelxlocderivz0.clear(); + m_statelxlocderivphi.clear(); + m_statelxlocderivtheta.clear(); + m_statelxlocderivqop.clear(); + + m_statelzglobderivdx.clear(); + m_statelzglobderivdy.clear(); + m_statelzglobderivdz.clear(); + m_statelzglobderivdalpha.clear(); + m_statelzglobderivdbeta.clear(); + m_statelzglobderivdgamma.clear(); + + m_statelzlocderivd0.clear(); + m_statelzlocderivz0.clear(); + m_statelzlocderivphi.clear(); + m_statelzlocderivtheta.clear(); + m_statelzlocderivqop.clear(); + m_cluslx.clear(); m_cluslz.clear(); m_cluselx.clear(); @@ -106,6 +134,8 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) auto clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); auto geometry = findNode::getClass(topNode, "ActsGeometry"); auto vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + auto alignmentmap = findNode::getClass(topNode, "SvtxAlignmentStateMap"); + if (!trackmap or !clustermap or !geometry or !vertexmap) { std::cout << "Missing node, can't continue" << std::endl; @@ -214,10 +244,10 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) //! have cluster and state, fill vectors m_cluslx.push_back(cluster->getLocalX()); float clusz = cluster->getLocalY(); - if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::tpcId) - { - clusz = convertTimeToZ(geometry,ckey, cluster); - } + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::tpcId) + { + clusz = convertTimeToZ(geometry, ckey, cluster); + } m_cluslz.push_back(clusz); m_cluselx.push_back(cluster->getRPhiError()); m_cluselz.push_back(cluster->getZError()); @@ -271,6 +301,43 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) m_nhits = m_nmaps + m_nintt + m_ntpc + m_nmms; + if (alignmentmap and alignmentmap->find(key) != alignmentmap->end()) + { + auto& statevec = alignmentmap->find(key)->second; + + for (auto& state : statevec) + { + auto& globderivs = state->get_global_derivative_matrix(); + auto& locderivs = state->get_local_derivative_matrix(); + + m_statelxglobderivdalpha.push_back(globderivs(0, 0)); + m_statelxglobderivdbeta.push_back(globderivs(0, 1)); + m_statelxglobderivdgamma.push_back(globderivs(0, 2)); + m_statelxglobderivdx.push_back(globderivs(0, 3)); + m_statelxglobderivdy.push_back(globderivs(0, 4)); + m_statelxglobderivdz.push_back(globderivs(0, 5)); + + m_statelzglobderivdalpha.push_back(globderivs(1, 0)); + m_statelzglobderivdbeta.push_back(globderivs(1, 1)); + m_statelzglobderivdgamma.push_back(globderivs(1, 2)); + m_statelzglobderivdx.push_back(globderivs(1, 3)); + m_statelzglobderivdy.push_back(globderivs(1, 4)); + m_statelzglobderivdz.push_back(globderivs(1, 5)); + + m_statelxlocderivd0.push_back(locderivs(0, 0)); + m_statelxlocderivz0.push_back(locderivs(0, 1)); + m_statelxlocderivphi.push_back(locderivs(0, 2)); + m_statelxlocderivtheta.push_back(locderivs(0, 3)); + m_statelxlocderivqop.push_back(locderivs(0, 4)); + + m_statelzlocderivd0.push_back(locderivs(1, 0)); + m_statelzlocderivz0.push_back(locderivs(1, 1)); + m_statelzlocderivphi.push_back(locderivs(1, 2)); + m_statelzlocderivtheta.push_back(locderivs(1, 3)); + m_statelzlocderivqop.push_back(locderivs(1, 4)); + } + } + m_tree->Fill(); } @@ -278,18 +345,18 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } -float TrackResiduals::convertTimeToZ(ActsGeometry* geometry, TrkrDefs::cluskey cluster_key, TrkrCluster *cluster) +float TrackResiduals::convertTimeToZ(ActsGeometry* geometry, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster) { // must convert local Y from cluster average time of arival to local cluster z position double drift_velocity = geometry->get_drift_velocity(); double zdriftlength = cluster->getLocalY() * drift_velocity; - double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is - double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north + double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is + double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north unsigned int side = TpcDefs::getSide(cluster_key); - if(side == 0) zloc = -zloc; + if (side == 0) zloc = -zloc; float z = zloc; // in cm - - return z; + + return z; } //____________________________________________________________________________.. @@ -351,4 +418,30 @@ void TrackResiduals::createBranches() m_tree->Branch("statepy", &m_statepy); m_tree->Branch("statepz", &m_statepz); m_tree->Branch("statepl", &m_statepl); + + m_tree->Branch("statelxglobderivdx", &m_statelxglobderivdx); + m_tree->Branch("statelxglobderivdy", &m_statelxglobderivdy); + m_tree->Branch("statelxglobderivdz", &m_statelxglobderivdz); + m_tree->Branch("statelxglobderivdalpha", &m_statelxglobderivdalpha); + m_tree->Branch("statelxglobderivdbeta", &m_statelxglobderivdbeta); + m_tree->Branch("statelxglobderivdgamma", &m_statelxglobderivdgamma); + + m_tree->Branch("statelxlocderivd0", &m_statelxlocderivd0); + m_tree->Branch("statelxlocderivz0", &m_statelxlocderivz0); + m_tree->Branch("statelxlocderivphi", &m_statelxlocderivphi); + m_tree->Branch("statelxlocderivtheta", &m_statelxlocderivtheta); + m_tree->Branch("statelxlocderivqop", &m_statelxlocderivqop); + + m_tree->Branch("statelzglobderivdx", &m_statelzglobderivdx); + m_tree->Branch("statelzglobderivdy", &m_statelzglobderivdy); + m_tree->Branch("statelzglobderivdz", &m_statelzglobderivdz); + m_tree->Branch("statelzglobderivdalpha", &m_statelzglobderivdalpha); + m_tree->Branch("statelzglobderivdbeta", &m_statelzglobderivdbeta); + m_tree->Branch("statelzglobderivdgamma", &m_statelzglobderivdgamma); + + m_tree->Branch("statelzlocderivd0", &m_statelzlocderivd0); + m_tree->Branch("statelzlocderivz0", &m_statelzlocderivz0); + m_tree->Branch("statelzlocderivphi", &m_statelzlocderivphi); + m_tree->Branch("statelzlocderivtheta", &m_statelzlocderivtheta); + m_tree->Branch("statelzlocderivqop", &m_statelzlocderivqop); } diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index a9b1b8ffdf..ecd7296b9a 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -36,7 +36,7 @@ class TrackResiduals : public SubsysReco private: void clearClusterStateVectors(); void createBranches(); - float convertTimeToZ(ActsGeometry* geometry, TrkrDefs::cluskey cluster_key, TrkrCluster* cluster); + float convertTimeToZ(ActsGeometry *geometry, TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); std::string m_outfileName = ""; TFile *m_outfile = nullptr; TTree *m_tree = nullptr; @@ -92,6 +92,32 @@ class TrackResiduals : public SubsysReco std::vector m_statepy; std::vector m_statepz; std::vector m_statepl; + + std::vector m_statelxglobderivdx; + std::vector m_statelxglobderivdy; + std::vector m_statelxglobderivdz; + std::vector m_statelxglobderivdalpha; + std::vector m_statelxglobderivdbeta; + std::vector m_statelxglobderivdgamma; + + std::vector m_statelxlocderivd0; + std::vector m_statelxlocderivz0; + std::vector m_statelxlocderivphi; + std::vector m_statelxlocderivtheta; + std::vector m_statelxlocderivqop; + + std::vector m_statelzglobderivdx; + std::vector m_statelzglobderivdy; + std::vector m_statelzglobderivdz; + std::vector m_statelzglobderivdalpha; + std::vector m_statelzglobderivdbeta; + std::vector m_statelzglobderivdgamma; + + std::vector m_statelzlocderivd0; + std::vector m_statelzlocderivz0; + std::vector m_statelzlocderivphi; + std::vector m_statelzlocderivtheta; + std::vector m_statelzlocderivqop; }; #endif // TRACKRESIDUALS_H From f31b1358b5e475c0ee13497006004b7917e8d64b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 18 May 2023 15:45:24 -0400 Subject: [PATCH 397/468] merge --- .../TrackingDiagnostics/TrackResiduals.cc | 285 ++++++++++-------- .../TrackingDiagnostics/TrackResiduals.h | 9 + 2 files changed, 161 insertions(+), 133 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 95da333010..ef88825aae 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -142,8 +142,6 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } - ActsTransformations transformer; - if (Verbosity() > 1) { std::cout << "Track map size is " << trackmap->size() << std::endl; @@ -198,146 +196,57 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) for (const auto& ckey : get_cluster_keys(track)) { - TrkrCluster* cluster = clustermap->findCluster(ckey); - switch (TrkrDefs::getTrkrId(ckey)) - { - case TrkrDefs::mvtxId: - m_nmaps++; - break; - case TrkrDefs::inttId: - m_nintt++; - break; - case TrkrDefs::tpcId: - m_ntpc++; - break; - case TrkrDefs::micromegasId: - m_nmms++; - break; - } - - Acts::Vector3 clusglob = geometry->getGlobalPosition(ckey, cluster); - - auto matched_state = track->begin_states(); - float drmin = -1; - float clusr = r(clusglob.x(), clusglob.y()); - - for (auto state_iter = track->begin_states(); - state_iter != track->end_states(); - ++state_iter) - { - SvtxTrackState* state = state_iter->second; - float stater = r(state->get_x(), state->get_y()); - float thisdr = std::abs(clusr - stater); - if (drmin < 0 or thisdr < drmin) - { - matched_state = state_iter; - drmin = thisdr; - } - else - { - break; - } - } - - SvtxTrackState* state = matched_state->second; - - //! have cluster and state, fill vectors - m_cluslx.push_back(cluster->getLocalX()); - float clusz = cluster->getLocalY(); - if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::tpcId) - { - clusz = convertTimeToZ(geometry, ckey, cluster); - } - m_cluslz.push_back(clusz); - m_cluselx.push_back(cluster->getRPhiError()); - m_cluselz.push_back(cluster->getZError()); - m_clusgx.push_back(clusglob.x()); - m_clusgy.push_back(clusglob.y()); - m_clusgz.push_back(clusglob.z()); - m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); - m_clussize.push_back(cluster->getPhiSize() + cluster->getZSize()); - - if (Verbosity() > 1) - { - std::cout << "Track state/clus in layer " - << TrkrDefs::getLayer(ckey) << std::endl; - } - - auto surf = geometry->maps().getSurface(ckey, cluster); - Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); - Acts::Vector2 stateloc; - auto norm = surf->normal(geometry->geometry().getGeoContext()); - auto result = surf->globalToLocal(geometry->geometry().getGeoContext(), - stateglob * Acts::UnitConstants::cm, - norm); - if (result.ok()) - { - stateloc = result.value() / Acts::UnitConstants::cm; - } - else - { - //! manual transform for tpc - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); - loct /= Acts::UnitConstants::cm; - stateloc(0) = loct(0); - stateloc(1) = loct(1); - } - - const Acts::BoundSymMatrix actscov = - transformer.rotateSvtxTrackCovToActs(state); - - m_statelx.push_back(stateloc(0)); - m_statelz.push_back(stateloc(1)); - m_stateelx.push_back(std::sqrt(actscov(Acts::eBoundLoc0, Acts::eBoundLoc0)) / Acts::UnitConstants::cm); - m_stateelz.push_back(std::sqrt(actscov(Acts::eBoundLoc1, Acts::eBoundLoc1)) / Acts::UnitConstants::cm); - m_stategx.push_back(state->get_x()); - m_stategy.push_back(state->get_y()); - m_stategz.push_back(state->get_z()); - m_statepx.push_back(state->get_px()); - m_statepy.push_back(state->get_py()); - m_statepz.push_back(state->get_pz()); - m_statepl.push_back(state->get_pathlength()); + fillClusterBranches(ckey, track, topNode); } m_nhits = m_nmaps + m_nintt + m_ntpc + m_nmms; - if (alignmentmap and alignmentmap->find(key) != alignmentmap->end()) + if (m_doAlignment) { - auto& statevec = alignmentmap->find(key)->second; + /// repopulate with info that is going into alignment + clearClusterStateVectors(); - for (auto& state : statevec) + if (alignmentmap and alignmentmap->find(key) != alignmentmap->end()) { - auto& globderivs = state->get_global_derivative_matrix(); - auto& locderivs = state->get_local_derivative_matrix(); - - m_statelxglobderivdalpha.push_back(globderivs(0, 0)); - m_statelxglobderivdbeta.push_back(globderivs(0, 1)); - m_statelxglobderivdgamma.push_back(globderivs(0, 2)); - m_statelxglobderivdx.push_back(globderivs(0, 3)); - m_statelxglobderivdy.push_back(globderivs(0, 4)); - m_statelxglobderivdz.push_back(globderivs(0, 5)); - - m_statelzglobderivdalpha.push_back(globderivs(1, 0)); - m_statelzglobderivdbeta.push_back(globderivs(1, 1)); - m_statelzglobderivdgamma.push_back(globderivs(1, 2)); - m_statelzglobderivdx.push_back(globderivs(1, 3)); - m_statelzglobderivdy.push_back(globderivs(1, 4)); - m_statelzglobderivdz.push_back(globderivs(1, 5)); - - m_statelxlocderivd0.push_back(locderivs(0, 0)); - m_statelxlocderivz0.push_back(locderivs(0, 1)); - m_statelxlocderivphi.push_back(locderivs(0, 2)); - m_statelxlocderivtheta.push_back(locderivs(0, 3)); - m_statelxlocderivqop.push_back(locderivs(0, 4)); - - m_statelzlocderivd0.push_back(locderivs(1, 0)); - m_statelzlocderivz0.push_back(locderivs(1, 1)); - m_statelzlocderivphi.push_back(locderivs(1, 2)); - m_statelzlocderivtheta.push_back(locderivs(1, 3)); - m_statelzlocderivqop.push_back(locderivs(1, 4)); + auto& statevec = alignmentmap->find(key)->second; + + for (auto& state : statevec) + { + auto ckey = state->get_cluster_key(); + + fillClusterBranches(ckey, track, topNode); + + auto& globderivs = state->get_global_derivative_matrix(); + auto& locderivs = state->get_local_derivative_matrix(); + + m_statelxglobderivdalpha.push_back(globderivs(0, 0)); + m_statelxglobderivdbeta.push_back(globderivs(0, 1)); + m_statelxglobderivdgamma.push_back(globderivs(0, 2)); + m_statelxglobderivdx.push_back(globderivs(0, 3)); + m_statelxglobderivdy.push_back(globderivs(0, 4)); + m_statelxglobderivdz.push_back(globderivs(0, 5)); + + m_statelzglobderivdalpha.push_back(globderivs(1, 0)); + m_statelzglobderivdbeta.push_back(globderivs(1, 1)); + m_statelzglobderivdgamma.push_back(globderivs(1, 2)); + m_statelzglobderivdx.push_back(globderivs(1, 3)); + m_statelzglobderivdy.push_back(globderivs(1, 4)); + m_statelzglobderivdz.push_back(globderivs(1, 5)); + + m_statelxlocderivd0.push_back(locderivs(0, 0)); + m_statelxlocderivz0.push_back(locderivs(0, 1)); + m_statelxlocderivphi.push_back(locderivs(0, 2)); + m_statelxlocderivtheta.push_back(locderivs(0, 3)); + m_statelxlocderivqop.push_back(locderivs(0, 4)); + + m_statelzlocderivd0.push_back(locderivs(1, 0)); + m_statelzlocderivz0.push_back(locderivs(1, 1)); + m_statelzlocderivphi.push_back(locderivs(1, 2)); + m_statelzlocderivtheta.push_back(locderivs(1, 3)); + m_statelzlocderivqop.push_back(locderivs(1, 4)); + } } } - m_tree->Fill(); } @@ -369,6 +278,115 @@ int TrackResiduals::End(PHCompositeNode*) return Fun4AllReturnCodes::EVENT_OK; } +void TrackResiduals::fillClusterBranches(TrkrDefs::cluskey ckey, SvtxTrack* track, + PHCompositeNode* topNode) +{ + auto clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); + auto geometry = findNode::getClass(topNode, "ActsGeometry"); + + ActsTransformations transformer; + TrkrCluster* cluster = clustermap->findCluster(ckey); + switch (TrkrDefs::getTrkrId(ckey)) + { + case TrkrDefs::mvtxId: + m_nmaps++; + break; + case TrkrDefs::inttId: + m_nintt++; + break; + case TrkrDefs::tpcId: + m_ntpc++; + break; + case TrkrDefs::micromegasId: + m_nmms++; + break; + } + + Acts::Vector3 clusglob = geometry->getGlobalPosition(ckey, cluster); + + auto matched_state = track->begin_states(); + float drmin = -1; + float clusr = r(clusglob.x(), clusglob.y()); + + for (auto state_iter = track->begin_states(); + state_iter != track->end_states(); + ++state_iter) + { + SvtxTrackState* state = state_iter->second; + float stater = r(state->get_x(), state->get_y()); + float thisdr = std::abs(clusr - stater); + if (drmin < 0 or thisdr < drmin) + { + matched_state = state_iter; + drmin = thisdr; + } + else + { + break; + } + } + + SvtxTrackState* state = matched_state->second; + + //! have cluster and state, fill vectors + m_cluslx.push_back(cluster->getLocalX()); + float clusz = cluster->getLocalY(); + + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::tpcId) + { + clusz = convertTimeToZ(geometry, ckey, cluster); + } + m_cluslz.push_back(clusz); + m_cluselx.push_back(cluster->getRPhiError()); + m_cluselz.push_back(cluster->getZError()); + m_clusgx.push_back(clusglob.x()); + m_clusgy.push_back(clusglob.y()); + m_clusgz.push_back(clusglob.z()); + m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getPhiSize() + cluster->getZSize()); + m_clushitsetkey.push_back(TrkrDefs::getHitSetKeyFromClusKey(ckey)); + + if (Verbosity() > 1) + { + std::cout << "Track state/clus in layer " + << TrkrDefs::getLayer(ckey) << std::endl; + } + + auto surf = geometry->maps().getSurface(ckey, cluster); + Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + Acts::Vector2 stateloc; + auto norm = surf->normal(geometry->geometry().getGeoContext()); + auto result = surf->globalToLocal(geometry->geometry().getGeoContext(), + stateglob * Acts::UnitConstants::cm, + norm); + if (result.ok()) + { + stateloc = result.value() / Acts::UnitConstants::cm; + } + else + { + //! manual transform for tpc + Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); + loct /= Acts::UnitConstants::cm; + stateloc(0) = loct(0); + stateloc(1) = loct(1); + } + + const Acts::BoundSymMatrix actscov = + transformer.rotateSvtxTrackCovToActs(state); + + m_statelx.push_back(stateloc(0)); + m_statelz.push_back(stateloc(1)); + m_stateelx.push_back(std::sqrt(actscov(Acts::eBoundLoc0, Acts::eBoundLoc0)) / Acts::UnitConstants::cm); + m_stateelz.push_back(std::sqrt(actscov(Acts::eBoundLoc1, Acts::eBoundLoc1)) / Acts::UnitConstants::cm); + m_stategx.push_back(state->get_x()); + m_stategy.push_back(state->get_y()); + m_stategz.push_back(state->get_z()); + m_statepx.push_back(state->get_px()); + m_statepy.push_back(state->get_py()); + m_statepz.push_back(state->get_pz()); + m_statepl.push_back(state->get_pathlength()); +} void TrackResiduals::createBranches() { m_tree = new TTree("residualtree", "A tree with track, cluster, and state info"); @@ -406,6 +424,7 @@ void TrackResiduals::createBranches() m_tree->Branch("clusgz", &m_clusgz); m_tree->Branch("cluslayer", &m_cluslayer); m_tree->Branch("clussize", &m_clussize); + m_tree->Branch("clushitsetkey", &m_clushitsetkey); m_tree->Branch("statelx", &m_statelx); m_tree->Branch("statelz", &m_statelz); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index ecd7296b9a..6ea73562df 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -19,6 +19,7 @@ class TrkrCluster; class PHCompositeNode; class ActsGeometry; +class SvtxTrack; class TrackResiduals : public SubsysReco { @@ -32,15 +33,22 @@ class TrackResiduals : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; void outfileName(std::string name) { m_outfileName = name; } + void alignment(bool align) { m_doAlignment = align; } private: void clearClusterStateVectors(); void createBranches(); float convertTimeToZ(ActsGeometry *geometry, TrkrDefs::cluskey cluster_key, TrkrCluster *cluster); + + void fillClusterBranches(TrkrDefs::cluskey ckey, SvtxTrack *track, + PHCompositeNode *topNode); + std::string m_outfileName = ""; TFile *m_outfile = nullptr; TTree *m_tree = nullptr; + bool m_doAlignment = false; + int m_event = 0; //! Track level quantities unsigned int m_trackid = std::numeric_limits::quiet_NaN(); @@ -79,6 +87,7 @@ class TrackResiduals : public SubsysReco std::vector m_clusgz; std::vector m_cluslayer; std::vector m_clussize; + std::vector m_clushitsetkey; //! states on track information std::vector m_statelx; From f0f18c30b95c8cfa6d476d313ccea31adfe4c59a Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 18 May 2023 17:37:44 -0400 Subject: [PATCH 398/468] Adding ability to set sector number for output file data --- .../tpc/TPCPedestalCalibration/TPCPedestalCalibration.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h index fd11c4facf..101bcde7a1 100644 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.h @@ -32,6 +32,11 @@ class TPCPedestalCalibration : public SubsysReco m_packets.push_back(packet); } + void SetSector(int sectorNum) + { + m_sector = sectorNum; + } + protected: //! which packet to decode std::vector m_packets{1001}; From a1f82d63a5496978502a0d6c62f6ab68418acbf6 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 18 May 2023 18:40:46 -0400 Subject: [PATCH 399/468] Added raw data dedicated evaluation module. This feels a simple tree useful for calibration, signal timing, etc. --- offline/packages/micromegas/Makefile.am | 6 +- .../micromegas/MicromegasRawDataEvaluation.cc | 158 ++++++++++++++++++ .../micromegas/MicromegasRawDataEvaluation.h | 88 ++++++++++ .../MicromegasRawDataEvaluationLinkDef.h | 5 + 4 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 offline/packages/micromegas/MicromegasRawDataEvaluation.cc create mode 100644 offline/packages/micromegas/MicromegasRawDataEvaluation.h create mode 100644 offline/packages/micromegas/MicromegasRawDataEvaluationLinkDef.h diff --git a/offline/packages/micromegas/Makefile.am b/offline/packages/micromegas/Makefile.am index 5c4b0e9b7b..def022a6eb 100644 --- a/offline/packages/micromegas/Makefile.am +++ b/offline/packages/micromegas/Makefile.am @@ -66,6 +66,7 @@ pkginclude_HEADERS = \ MicromegasMapping.h \ MicromegasRawDataCalibration.h \ MicromegasRawDataDecoder.h \ + MicromegasRawDataEvaluation.h \ MicromegasTile.h ROOTDICTS = \ @@ -75,6 +76,7 @@ ROOTDICTS = \ pcmdir = $(libdir) nobase_dist_pcm_DATA = \ CylinderGeomMicromegas_Dict_rdict.pcm \ + MicromegasRawDataEvaluation_Dict_rdict.pcm \ MicromegasTile_Dict_rdict.pcm libmicromegas_io_la_SOURCES = \ @@ -95,7 +97,9 @@ libmicromegas_io_la_LIBADD = \ libmicromegas_la_SOURCES = \ MicromegasClusterizer.cc \ MicromegasRawDataCalibration.cc \ - MicromegasRawDataDecoder.cc + MicromegasRawDataDecoder.cc \ + MicromegasRawDataEvaluation.cc \ + MicromegasRawDataEvaluation_Dict.cc libmicromegas_la_LIBADD = \ libmicromegas_io.la \ diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluation.cc b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc new file mode 100644 index 0000000000..d9eb66ea33 --- /dev/null +++ b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc @@ -0,0 +1,158 @@ +/*! + * \file MicromegasRawDataEvaluation.cc + * \author Hugo Pereira Da Costa + */ + +#include "MicromegasRawDataEvaluation.h" +#include "MicromegasDefs.h" + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +//_________________________________________________________ +void MicromegasRawDataEvaluation::Container::Reset() +{ + n_waveforms = 0; + samples.clear(); +} + +//_________________________________________________________ +MicromegasRawDataEvaluation::MicromegasRawDataEvaluation( const std::string& name ): + SubsysReco( name ) +{} + +//_____________________________________________________________________ +int MicromegasRawDataEvaluation::Init(PHCompositeNode* /*topNode*/ ) +{ + m_evaluation_file.reset( new TFile( m_evaluation_filename.c_str(), "RECREATE" ) ); + m_evaluation_tree = new TTree( "T", "T" ); + m_container = new Container; + m_evaluation_tree->Branch( "Event", &m_container ); + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasRawDataEvaluation::InitRun(PHCompositeNode* /*topNode*/) +{ return Fun4AllReturnCodes::EVENT_OK; } + +//___________________________________________________________________________ +int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) +{ + + // map fee id to detector index in histogram + using fee_map_t = std::map; + fee_map_t fee_map = { + {5, 0}, // SEIP + {7, 1}, // SEIZ + {6, 2}, // SCOP + {8, 3}, // SCOZ + {9, 4}, // SCIP + {10, 5}, // SCIZ + {24, 6}, // SWIP + {25, 7}, // SWIZ + + {11, 8}, // NEIP + {12, 9}, // NEIZ + {19, 10}, // NCOP + {18, 11}, // NCOZ + {0, 12}, // NCIP + {1, 13}, // NCIZ + {15, 14}, // NWIP + {14, 15}, // NWIZ + }; + + // load relevant nodes + // PRDF node + auto event = findNode::getClass(topNode, "PRDF"); + assert( event ); + + // check event type + if(event->getEvtType() >= 8) + { return Fun4AllReturnCodes::DISCARDEVENT; } + + // get TPOT packet number + /* + * for now it is the same packet number as the TPC: 4001. + * To be fixed at a later stage. + * check with Martin Purschke + */ + std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); + if( !packet ) + { + // no data + std::cout << "MicromegasRawDataEvaluation::process_event - event contains no TPOT data" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + m_container->Reset(); + + // get number of datasets (also call waveforms) + const auto n_waveforms = packet->iValue(0, "NR_WF" ); + m_container->n_waveforms = n_waveforms; + if( Verbosity() ) + { std::cout << "MicromegasRawDataEvaluation::process_event - n_waveforms: " << n_waveforms << std::endl; } + + for( int i=0; iiValue( i, "CHANNEL" ); + const unsigned short fee = packet->iValue(i, "FEE" ); + + // get hitsetkey, layer and tile + const auto hitsetkey = m_mapping.get_hitsetkey(fee); + const unsigned short layer = TrkrDefs::getLayer( hitsetkey ); + const unsigned short tile = MicromegasDefs::getTileId( hitsetkey ); + + // get detector index and absolute channel number + const unsigned short det_index = fee_map[fee]; + const unsigned short absolute_channel = channel + det_index*MicromegasDefs::m_nchannels_fee; + + // get number of samples and loop + const unsigned short samples = packet->iValue( i, "SAMPLES" ); + for( unsigned short is = 0; is < samples; ++is ) + { + unsigned short adc = packet->iValue(i,is); + m_container->samples.push_back( + Sample{ + .fee_id = fee, + .layer = layer, + .tile = tile, + .channel = channel, + .absolute_channel = absolute_channel, + .sample = is, + .adc = adc + }); + } + + } + + m_evaluation_tree->Fill(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int MicromegasRawDataEvaluation::End(PHCompositeNode* /*topNode*/ ) +{ + if( m_evaluation_file && m_evaluation_tree ) + { + m_evaluation_file->cd(); + m_evaluation_tree->Write(); + m_evaluation_file->Close(); + } + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluation.h b/offline/packages/micromegas/MicromegasRawDataEvaluation.h new file mode 100644 index 0000000000..d52e276e91 --- /dev/null +++ b/offline/packages/micromegas/MicromegasRawDataEvaluation.h @@ -0,0 +1,88 @@ +#ifndef MICROMEGAS_MicromegasRawDataEvaluation_H +#define MICROMEGAS_MicromegasRawDataEvaluation_H + +/*! + * \file MicromegasRawDataEvaluation.h + * \author Hugo Pereira Da Costa + */ + +#include "MicromegasMapping.h" + +#include +#include + +#include + +#include +#include +#include + +class PHCompositeNode; +class TFile; +class TH1; +class TH2; +class TProfile; + +/// micromegas raw data decoder +class MicromegasRawDataEvaluation : public SubsysReco +{ + public: + + /// constructor + MicromegasRawDataEvaluation( const std::string &name = "MicromegasRawDataEvaluation" ); + + /// global initialization + int Init(PHCompositeNode*) override; + + /// run initialization + int InitRun(PHCompositeNode*) override; + + /// event processing + int process_event(PHCompositeNode*) override; + + /// end of processing + int End(PHCompositeNode*) override; + + /// output file name for evaluation histograms + void set_evaluation_outputfile(const std::string &outputfile) {m_evaluation_filename = outputfile;} + + class Sample + { + public: + unsigned short fee_id = 0; + unsigned short layer = 0; + unsigned short tile = 0; + unsigned short channel = 0; + unsigned short absolute_channel = 0; + unsigned short sample = 0; + unsigned short adc = 0; + using List = std::vector; + }; + + class Container: public PHObject + { + public: + void Reset(); + int n_waveforms = 0; + Sample::List samples; + ClassDef(Container,1) + }; + + private: + + // evaluation output filename + std::string m_evaluation_filename = "MicromegasRawDataEvaluation.root"; + std::unique_ptr m_evaluation_file; + + // mapping + MicromegasMapping m_mapping; + + // tree + TTree* m_evaluation_tree = nullptr; + + // main branch + Container* m_container = nullptr; + +}; + +#endif diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluationLinkDef.h b/offline/packages/micromegas/MicromegasRawDataEvaluationLinkDef.h new file mode 100644 index 0000000000..cb6f58bc9d --- /dev/null +++ b/offline/packages/micromegas/MicromegasRawDataEvaluationLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MicromegasRawDataEvaluation::Container+; + +#endif /* __CINT__ */ From f983e0b823f3cd6b057c6176bd34f236dfed428c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 18 May 2023 18:41:17 -0400 Subject: [PATCH 400/468] removed evaluation histograms. They were redundant and less flexible than those from MicromegasRawDataEvaluation. --- .../MicromegasRawDataCalibration.cc | 83 ------------------- .../micromegas/MicromegasRawDataCalibration.h | 27 ------ 2 files changed, 110 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 36084056f5..6e82703180 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -6,7 +6,6 @@ #include "MicromegasRawDataCalibration.h" #include "MicromegasCalibrationData.h" #include "MicromegasDefs.h" -#include "MicromegasMapping.h" #include #include @@ -18,8 +17,6 @@ #include #include -#include -#include #include #include @@ -34,11 +31,7 @@ MicromegasRawDataCalibration::MicromegasRawDataCalibration( const std::string& n //_____________________________________________________________________ int MicromegasRawDataCalibration::Init(PHCompositeNode* /*topNode*/ ) { - - MicromegasMapping(); - // histogram evaluation - if( m_savehistograms ) create_histograms(); return Fun4AllReturnCodes::EVENT_OK; } @@ -50,28 +43,6 @@ int MicromegasRawDataCalibration::InitRun(PHCompositeNode* /*topNode*/) int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) { - // map fee id to detector index in histogram - using fee_map_t = std::map; - fee_map_t fee_map = { - {5, 0}, // SEIP - {7, 1}, // SEIZ - {6, 2}, // SCOP - {8, 3}, // SCOZ - {9, 4}, // SCIP - {10, 5}, // SCIZ - {24, 6}, // SWIP - {25, 7}, // SWIZ - - {11, 8}, // NEIP - {12, 9}, // NEIZ - {19, 10}, // NCOP - {18, 11}, // NCOZ - {0, 12}, // NCIP - {1, 13}, // NCIZ - {15, 14}, // NWIP - {14, 15}, // NWIZ - }; - // load relevant nodes // PRDF node auto event = findNode::getClass(topNode, "PRDF"); @@ -132,29 +103,6 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) { profile->Fill( channel, packet->iValue(i,is) ); } - // fill evaluation histograms - if( m_savehistograms ) - { - if( m_h_fee_id ) m_h_fee_id->Fill(fee); - - // find fee index from map - const auto iter = fee_map.find( fee ); - if( iter == fee_map.end() ) - { - std::cout << "MicromegasRawDataCalibration::process_event - unable to find fee " << fee << " in map" << std::endl; - } else { - - const auto fee_index = iter->second; - const auto channel_index = fee_index*MicromegasDefs::m_nchannels_fee + channel; - - // loop over samples - if( m_h_adc_channel ) - { - for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) - { m_h_adc_channel->Fill( channel_index, packet->iValue(i,is) ); } - } - } - } } return Fun4AllReturnCodes::EVENT_OK; @@ -185,36 +133,5 @@ int MicromegasRawDataCalibration::End(PHCompositeNode* /*topNode*/ ) calibration_data.write( m_calibration_filename ); } - // save evaluation histograms - if( m_savehistograms && m_histogramfile ) - { - // create mean and rms histograms - auto profile = m_h_adc_channel->ProfileX("h_adc_channel_profx", 1, -1, "s" ); - auto h_pedestal = new TH1F( "h_pedestal", "pedestal vs channel;channel;pedestal (adc)", MicromegasDefs::m_nchannels_total, 0, MicromegasDefs::m_nchannels_total ); - auto h_rms = new TH1F( "h_rms", "rms vs channel;channel;RMS (adc)", MicromegasDefs::m_nchannels_total, 0, MicromegasDefs::m_nchannels_total ); - for( int i =0; iSetBinContent( i+1, profile->GetBinContent(i+1) ); - h_rms->SetBinContent(i+1, profile->GetBinError(i+1) ); - } - - m_histogramfile->cd(); - m_h_fee_id->Write(); - m_h_adc_channel->Write(); - h_pedestal->Write(); - h_rms->Write(); - m_histogramfile->Close(); - } return Fun4AllReturnCodes::EVENT_OK; } - -//_____________________________________________________________________ -void MicromegasRawDataCalibration::create_histograms() -{ - std::cout << "MicromegasRawDataCalibration::create_histograms - writing evaluation histograms to: " << m_histogramfilename << std::endl; - m_histogramfile.reset( new TFile(m_histogramfilename.c_str(), "RECREATE") ); - m_histogramfile->cd(); - - m_h_fee_id = new TH1I( "h_fee_id", "FEE id;Fee id;entries", 10, 0, 10 ); - m_h_adc_channel = new TH2I( "h_adc_channel", "ADC vs channel;channel;adc", MicromegasDefs::m_nchannels_total, 0, MicromegasDefs::m_nchannels_total, MicromegasDefs::m_max_adc, 0, MicromegasDefs::m_max_adc ); -} diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.h b/offline/packages/micromegas/MicromegasRawDataCalibration.h index d65f3e9c4f..1604900584 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.h +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.h @@ -46,17 +46,8 @@ class MicromegasRawDataCalibration : public SubsysReco /// set to true to store evaluation histograms and ntuples void set_calibration_file( const std::string& value ) { m_calibration_filename = value; } - /// set to true to store evaluation histograms and ntuples - void set_save_histograms( bool value ) { m_savehistograms = value; } - - /// output file name for evaluation histograms - void set_histogram_outputfile(const std::string &outputfile) {m_histogramfilename = outputfile;} - private: - /// create evaluation histograms - void create_histograms(); - /// min sample for noise estimation int m_sample_min = 0; @@ -70,24 +61,6 @@ class MicromegasRawDataCalibration : public SubsysReco using profile_map_t = std::map; profile_map_t m_profile_map; - ///@name evaluation histograms - //@{ - - /// Output root histograms - bool m_savehistograms = true; - - /// histogram output file name - std::string m_histogramfilename = "MicromegasRawDataCalibration.root"; - std::unique_ptr m_histogramfile; - - /// Fired FEE - TH1* m_h_fee_id = nullptr; - - /// ADC distribution vs channel number - TH2* m_h_adc_channel = nullptr; - - //@} - }; #endif From 9e1a7a037800cf153777b7fba7e9239e685939d0 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Thu, 18 May 2023 19:29:18 -0400 Subject: [PATCH 401/468] new stepping action that directly put light yield into towerinfo --- .../g4simulation/g4detectors/Makefile.am | 1 + .../g4detectors/PHG4FullProjSpacalCellReco.cc | 130 ++---------------- .../g4detectors/PHG4FullProjSpacalCellReco.h | 46 +------ .../g4detectors/PHG4SpacalSteppingAction.cc | 71 +++++++--- .../g4detectors/PHG4SpacalSteppingAction.h | 5 +- .../g4detectors/PHG4SpacalSubsystem.cc | 9 +- .../g4detectors/PHG4SpacalSubsystem.h | 1 + 7 files changed, 76 insertions(+), 187 deletions(-) diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index cc307c68fe..e86cef946d 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -93,6 +93,7 @@ pkginclude_HEADERS = \ PHG4SectorConstructor.h \ PHG4SectorSubsystem.h \ PHG4SpacalSubsystem.h \ + PHG4SpacalSteppingAction.h \ PHG4StepStatusDecode.h \ PHG4TpcCylinderGeom.h \ PHG4TpcCylinderGeomContainer.h \ diff --git a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc index b160160716..d6ede34bff 100644 --- a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc +++ b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.cc @@ -1,10 +1,11 @@ #include "PHG4FullProjSpacalCellReco.h" +#include "LightCollectionModel.h" #include "PHG4Cell.h" // for PHG4Cell #include "PHG4CylinderCellGeom.h" #include "PHG4CylinderCellGeomContainer.h" #include "PHG4CylinderCellGeom_Spacalv1.h" -#include "PHG4CylinderGeom.h" // for PHG4CylinderGeom +#include "PHG4CylinderGeom.h" // for PHG4CylinderGeom #include "PHG4CylinderGeomContainer.h" #include "PHG4CylinderGeom_Spacalv1.h" // for PHG4CylinderGeom_Spaca... #include "PHG4CylinderGeom_Spacalv3.h" @@ -25,11 +26,11 @@ #include #include -#include // for PHNode +#include // for PHNode #include #include // for PHObject #include -#include // for PHWHERE +#include // for PHWHERE #include #include @@ -181,14 +182,14 @@ int PHG4FullProjSpacalCellReco::InitRun(PHCompositeNode *topNode) if (tower_ID_phi == 0) { - //assign phi min according phi bin 0 + // assign phi min according phi bin 0 phi_min = M_PI_2 - deltaphi * (layergeom->get_max_phi_bin_in_sec() * layergeom->get_n_subtower_phi() / 2) // shift of first tower in sector + sector_map.begin()->second; } if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) { - //assign eta min according phi bin 0 + // assign eta min according phi bin 0 map_z_tower_z_ID[tower.centralZ] = tower_ID_z; } // ... @@ -211,7 +212,7 @@ int PHG4FullProjSpacalCellReco::InitRun(PHCompositeNode *topNode) layerseggeo->set_etamin(NAN); layerseggeo->set_etastep(NAN); - //build eta bin maps + // build eta bin maps for (const auto &tower_pair : tower_map) { const int &tower_ID = tower_pair.first; @@ -229,7 +230,8 @@ int PHG4FullProjSpacalCellReco::InitRun(PHCompositeNode *topNode) const double dz = fabs(0.5 * (tower.pDy1 + tower.pDy2) / sin(tower.pRotationAngleX)); const double tower_radial = layergeom->get_tower_radial_position(tower); - auto z_to_eta = [&tower_radial](const double &z) { return -log(tan(0.5 * atan2(tower_radial, z))); }; + auto z_to_eta = [&tower_radial](const double &z) + { return -log(tan(0.5 * atan2(tower_radial, z))); }; const double eta_central = z_to_eta(tower.centralZ); // half eta-range @@ -421,6 +423,7 @@ int PHG4FullProjSpacalCellReco::process_event(PHCompositeNode *topNode) double light_yield = hiter->second->get_light_yield(); // light yield correction from fiber attenuation: + if (light_collection_model.use_fiber_model()) { const double z = 0.5 * (hiter->second->get_local_z(0) + hiter->second->get_local_z(1)); @@ -428,6 +431,7 @@ int PHG4FullProjSpacalCellReco::process_event(PHCompositeNode *topNode) light_yield *= light_collection_model.get_fiber_transmission(z); } + // light yield correction from light guide collection efficiency: if (light_collection_model.use_fiber_model()) @@ -437,7 +441,6 @@ int PHG4FullProjSpacalCellReco::process_event(PHCompositeNode *topNode) light_yield *= light_collection_model.get_light_guide_efficiency(x, y); } - cell->add_edep(hiter->first, hiter->second->get_edep()); cell->add_edep(hiter->second->get_edep()); cell->add_light_yield(light_yield); @@ -514,117 +517,6 @@ int PHG4FullProjSpacalCellReco::CheckEnergy(PHCompositeNode *topNode) return 0; } -PHG4FullProjSpacalCellReco::LightCollectionModel::LightCollectionModel() -{ - data_grid_light_guide_efficiency_verify = new TH2F("data_grid_light_guide_efficiency_verify", - "light collection efficiency as used in PHG4FullProjSpacalCellReco::LightCollectionModel;x positio fraction;y position fraction", // - 100, 0., 1., 100, 0., 1.); - - data_grid_fiber_trans_verify = new TH1F("data_grid_fiber_trans", - "SCSF-78 Fiber Transmission as used in PHG4FullProjSpacalCellReco::LightCollectionModel;position in fiber (cm);Effective transmission", - 100, -15, 15); - - // register histograms - Fun4AllServer *se = Fun4AllServer::instance(); - - se->registerHisto(data_grid_light_guide_efficiency_verify); - se->registerHisto(data_grid_fiber_trans_verify); -} - -PHG4FullProjSpacalCellReco::LightCollectionModel::~LightCollectionModel() -{ - delete data_grid_light_guide_efficiency; - delete data_grid_fiber_trans; -} - -void PHG4FullProjSpacalCellReco::LightCollectionModel::load_data_from_CDB( - const std::string &domain, - const std::string &histogram_light_guide_model, - const std::string &histogram_fiber_model) -{ - recoConsts *rc = recoConsts::instance(); - std::string url = CDBInterface::instance()->getUrl(domain); - if (url.empty()) - { - std::cout << "No calibration for domain " << domain << " for timestamp " << rc->get_uint64Flag("TIMESTAMP") << std::endl; - gSystem->Exit(1); - } - TFile *fin = TFile::Open(url.c_str()); - if (!fin) - { - std::cout << "could not open " << url << std::endl; - gSystem->Exit(1); - } - if (data_grid_light_guide_efficiency) delete data_grid_light_guide_efficiency; - data_grid_light_guide_efficiency = dynamic_cast(fin->Get(histogram_light_guide_model.c_str())); - assert(data_grid_light_guide_efficiency); - data_grid_light_guide_efficiency->SetDirectory(nullptr); - if (data_grid_fiber_trans) delete data_grid_fiber_trans; - data_grid_fiber_trans = dynamic_cast(fin->Get(histogram_fiber_model.c_str())); - assert(data_grid_fiber_trans); - data_grid_fiber_trans->SetDirectory(nullptr); - delete fin; -} - -void PHG4FullProjSpacalCellReco::LightCollectionModel::load_data_file( - const std::string &input_file, - const std::string &histogram_light_guide_model, - const std::string &histogram_fiber_model) -{ - TFile *fin = TFile::Open(input_file.c_str()); - - assert(fin); - assert(fin->IsOpen()); - - if (data_grid_light_guide_efficiency) delete data_grid_light_guide_efficiency; - data_grid_light_guide_efficiency = dynamic_cast(fin->Get(histogram_light_guide_model.c_str())); - assert(data_grid_light_guide_efficiency); - data_grid_light_guide_efficiency->SetDirectory(nullptr); - - if (data_grid_fiber_trans) delete data_grid_fiber_trans; - data_grid_fiber_trans = dynamic_cast(fin->Get(histogram_fiber_model.c_str())); - assert(data_grid_fiber_trans); - data_grid_fiber_trans->SetDirectory(nullptr); - - delete fin; -} - -double -PHG4FullProjSpacalCellReco::LightCollectionModel::get_light_guide_efficiency(const double x_fraction, const double y_fraction) -{ - assert(data_grid_light_guide_efficiency); - assert(x_fraction >= 0); - assert(x_fraction <= 1); - assert(y_fraction >= 0); - assert(y_fraction <= 1); - - const double eff = data_grid_light_guide_efficiency->Interpolate(x_fraction, - y_fraction); - - data_grid_light_guide_efficiency_verify->SetBinContent( // - data_grid_light_guide_efficiency_verify->GetXaxis()->FindBin(x_fraction), // - data_grid_light_guide_efficiency_verify->GetYaxis()->FindBin(y_fraction), // - eff // - ); - - return eff; -} - -double -PHG4FullProjSpacalCellReco::LightCollectionModel::get_fiber_transmission(const double z_distance) -{ - assert(data_grid_fiber_trans); - - const double eff = data_grid_fiber_trans->Interpolate(z_distance); - - data_grid_fiber_trans_verify->SetBinContent( // - data_grid_fiber_trans_verify->GetXaxis()->FindBin(z_distance), // - eff // - ); - - return eff; -} - void PHG4FullProjSpacalCellReco::SetDefaultParameters() { set_default_double_param("tmax", 60.0); diff --git a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.h b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.h index 58ee252046..ec98aa0e49 100644 --- a/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.h +++ b/simulation/g4simulation/g4detectors/PHG4FullProjSpacalCellReco.h @@ -3,6 +3,8 @@ #ifndef G4DETECTORS_PHG4FULLPROJSPACALCELLRECO_H #define G4DETECTORS_PHG4FULLPROJSPACALCELLRECO_H +#include "LightCollectionModel.h" + #include #include @@ -11,6 +13,7 @@ #include #include +class LightCollectionModel; class PHCompositeNode; class PHG4Cell; class TH2; @@ -40,49 +43,6 @@ class PHG4FullProjSpacalCellReco : public SubsysReco, public PHParameterInterfac void set_timing_window(const double tmin, const double tmax); - class LightCollectionModel - { - public: - LightCollectionModel(); - - //! delete copy ctor and assignment opertor (cppcheck) - explicit LightCollectionModel(const LightCollectionModel &) = delete; - LightCollectionModel &operator=(const LightCollectionModel &) = delete; - - virtual ~LightCollectionModel(); - - //! input data file - void load_data_file(const std::string &input_file, const std::string &histogram_light_guide_model, const std::string &histogram_fiber_model); - - //! load from CDB - void load_data_from_CDB(const std::string &domain, const std::string &histogram_light_guide_model, const std::string &histogram_fiber_model); - - //! Whether use light collection model - bool use_light_guide_model() const { return data_grid_light_guide_efficiency != nullptr; } - - //! Whether use Light Transmission Efficiency model for the fiber - bool use_fiber_model() const { return data_grid_fiber_trans != nullptr; } - - //! get Light Collection Efficiency for the light guide as function of x,y position in fraction of tower width - double get_light_guide_efficiency(const double x_fraction, const double y_fraction); - - //! get Light Transmission Efficiency for the fiber as function of z position (cm) in the fiber. Z=0 is at the middle of the fiber - double get_fiber_transmission(const double z_distance); - - private: - //! 2-D data grid for Light Collection Efficiency for the light guide as function of x,y position in fraction of tower width - TH2 *data_grid_light_guide_efficiency = nullptr; - - //! 1-D data grid for the light transmission efficiency in the fiber as function of distance to location in the fiber. Z=0 is at the middle of the fiber - TH1 *data_grid_fiber_trans = nullptr; - - // These two histograms are handed off to Fun4All and will be deleted there - // this suppresses the cppcheck warning - // cppcheck-suppress unsafeClassCanLeak - TH2 *data_grid_light_guide_efficiency_verify = nullptr; - // cppcheck-suppress unsafeClassCanLeak - TH1 *data_grid_fiber_trans_verify = nullptr; - }; LightCollectionModel &get_light_collection_model() { return light_collection_model; } diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc index 70a4b2130e..4849b01309 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc @@ -71,10 +71,15 @@ class G4VPhysicalVolume; class PHCompositeNode; //____________________________________________________________________________.. -PHG4SpacalSteppingAction::PHG4SpacalSteppingAction(PHG4SpacalDetector *indetector) +PHG4SpacalSteppingAction::PHG4SpacalSteppingAction(PHG4SpacalDetector *indetector, const PHParameters *parameters) : PHG4SteppingAction(indetector->GetName()) , PHParameterInterface(indetector->GetName()) , m_Detector(indetector) + , m_Params(parameters) + , m_doG4Hit(m_Params->get_int_param("saveg4hit")) + , m_tmin(m_Params->get_double_param("tmin")) + , m_tmax(m_Params->get_double_param("tmax")) + , m_dt(m_Params->get_double_param("dt")) { } @@ -89,11 +94,37 @@ PHG4SpacalSteppingAction::~PHG4SpacalSteppingAction() int PHG4SpacalSteppingAction::InitWithNode(PHCompositeNode *topNode) { - UpdateParametersWithMacro(); - m_doG4Hit = get_int_param("saveg4hit"); - m_tmin = get_double_param("tmin"); - m_tmax = get_double_param("tmax"); - m_dt = get_double_param("dt"); + if (m_doG4Hit) return 0; + PHNodeIterator iter(topNode); + detector = m_Detector->SuperDetector(); + // Looking for the DST node + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + exit(1); + } + + // add towerinfo here + PHNodeIterator dstiter(dstNode); + PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", detector)); + if (!DetNode) + { + DetNode = new PHCompositeNode(detector); + dstNode->addNode(DetNode); + } + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::EMCAL); + PHIODataNode *towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + detector, "PHObject"); + DetNode->addNode(towerNode); + + return 0; +} + +int PHG4SpacalSteppingAction::SetUpGeomNode(PHCompositeNode *topNode) +{ + if(m_geomsetup) return 0; + if (m_doG4Hit) return 0; PHNodeIterator iter(topNode); detector = m_Detector->SuperDetector(); @@ -266,7 +297,6 @@ int PHG4SpacalSteppingAction::InitWithNode(PHCompositeNode *topNode) // add geo object filled by different binning methods seggeo->AddLayerCellGeom(layerseggeo); - // save this to the run wise tree to store on DST PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); @@ -314,22 +344,13 @@ int PHG4SpacalSteppingAction::InitWithNode(PHCompositeNode *topNode) // a special implimentation of PHG4CylinderGeom is required here. _layergeom = dynamic_cast(_layergeom_raw); assert(_layergeom); - - // add towerinfo here - PHNodeIterator dstiter(dstNode); - PHCompositeNode *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", detector)); - if (!DetNode) - { - DetNode = new PHCompositeNode(detector); - dstNode->addNode(DetNode); - } - m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::EMCAL); - PHIODataNode *towerNode = new PHIODataNode(m_CaloInfoContainer, "TOWERINFO_SIM_" + detector, "PHObject"); - DetNode->addNode(towerNode); - + m_geomsetup = true; return 0; } + + + bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) { // get volume of the current step @@ -422,6 +443,7 @@ bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) // get light yield double light_yield = GetVisibleEnergyDeposition(aStep); + if (light_collection_model.use_fiber_model()) { const G4TouchableHandle &theTouchable0 = prePoint->GetTouchableHandle(); @@ -439,6 +461,8 @@ bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) light_yield *= light_collection_model.get_fiber_transmission(z); } + + // light yield correction from light guide collection efficiency: if (light_collection_model.use_fiber_model()) { @@ -759,6 +783,11 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step *aStep, bool) //____________________________________________________________________________.. void PHG4SpacalSteppingAction::SetInterfacePointers(PHCompositeNode *topNode) { + //we can only play with the geometry node after ConstructMe is called + if(!m_geomsetup) + { + SetUpGeomNode(topNode); + } m_HitContainer = findNode::getClass(topNode, m_HitNodeName); m_AbsorberHitContainer = findNode::getClass(topNode, m_AbsorberNodeName); // if we do not find the node it's messed up. @@ -772,7 +801,7 @@ void PHG4SpacalSteppingAction::SetInterfacePointers(PHCompositeNode *topNode) { if (Verbosity() > 0) { - std::cout << "PHG4ZDCSteppingAction::SetTopNode - unable to find " << m_AbsorberNodeName << std::endl; + std::cout << "PHG4SpacalSteppingAction::SetTopNode - unable to find " << m_AbsorberNodeName << std::endl; } } } diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h index 689d9cd336..ee38401a45 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h @@ -35,7 +35,7 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterIn { public: //! ctor - explicit PHG4SpacalSteppingAction(PHG4SpacalDetector *); + explicit PHG4SpacalSteppingAction(PHG4SpacalDetector *, const PHParameters *parameters); //! dtor ~PHG4SpacalSteppingAction() override; @@ -56,6 +56,8 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterIn void SetDefaultParameters() override; + int SetUpGeomNode(PHCompositeNode *topNode); + LightCollectionModel &get_light_collection_model() { return light_collection_model; } private: @@ -73,6 +75,7 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterIn int m_SaveTrackid = -1; int m_SavePostStepStatus = -1; bool m_doG4Hit = true; + bool m_geomsetup = false; double m_tmin = -20.; double m_tmax = 60.; double m_dt = 100.; diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc index a25b9ee74f..125b6dca5c 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc @@ -138,14 +138,13 @@ int PHG4SpacalSubsystem::InitRunSubsystem(PHCompositeNode* topNode) g4_hits->AddLayer(GetLayer()); } - steppingAction_ = new PHG4SpacalSteppingAction(detector_); - steppingAction_->set_int_param("saveg4hit", GetParams()->get_int_param("saveg4hit")); + steppingAction_ = new PHG4SpacalSteppingAction(detector_, GetParams()); + steppingAction_->InitWithNode(topNode); steppingAction_->get_light_collection_model().load_data_file( std::string(getenv("CALIBRATIONROOT")) + std::string("/CEMC/LightCollection/Prototype3Module.xml"), "data_grid_light_guide_efficiency", "data_grid_fiber_trans"); steppingAction_->SetHitNodeName("G4HIT", m_HitNodeName); steppingAction_->SetHitNodeName("G4HIT_ABSORBER", m_AbsorberNodeName); - steppingAction_->InitWithNode(topNode); } return 0; } @@ -157,6 +156,7 @@ int PHG4SpacalSubsystem::process_event(PHCompositeNode* topNode) // relevant nodes needed internally if (steppingAction_) { + steppingAction_->SetInterfacePointers(topNode); } return 0; @@ -185,6 +185,9 @@ void PHG4SpacalSubsystem::SetDefaultParameters() set_default_double_param("radius", 90.); set_default_double_param("zmin", -149.470000); set_default_double_param("zmax", 149.470000); + set_default_double_param("tmin", -20.); + set_default_double_param("tmax", 60.); + set_default_double_param("dt", 100.); set_default_int_param("azimuthal_n_sec", 256); set_default_int_param("construction_verbose", 0.); diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h index 243c12a8f6..dfef357d3f 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.h @@ -20,6 +20,7 @@ class PHCompositeNode; class PHG4Detector; class PHG4DisplayAction; class PHG4SpacalDetector; +class PHG4SpacalSteppingAction; class PHG4SpacalSubsystem : public PHG4DetectorSubsystem { From 08bec2472a57ca66b020212024f09195e9410420 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Fri, 19 May 2023 09:31:20 -0400 Subject: [PATCH 402/468] fix build warning --- simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc index 125b6dca5c..679e736c39 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSubsystem.cc @@ -32,6 +32,7 @@ #include #include // for operator<<, basic_ostream #include +#include class PHG4Detector; @@ -140,9 +141,11 @@ int PHG4SpacalSubsystem::InitRunSubsystem(PHCompositeNode* topNode) steppingAction_ = new PHG4SpacalSteppingAction(detector_, GetParams()); steppingAction_->InitWithNode(topNode); + const char* calibrationRoot = getenv("CALIBRATIONROOT"); + assert(calibrationRoot != nullptr && "Environment variable CALIBRATIONROOT is not set"); + std::string filePath = std::string(calibrationRoot) + "/CEMC/LightCollection/Prototype3Module.xml"; steppingAction_->get_light_collection_model().load_data_file( - std::string(getenv("CALIBRATIONROOT")) + std::string("/CEMC/LightCollection/Prototype3Module.xml"), - "data_grid_light_guide_efficiency", "data_grid_fiber_trans"); + filePath, "data_grid_light_guide_efficiency", "data_grid_fiber_trans"); steppingAction_->SetHitNodeName("G4HIT", m_HitNodeName); steppingAction_->SetHitNodeName("G4HIT_ABSORBER", m_AbsorberNodeName); } From 8069e6361d2859cf5b45aa7e165864ac212118e7 Mon Sep 17 00:00:00 2001 From: rosstom Date: Fri, 19 May 2023 14:31:32 -0400 Subject: [PATCH 403/468] Fixing array initialization issue --- .../TPCPedestalCalibration.cc | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc index 836e28bfad..ad14515976 100644 --- a/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc +++ b/calibrations/tpc/TPCPedestalCalibration/TPCPedestalCalibration.cc @@ -32,6 +32,18 @@ TPCPedestalCalibration::TPCPedestalCalibration(const std::string &name) { // reserve memory for max ADC samples m_adcSamples.resize(1024, 0); + + for(int fee_no=0;fee_no<26;fee_no++) + { + for(int channel_no=0;channel_no<256;channel_no++) + { + m_aveADCFeeChannel[fee_no][channel_no]=0.0; + m_stdADCFeeChannel[fee_no][channel_no]=0.0; + m_countsADCFeeChannel[fee_no][channel_no]=0.0; + m_aliveArrayFeeChannel[fee_no][channel_no]=1; + } + } + } int TPCPedestalCalibration::InitRun(PHCompositeNode *) @@ -49,18 +61,7 @@ int TPCPedestalCalibration::InitRun(PHCompositeNode *) m_pedestalTree->Branch("channel",&m_chan,"channel/I"); m_pedestalTree->Branch("module",&m_module,"module/I"); m_pedestalTree->Branch("slot",&m_slot,"slot/I"); - - for(int fee_no=0;fee_no<26;fee_no++) - { - for(int channel_no=0;channel_no<256;channel_no++) - { - m_aveADCFeeChannel[fee_no][channel_no]=0.0; - m_stdADCFeeChannel[fee_no][channel_no]=0.0; - m_countsADCFeeChannel[fee_no][channel_no]=0.0; - m_aliveArrayFeeChannel[fee_no][channel_no]=1; - } - } - + return Fun4AllReturnCodes::EVENT_OK; } From 30fb565b8dc02edb9933eb21078616686aeab198 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 19 May 2023 15:12:19 -0400 Subject: [PATCH 404/468] fix seg fault --- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 66d4fdd308..118b7d4337 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -257,7 +257,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) << " position: (" << track->get_x() << ", " << track->get_y() << ", " << track->get_z() << ")" << std::endl; } - ActsPropagator propagator; + ActsPropagator propagator(m_tGeometry); // create ACTS parameters from track parameters at origin auto trackParams = makeTrackParams(track); From 8315b7d565c43e98e5b1c155d8426fbf95dd0280 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 May 2023 19:14:55 -0400 Subject: [PATCH 405/468] add input manager for run nodes (no eventwise dst) --- .../fun4all/Fun4AllDstInputManager.cc | 96 ++++++------- .../fun4all/Fun4AllDstInputManager.h | 23 ++- .../fun4all/Fun4AllRunNodeInputManager.cc | 131 ++++++++++++++++++ .../fun4all/Fun4AllRunNodeInputManager.h | 37 +++++ offline/framework/fun4all/Makefile.am | 2 + 5 files changed, 234 insertions(+), 55 deletions(-) create mode 100644 offline/framework/fun4all/Fun4AllRunNodeInputManager.cc create mode 100644 offline/framework/fun4all/Fun4AllRunNodeInputManager.h diff --git a/offline/framework/fun4all/Fun4AllDstInputManager.cc b/offline/framework/fun4all/Fun4AllDstInputManager.cc index ab3ce3d1e3..34689d0b90 100644 --- a/offline/framework/fun4all/Fun4AllDstInputManager.cc +++ b/offline/framework/fun4all/Fun4AllDstInputManager.cc @@ -41,8 +41,8 @@ Fun4AllDstInputManager::Fun4AllDstInputManager(const std::string &name, const st Fun4AllDstInputManager::~Fun4AllDstInputManager() { - delete IManager; - delete runNodeSum; + delete m_IManager; + delete m_RunNodeSum; return; } @@ -65,78 +65,78 @@ int Fun4AllDstInputManager::fileopen(const std::string &filenam) } // sanity check - the IManager must be nullptr when this method is executed // if not something is very very wrong and we must not continue - if (IManager) + if (m_IManager) { - std::cout << PHWHERE << " IManager pointer is not nullptr but " << IManager + std::cout << PHWHERE << " IManager pointer is not nullptr but " << m_IManager << std::endl; std::cout << "Send mail to off-l with this printout and the macro you used" << std::endl; std::cout << "Trying to execute IManager->print() to display more info" << std::endl; std::cout << "Code will probably segfault now" << std::endl; - IManager->print(); + m_IManager->print(); std::cout << "Have someone look into this problem - Exiting now" << std::endl; exit(1); } // first read the runnode if not disabled if (m_ReadRunTTree) { - IManager = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree); - if (IManager->isFunctional()) + m_IManager = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree); + if (m_IManager->isFunctional()) { - runNode = se->getNode(RunNode, TopNodeName()); - IManager->read(runNode); + m_RunNode = se->getNode(RunNode, TopNodeName()); + m_IManager->read(m_RunNode); // get the current run number - RunHeader *runheader = findNode::getClass(runNode, "RunHeader"); + RunHeader *runheader = findNode::getClass(m_RunNode, "RunHeader"); if (runheader) { SetRunNumber(runheader->get_RunNumber()); } // delete our internal copy of the runnode when opening subsequent files - if (runNodeCopy) + if (m_RunNodeCopy) { std::cout << PHWHERE << " The impossible happened, we have a valid copy of the run node " - << runNodeCopy->getName() << " which should be a nullptr" + << m_RunNodeCopy->getName() << " which should be a nullptr" << std::endl; gSystem->Exit(1); } - runNodeCopy = new PHCompositeNode("RUNNODECOPY"); - if (!runNodeSum) + m_RunNodeCopy = new PHCompositeNode("RUNNODECOPY"); + if (!m_RunNodeSum) { - runNodeSum = new PHCompositeNode("RUNNODESUM"); + m_RunNodeSum = new PHCompositeNode("RUNNODESUM"); } PHNodeIOManager *tmpIman = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree); - tmpIman->read(runNodeCopy); + tmpIman->read(m_RunNodeCopy); delete tmpIman; PHNodeIntegrate integrate; - integrate.RunNode(runNode); - integrate.RunSumNode(runNodeSum); + integrate.RunNode(m_RunNode); + integrate.RunSumNode(m_RunNodeSum); // run recursively over internal run node copy and integrate objects - PHNodeIterator mainIter(runNodeCopy); + PHNodeIterator mainIter(m_RunNodeCopy); mainIter.forEach(integrate); // we do not need to keep the internal copy, keeping it would crate // problems in case a subsequent file does not contain all the // runwise objects from the previous file. Keeping this copy would then // integrate the missing object again with the old copy - delete runNodeCopy; - runNodeCopy = nullptr; + delete m_RunNodeCopy; + m_RunNodeCopy = nullptr; } // DLW: move the delete outside the if block to cover the case where isFunctional() fails - delete IManager; + delete m_IManager; } // now open the dst node dstNode = se->getNode(InputNode(), TopNodeName()); - IManager = new PHNodeIOManager(fullfilename, PHReadOnly); - if (IManager->isFunctional()) + m_IManager = new PHNodeIOManager(fullfilename, PHReadOnly); + if (m_IManager->isFunctional()) { IsOpen(1); events_thisfile = 0; setBranches(); // set branch selections AddToFileOpened(FileName()); // add file to the list of files which were opened // check if our input file has a sync object or not - if (IManager->NodeExist(syncdefs::SYNCNODENAME)) + if (m_IManager->NodeExist(syncdefs::SYNCNODENAME)) { m_HaveSyncObject = 1; } @@ -151,8 +151,8 @@ int Fun4AllDstInputManager::fileopen(const std::string &filenam) { std::cout << PHWHERE << ": " << Name() << " Could not open file " << FileName() << std::endl; - delete IManager; - IManager = nullptr; + delete m_IManager; + m_IManager = nullptr; return -1; } } @@ -185,7 +185,7 @@ int Fun4AllDstInputManager::run(const int nevents) readagain: PHCompositeNode *dummy; int ncount = 0; - dummy = IManager->read(dstNode); + dummy = m_IManager->read(dstNode); while (dummy) { ncount++; @@ -193,7 +193,7 @@ int Fun4AllDstInputManager::run(const int nevents) { break; } - dummy = IManager->read(dstNode); + dummy = m_IManager->read(dstNode); } if (!dummy) { @@ -222,8 +222,8 @@ int Fun4AllDstInputManager::fileclose() std::cout << Name() << ": fileclose: No Input file open" << std::endl; return -1; } - delete IManager; - IManager = nullptr; + delete m_IManager; + m_IManager = nullptr; IsOpen(0); UpdateFileList(); m_HaveSyncObject = 0; @@ -372,7 +372,7 @@ int Fun4AllDstInputManager::SyncIt(const SyncObject *mastersync) // Here the event counter and segment number and run number do agree - we found the right match // now read the full event (previously we only read the sync object) PHCompositeNode *dummy; - dummy = IManager->read(dstNode); + dummy = m_IManager->read(dstNode); if (!dummy) { std::cout << PHWHERE << " " << Name() << " Could not read full Event" << std::endl; @@ -413,7 +413,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() { readnextsync: static int readfull = 0; // for some reason all the input managers need to see the same (I think, should look at this at some point) - if (!IManager) // in case the old file was exhausted and there is no new file opened + if (!m_IManager) // in case the old file was exhausted and there is no new file opened { return Fun4AllReturnCodes::SYNC_FAIL; } @@ -421,7 +421,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() { readfull = 1; // we need to read a full event to set the root branches to phool nodes right when a new file has been opened std::map::const_iterator bIter; - for (bIter = IManager->GetBranchMap()->begin(); bIter != IManager->GetBranchMap()->end(); ++bIter) + for (bIter = m_IManager->GetBranchMap()->begin(); bIter != m_IManager->GetBranchMap()->end(); ++bIter) { if (Verbosity() > 2) { @@ -448,7 +448,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() std::cout << PHWHERE << "Could not locate Sync Branch" << std::endl; std::cout << "Please check for it in the following list of branch names and" << std::endl; std::cout << "PLEASE NOTIFY PHENIX-OFF-L and post the macro you used" << std::endl; - for (bIter = IManager->GetBranchMap()->begin(); bIter != IManager->GetBranchMap()->end(); ++bIter) + for (bIter = m_IManager->GetBranchMap()->begin(); bIter != m_IManager->GetBranchMap()->end(); ++bIter) { std::cout << bIter->first << std::endl; } @@ -461,10 +461,10 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() { // if all files are exhausted, the IManager is deleted and set to nullptr // so check if IManager is valid before getting a new event - if (IManager) + if (m_IManager) { - EventOnDst = IManager->getEventNumber(); // this returns the next number of the event - itest = IManager->readSpecific(EventOnDst, syncbranchname.c_str()); + EventOnDst = m_IManager->getEventNumber(); // this returns the next number of the event + itest = m_IManager->readSpecific(EventOnDst, syncbranchname.c_str()); } else { @@ -477,7 +477,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() } else { - if (IManager->read(dstNode)) + if (m_IManager->read(dstNode)) { itest = 1; } @@ -503,7 +503,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() if (!readfull) { EventOnDst++; - IManager->setEventNumber(EventOnDst); // update event number in phool io manager + m_IManager->setEventNumber(EventOnDst); // update event number in phool io manager } else { @@ -556,14 +556,14 @@ int Fun4AllDstInputManager::BranchSelect(const std::string &branch, const int if int Fun4AllDstInputManager::setBranches() { - if (IManager) + if (m_IManager) { if (!branchread.empty()) { std::map::const_iterator branchiter; for (branchiter = branchread.begin(); branchiter != branchread.end(); ++branchiter) { - IManager->selectObjectToRead(branchiter->first.c_str(), branchiter->second); + m_IManager->selectObjectToRead(branchiter->first.c_str(), branchiter->second); if (Verbosity() > 0) { std::cout << branchiter->first << " set to " << branchiter->second << std::endl; @@ -571,7 +571,7 @@ int Fun4AllDstInputManager::setBranches() } // protection against switching off the sync variables // only implemented in the Sync Manager - setSyncBranches(IManager); + setSyncBranches(m_IManager); } } else @@ -617,13 +617,13 @@ void Fun4AllDstInputManager::Print(const std::string &what) const std::cout << std::endl; } } - if ((what == "ALL" || what == "PHOOL") && IManager) + if ((what == "ALL" || what == "PHOOL") && m_IManager) { // loop over the map and print out the content (name and location in memory) std::cout << "--------------------------------------" << std::endl << std::endl; std::cout << "PHNodeIOManager print in Fun4AllDstInputManager " << Name() << ":" << std::endl; - IManager->print(); + m_IManager->print(); } Fun4AllInputManager::Print(what); return; @@ -631,11 +631,11 @@ void Fun4AllDstInputManager::Print(const std::string &what) const int Fun4AllDstInputManager::PushBackEvents(const int i) { - if (IManager) + if (m_IManager) { - unsigned EventOnDst = IManager->getEventNumber(); + unsigned EventOnDst = m_IManager->getEventNumber(); EventOnDst -= static_cast(i); - IManager->setEventNumber(EventOnDst); + m_IManager->setEventNumber(EventOnDst); return 0; } std::cout << PHWHERE << Name() << ": could not push back events, Imanager is NULL" diff --git a/offline/framework/fun4all/Fun4AllDstInputManager.h b/offline/framework/fun4all/Fun4AllDstInputManager.h index 5346497adf..1043a39b22 100644 --- a/offline/framework/fun4all/Fun4AllDstInputManager.h +++ b/offline/framework/fun4all/Fun4AllDstInputManager.h @@ -24,7 +24,7 @@ class Fun4AllDstInputManager : public Fun4AllInputManager int SyncIt(const SyncObject *mastersync) override; int BranchSelect(const std::string &branch, const int iflag) override; int setBranches() override; - virtual int setSyncBranches(PHNodeIOManager *IManager); + virtual int setSyncBranches(PHNodeIOManager *iman); void Print(const std::string &what = "ALL") const override; int PushBackEvents(const int i) override; int HasSyncObject() const override; @@ -32,6 +32,16 @@ class Fun4AllDstInputManager : public Fun4AllInputManager protected: int ReadNextEventSyncObject(); void ReadRunTTree(const int i) { m_ReadRunTTree = i; } + void IManager(PHNodeIOManager *iman) {m_IManager = iman;} + PHNodeIOManager *IManager() {return m_IManager;} + void runNode(PHCompositeNode *node) {m_RunNode = node;} + PHCompositeNode *runNode() {return m_RunNode;} + void runNodeCopy(PHCompositeNode *node) {m_RunNodeCopy = node;} + PHCompositeNode *runNodeCopy() {return m_RunNodeCopy;} + void runNodeSum(PHCompositeNode *node) {m_RunNodeSum = node;} + PHCompositeNode *runNodeSum() {return m_RunNodeSum;} + std::string RunNodeName() const {return RunNode;} + std::string fullfilename; private: int m_ReadRunTTree = 1; @@ -39,16 +49,15 @@ class Fun4AllDstInputManager : public Fun4AllInputManager int events_thisfile = 0; int events_skipped_during_sync = 0; int m_HaveSyncObject = 0; - std::string fullfilename; - std::string RunNode = "RUN"; std::map branchread; std::string syncbranchname; PHCompositeNode *dstNode = nullptr; - PHCompositeNode *runNode = nullptr; - PHCompositeNode *runNodeCopy = nullptr; - PHCompositeNode *runNodeSum = nullptr; - PHNodeIOManager *IManager = nullptr; + PHCompositeNode *m_RunNode = nullptr; + PHCompositeNode *m_RunNodeCopy = nullptr; + PHCompositeNode *m_RunNodeSum = nullptr; + PHNodeIOManager *m_IManager = nullptr; SyncObject *syncobject = nullptr; + std::string RunNode = "RUN"; }; #endif /* __FUN4ALLDSTINPUTMANAGER_H__ */ diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc new file mode 100644 index 0000000000..6efe864633 --- /dev/null +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc @@ -0,0 +1,131 @@ +#include "Fun4AllRunNodeInputManager.h" + +#include "Fun4AllReturnCodes.h" +#include "Fun4AllServer.h" + +#include + +#include + +#include +#include +#include +#include +#include // for PHWHERE, PHReadOnly, PHRunTree +#include + +#include + +#include +#include + +Fun4AllRunNodeInputManager::Fun4AllRunNodeInputManager(const std::string &name, + const std::string &nodename, + const std::string &topnodename) + : Fun4AllDstInputManager(name, nodename, topnodename) +{ + return; +} + +int Fun4AllRunNodeInputManager::fileopen(const std::string &filenam) +{ + Fun4AllServer *se = Fun4AllServer::instance(); + if (IsOpen()) + { + std::cout << "Closing currently open file " + << FileName() + << " and opening " << filenam << std::endl; + fileclose(); + } + FileName(filenam); + FROG frog; + fullfilename = frog.location(FileName()); + if (Verbosity() > 0) + { + std::cout << Name() << ": opening file " << fullfilename << std::endl; + } + // sanity check - the IManager must be nullptr when this method is executed + // if not something is very very wrong and we must not continue + if (IManager()) + { + std::cout << PHWHERE << " IManager pointer is not nullptr but " << IManager() + << std::endl; + std::cout << "Send mail to off-l with this printout and the macro you used" + << std::endl; + std::cout << "Trying to execute IManager->print() to display more info" + << std::endl; + std::cout << "Code will probably segfault now" << std::endl; + IManager()->print(); + std::cout << "Have someone look into this problem - Exiting now" << std::endl; + exit(1); + } + IManager(new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree)); + if (IManager()->isFunctional()) + { + runNode(se->getNode(RunNodeName(), TopNodeName())); + IManager()->read(runNode()); + // get the current run number + RunHeader *runheader = findNode::getClass(runNode(), "RunHeader"); + if (runheader) + { + SetRunNumber(runheader->get_RunNumber()); + } + // delete our internal copy of the runnode when opening subsequent files + if (runNodeCopy()) + { + std::cout << PHWHERE + << " The impossible happened, we have a valid copy of the run node " + << runNodeCopy()->getName() << " which should be a nullptr" + << std::endl; + gSystem->Exit(1); + } + runNodeCopy(new PHCompositeNode("RUNNODECOPY")); + if (!runNodeSum()) + { + runNodeSum(new PHCompositeNode("RUNNODESUM")); + } + PHNodeIOManager *tmpIman = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree); + tmpIman->read(runNodeCopy()); + delete tmpIman; + + PHNodeIntegrate integrate; + integrate.RunNode(runNode()); + integrate.RunSumNode(runNodeSum()); + // run recursively over internal run node copy and integrate objects + PHNodeIterator mainIter(runNodeCopy()); + mainIter.forEach(integrate); + // we do not need to keep the internal copy, keeping it would crate + // problems in case a subsequent file does not contain all the + // runwise objects from the previous file. Keeping this copy would then + // integrate the missing object again with the old copy + delete runNodeCopy(); + runNodeCopy(nullptr); + } + // DLW: move the delete outside the if block to cover the case where isFunctional() fails + delete IManager(); + return 0; +} + +int Fun4AllRunNodeInputManager::run(const int /*nevents*/) +{ + if (!IsOpen()) + { + if (FileListEmpty()) + { + if (Verbosity() > 0) + { + std::cout << Name() << ": No Input file open" << std::endl; + } + return -1; + } + else + { + if (OpenNextFile()) + { + std::cout << Name() << ": No Input file from filelist opened" << std::endl; + return -1; + } + } + } + return 0; +} diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.h b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h new file mode 100644 index 0000000000..c52d8e6704 --- /dev/null +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h @@ -0,0 +1,37 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef FUN4ALL_FUN4ALLRUNNODEINPUTMANAGER_H +#define FUN4ALL_FUN4ALLRUNNODEINPUTMANAGER_H + +#include "Fun4AllDstInputManager.h" + +#include "Fun4AllReturnCodes.h" + +#include // for string + +class PHNodeIOManager; +class SyncObject; + +class Fun4AllRunNodeInputManager : public Fun4AllDstInputManager +{ + public: + Fun4AllRunNodeInputManager(const std::string& name = "DUMMY", const std::string& nodename = "DST", const std::string& topnodename = "TOP"); + + ~Fun4AllRunNodeInputManager() override {} + + int fileopen(const std::string &filenam) override; + int run(const int /*nevents*/) override; + + // Effectivly turn off the synchronization checking + // + int SyncIt(const SyncObject* /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_OK; } + int GetSyncObject(SyncObject** /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_NOOBJECT; } + int NoSyncPushBackEvents(const int nevt) override { return PushBackEvents(nevt); } + /* // no sync object we don't need to enable the sync variables */ + int setSyncBranches(PHNodeIOManager* /*IManager*/) override { return 0; } + int PushBackEvents(const int /*i*/) override {return 0;} + int SkipForThisManager(const int nevents) override { return PushBackEvents(nevents); } + int HasSyncObject() const override { return 0; } +}; + +#endif // FUN4ALL_FUN4ALLRUNNODEINPUTMANAGER_H diff --git a/offline/framework/fun4all/Makefile.am b/offline/framework/fun4all/Makefile.am index 385432189f..96fafbe817 100644 --- a/offline/framework/fun4all/Makefile.am +++ b/offline/framework/fun4all/Makefile.am @@ -23,6 +23,7 @@ pkginclude_HEADERS = \ Fun4AllNoSyncDstInputManager.h \ Fun4AllOutputManager.h \ Fun4AllReturnCodes.h \ + Fun4AllRunNodeInputManager.h \ Fun4AllServer.h \ Fun4AllSyncManager.h \ Fun4AllUtils.h \ @@ -51,6 +52,7 @@ libfun4all_la_SOURCES = \ Fun4AllMemoryTracker.cc \ Fun4AllNoSyncDstInputManager.cc \ Fun4AllOutputManager.cc \ + Fun4AllRunNodeInputManager.cc \ Fun4AllServer.cc \ Fun4AllSyncManager.cc \ Fun4AllUtils.cc \ From 64ccfed6873eb4cb3af7d675074c6f242ac92173 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 May 2023 19:45:03 -0400 Subject: [PATCH 406/468] clang-format, clang-tidy --- offline/framework/fun4all/Fun4AllBase.h | 8 ++++---- .../fun4all/Fun4AllDstInputManager.cc | 6 +++--- .../fun4all/Fun4AllDstInputManager.h | 18 ++++++++--------- .../framework/fun4all/Fun4AllHistoManager.cc | 10 ++++++++-- .../framework/fun4all/Fun4AllMemoryTracker.cc | 4 ++-- .../framework/fun4all/Fun4AllOutputManager.h | 2 +- .../fun4all/Fun4AllRunNodeInputManager.cc | 10 +++++----- .../fun4all/Fun4AllRunNodeInputManager.h | 12 +++++------ offline/framework/fun4all/Fun4AllServer.cc | 4 ++++ offline/framework/fun4all/Fun4AllServer.h | 4 ++-- .../framework/fun4all/Fun4AllSyncManager.cc | 4 ++-- .../framework/fun4all/Fun4AllSyncManager.h | 8 ++++---- offline/framework/fun4all/PHTFileServer.cc | 20 ++++++++++++++----- offline/framework/fun4all/PHTFileServer.h | 10 +++++----- offline/framework/fun4all/SubsysReco.h | 6 +++--- offline/framework/fun4all/TDirectoryHelper.cc | 2 +- 16 files changed, 74 insertions(+), 54 deletions(-) diff --git a/offline/framework/fun4all/Fun4AllBase.h b/offline/framework/fun4all/Fun4AllBase.h index 9b92a70852..164275e1a9 100644 --- a/offline/framework/fun4all/Fun4AllBase.h +++ b/offline/framework/fun4all/Fun4AllBase.h @@ -8,13 +8,13 @@ /** Base class for all Fun4All Classes * - * It implements the Name, the Verbosity and the print method + * It implements the Name, the Verbosity and the print method */ class Fun4AllBase { public: - /** dtor. + /** dtor. Does nothing as this is a base class only. */ virtual ~Fun4AllBase(); @@ -25,7 +25,7 @@ class Fun4AllBase /// Sets the name of this module. virtual void Name(const std::string &name) { m_ThisName = name; } - /** Print out some info about this module. + /** Print out some info about this module. @param what can be used to specify what to print exactly. */ virtual void Print(const std::string &what = "ALL") const; @@ -66,7 +66,7 @@ class Fun4AllBase protected: /** ctor. - */ + */ Fun4AllBase(const std::string &name = "NONAME"); private: diff --git a/offline/framework/fun4all/Fun4AllDstInputManager.cc b/offline/framework/fun4all/Fun4AllDstInputManager.cc index 34689d0b90..4a6a00ad4c 100644 --- a/offline/framework/fun4all/Fun4AllDstInputManager.cc +++ b/offline/framework/fun4all/Fun4AllDstInputManager.cc @@ -413,7 +413,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() { readnextsync: static int readfull = 0; // for some reason all the input managers need to see the same (I think, should look at this at some point) - if (!m_IManager) // in case the old file was exhausted and there is no new file opened + if (!m_IManager) // in case the old file was exhausted and there is no new file opened { return Fun4AllReturnCodes::SYNC_FAIL; } @@ -430,7 +430,7 @@ int Fun4AllDstInputManager::ReadNextEventSyncObject() std::string delimeters = phooldefs::branchpathdelim; // + phooldefs::legacypathdelims; std::vector splitvec; boost::split(splitvec, bIter->first, boost::is_any_of(delimeters)); - for (auto & ia : splitvec) // -1 so we skip the node name + for (auto &ia : splitvec) // -1 so we skip the node name { if (ia == syncdefs::SYNCNODENAME) { @@ -586,7 +586,7 @@ int Fun4AllDstInputManager::setBranches() int Fun4AllDstInputManager::setSyncBranches(PHNodeIOManager *IMan) { // protection against switching off the sync variables - for (auto & i : syncdefs::SYNCVARS) + for (auto &i : syncdefs::SYNCVARS) { IMan->selectObjectToRead(i, true); } diff --git a/offline/framework/fun4all/Fun4AllDstInputManager.h b/offline/framework/fun4all/Fun4AllDstInputManager.h index 1043a39b22..825b2e63a2 100644 --- a/offline/framework/fun4all/Fun4AllDstInputManager.h +++ b/offline/framework/fun4all/Fun4AllDstInputManager.h @@ -32,15 +32,15 @@ class Fun4AllDstInputManager : public Fun4AllInputManager protected: int ReadNextEventSyncObject(); void ReadRunTTree(const int i) { m_ReadRunTTree = i; } - void IManager(PHNodeIOManager *iman) {m_IManager = iman;} - PHNodeIOManager *IManager() {return m_IManager;} - void runNode(PHCompositeNode *node) {m_RunNode = node;} - PHCompositeNode *runNode() {return m_RunNode;} - void runNodeCopy(PHCompositeNode *node) {m_RunNodeCopy = node;} - PHCompositeNode *runNodeCopy() {return m_RunNodeCopy;} - void runNodeSum(PHCompositeNode *node) {m_RunNodeSum = node;} - PHCompositeNode *runNodeSum() {return m_RunNodeSum;} - std::string RunNodeName() const {return RunNode;} + void IManager(PHNodeIOManager *iman) { m_IManager = iman; } + PHNodeIOManager *IManager() { return m_IManager; } + void runNode(PHCompositeNode *node) { m_RunNode = node; } + PHCompositeNode *runNode() { return m_RunNode; } + void runNodeCopy(PHCompositeNode *node) { m_RunNodeCopy = node; } + PHCompositeNode *runNodeCopy() { return m_RunNodeCopy; } + void runNodeSum(PHCompositeNode *node) { m_RunNodeSum = node; } + PHCompositeNode *runNodeSum() { return m_RunNodeSum; } + std::string RunNodeName() const { return RunNode; } std::string fullfilename; private: diff --git a/offline/framework/fun4all/Fun4AllHistoManager.cc b/offline/framework/fun4all/Fun4AllHistoManager.cc index b8dd36d252..696021ffcf 100644 --- a/offline/framework/fun4all/Fun4AllHistoManager.cc +++ b/offline/framework/fun4all/Fun4AllHistoManager.cc @@ -175,11 +175,15 @@ bool Fun4AllHistoManager::registerHisto(const std::string &hname, TNamed *h1d, c // reset directory for TTree if (h1d->InheritsFrom("TTree")) + { static_cast(h1d)->SetDirectory(nullptr); + } // For histograms, enforce error calculation and propagation if (h1d->InheritsFrom("TH1")) + { static_cast(h1d)->Sumw2(); + } return true; } @@ -285,11 +289,13 @@ void Fun4AllHistoManager::Reset() { TNamed *h = hiter->second; if (h->InheritsFrom("TH1")) + { (dynamic_cast(h))->Reset(); -#if HAS_THNSPARSE + } else if (h->InheritsFrom("THnSparse")) + { (dynamic_cast(h))->Reset(); -#endif + } } return; } diff --git a/offline/framework/fun4all/Fun4AllMemoryTracker.cc b/offline/framework/fun4all/Fun4AllMemoryTracker.cc index 80a7a01ae1..da81de21a1 100644 --- a/offline/framework/fun4all/Fun4AllMemoryTracker.cc +++ b/offline/framework/fun4all/Fun4AllMemoryTracker.cc @@ -111,7 +111,7 @@ void Fun4AllMemoryTracker::PrintMemoryTracker(const std::string &name) const { std::cout << iter->first << ": "; std::vector memvec = iter->second; - for (int & vit : memvec) + for (int &vit : memvec) { std::cout << vit << " "; } @@ -125,7 +125,7 @@ void Fun4AllMemoryTracker::PrintMemoryTracker(const std::string &name) const { std::cout << "SubsysReco/OutputManager: " << iter->first << std::endl; std::vector memvec = iter->second; - for (int & vit : memvec) + for (int &vit : memvec) { std::cout << vit << " "; } diff --git a/offline/framework/fun4all/Fun4AllOutputManager.h b/offline/framework/fun4all/Fun4AllOutputManager.h index 941eceb9f6..353ad422f0 100644 --- a/offline/framework/fun4all/Fun4AllOutputManager.h +++ b/offline/framework/fun4all/Fun4AllOutputManager.h @@ -100,7 +100,7 @@ class Fun4AllOutputManager : public Fun4AllBase void OutFileName(const std::string &name) { m_OutFileName = name; } protected: - /*! + /*! constructor. is protected since we do not want the class to be created in root macros */ diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc index 6efe864633..97e0dfbe3c 100644 --- a/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc @@ -20,8 +20,8 @@ #include Fun4AllRunNodeInputManager::Fun4AllRunNodeInputManager(const std::string &name, - const std::string &nodename, - const std::string &topnodename) + const std::string &nodename, + const std::string &topnodename) : Fun4AllDstInputManager(name, nodename, topnodename) { return; @@ -74,9 +74,9 @@ int Fun4AllRunNodeInputManager::fileopen(const std::string &filenam) if (runNodeCopy()) { std::cout << PHWHERE - << " The impossible happened, we have a valid copy of the run node " - << runNodeCopy()->getName() << " which should be a nullptr" - << std::endl; + << " The impossible happened, we have a valid copy of the run node " + << runNodeCopy()->getName() << " which should be a nullptr" + << std::endl; gSystem->Exit(1); } runNodeCopy(new PHCompositeNode("RUNNODECOPY")); diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.h b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h index c52d8e6704..620129f8e5 100644 --- a/offline/framework/fun4all/Fun4AllRunNodeInputManager.h +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h @@ -19,17 +19,17 @@ class Fun4AllRunNodeInputManager : public Fun4AllDstInputManager ~Fun4AllRunNodeInputManager() override {} - int fileopen(const std::string &filenam) override; + int fileopen(const std::string& filenam) override; int run(const int /*nevents*/) override; // Effectivly turn off the synchronization checking // - int SyncIt(const SyncObject* /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_OK; } - int GetSyncObject(SyncObject** /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_NOOBJECT; } - int NoSyncPushBackEvents(const int nevt) override { return PushBackEvents(nevt); } + int SyncIt(const SyncObject* /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_OK; } + int GetSyncObject(SyncObject** /*mastersync*/) override { return Fun4AllReturnCodes::SYNC_NOOBJECT; } + int NoSyncPushBackEvents(const int nevt) override { return PushBackEvents(nevt); } /* // no sync object we don't need to enable the sync variables */ - int setSyncBranches(PHNodeIOManager* /*IManager*/) override { return 0; } - int PushBackEvents(const int /*i*/) override {return 0;} + int setSyncBranches(PHNodeIOManager* /*IManager*/) override { return 0; } + int PushBackEvents(const int /*i*/) override { return 0; } int SkipForThisManager(const int nevents) override { return PushBackEvents(nevents); } int HasSyncObject() const override { return 0; } }; diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index d6a5867a6f..31be25ebd2 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -1480,9 +1480,13 @@ int Fun4AllServer::run(const int nevnts, const bool require_nevents) if (std::find(RetCodes.begin(), RetCodes.end(), static_cast(Fun4AllReturnCodes::ABORTEVENT)) == RetCodes.end()) + { icnt_good++; + } if (iret || (nevnts > 0 && icnt_good >= nevnts)) + { break; + } } else if (iret || (nevnts > 0 && icnt >= nevnts)) { diff --git a/offline/framework/fun4all/Fun4AllServer.h b/offline/framework/fun4all/Fun4AllServer.h index 09a1c5cfc4..154ff4d212 100644 --- a/offline/framework/fun4all/Fun4AllServer.h +++ b/offline/framework/fun4all/Fun4AllServer.h @@ -83,8 +83,8 @@ class Fun4AllServer : public Fun4AllBase //! run n events (0 means up to end of file) int run(const int nevnts = 0, const bool require_nevents = false); - /*! - \brief skip n events (0 means up to the end of file). + /*! + \brief skip n events (0 means up to the end of file). Skip means read, don't process. */ int skip(const int nevnts = 0); diff --git a/offline/framework/fun4all/Fun4AllSyncManager.cc b/offline/framework/fun4all/Fun4AllSyncManager.cc index 0f638b0a27..3f93a43c87 100644 --- a/offline/framework/fun4all/Fun4AllSyncManager.cc +++ b/offline/framework/fun4all/Fun4AllSyncManager.cc @@ -94,7 +94,7 @@ int Fun4AllSyncManager::run(const int nevnts) unsigned iman = 0; int ifirst = 0; int hassync = 0; - for (auto & iter : m_InManager) + for (auto &iter : m_InManager) { m_iretInManager[iman] = iter->run(1); iret += m_iretInManager[iman]; @@ -238,7 +238,7 @@ int Fun4AllSyncManager::run(const int nevnts) if (!resetnodetree) // all syncing is done and no read errors --> we have a good event in memory { m_CurrentRun = 0; // reset current run to 0 - for (auto & iter : m_InManager) + for (auto &iter : m_InManager) { int runno = iter->RunNumber(); if (Verbosity() > 2) diff --git a/offline/framework/fun4all/Fun4AllSyncManager.h b/offline/framework/fun4all/Fun4AllSyncManager.h index c7f9f4ffba..1601b8958d 100644 --- a/offline/framework/fun4all/Fun4AllSyncManager.h +++ b/offline/framework/fun4all/Fun4AllSyncManager.h @@ -26,8 +26,8 @@ class Fun4AllSyncManager : public Fun4AllBase //! run n events (0 means up to end of file int run(const int nevnts = 0); - /*! - \brief skip n events (0 means up to the end of file). + /*! + \brief skip n events (0 means up to the end of file). Skip means read, don't process. */ int skip(const int nevnts = 0); @@ -53,8 +53,8 @@ class Fun4AllSyncManager : public Fun4AllBase void PushBackInputMgrsEvents(const int i); int ResetEvent(); const std::vector GetInputManagers() const { return m_InManager; } - bool MixRunsOk() const {return m_MixRunsOkFlag;} - void MixRunsOk(bool b) {m_MixRunsOkFlag = b;} + bool MixRunsOk() const { return m_MixRunsOkFlag; } + void MixRunsOk(bool b) { m_MixRunsOkFlag = b; } private: void PrintSyncProblem() const; diff --git a/offline/framework/fun4all/PHTFileServer.cc b/offline/framework/fun4all/PHTFileServer.cc index 4fe0459274..86f41862ec 100644 --- a/offline/framework/fun4all/PHTFileServer.cc +++ b/offline/framework/fun4all/PHTFileServer.cc @@ -1,5 +1,5 @@ ////////////////////////////////////////////////////////////////// -/*! +/*! \file PHTFileServer.cc \brief TFile clean handling \author Hugo Pereira @@ -22,7 +22,10 @@ PHTFileServer::SafeTFile::TFileMap PHTFileServer::SafeTFile::_map; //_________________________________________________ PHTFileServer::~PHTFileServer() { - if (!SafeTFile::file_map().empty()) close(); + if (!SafeTFile::file_map().empty()) + { + close(); + } } //_________________________________________________ @@ -47,7 +50,10 @@ void PHTFileServer::open(const std::string& filename, const std::string& type) // create new SafeTFile; insert in map; change TDirectory SafeTFile* file(new SafeTFile(filename, type)); - if (!file->IsOpen()) std::cout << ("PHTFileServer::open - error opening TFile") << std::endl; + if (!file->IsOpen()) + { + std::cout << ("PHTFileServer::open - error opening TFile") << std::endl; + } SafeTFile::file_map().insert(make_pair(filename, file)); file->cd(); } @@ -58,7 +64,9 @@ bool PHTFileServer::flush(const std::string& filename) { SafeTFile::TFileMap::iterator iter(SafeTFile::file_map().find(filename)); if (iter != SafeTFile::file_map().end()) + { iter->second->Flush(); + } else { std::ostringstream what; @@ -75,7 +83,9 @@ bool PHTFileServer::cd(const std::string& filename) { SafeTFile::TFileMap::iterator iter(SafeTFile::file_map().find(filename)); if (iter != SafeTFile::file_map().end()) + { iter->second->cd(); + } else { std::ostringstream what; @@ -132,7 +142,7 @@ void PHTFileServer::close() { // close // MUTOO::TRACE( "PHTFileServer::close" ); - for (auto & iter : SafeTFile::file_map()) + for (auto& iter : SafeTFile::file_map()) { if (iter.second->IsOpen()) { @@ -177,7 +187,7 @@ PHTFileServer::SafeTFile::~SafeTFile() Close(); } - /* + /* remove this filename from the make to make sure that PHTFileServer does not try to write/close this TFile during the destructor */ diff --git a/offline/framework/fun4all/PHTFileServer.h b/offline/framework/fun4all/PHTFileServer.h index a1d0d0989c..4880ee6933 100644 --- a/offline/framework/fun4all/PHTFileServer.h +++ b/offline/framework/fun4all/PHTFileServer.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. ////////////////////////////////////////////////////////////////// -/*! +/*! \file PHTFileServer.h \brief TFile clean handling \author Hugo Pereira @@ -19,10 +19,10 @@ #include #include -/*! +/*! \brief TFile clean handling. It allow independant classes to access the same TFile and write ntuple to it. TFiles get written only when as many - write request are achieved as open request. + write request are achieved as open request. It get closed when the server is deleted */ class PHTFileServer @@ -38,7 +38,7 @@ class PHTFileServer //! destructor. All non close TFiles are closed, with a warning. virtual ~PHTFileServer(); - /*! \brief + /*! \brief open a SafeTFile. If filename is not found in the map, create a new TFile and append to the map; increment counter otherwise */ @@ -51,7 +51,7 @@ class PHTFileServer bool cd(const std::string& filename); /*! \brief - if TFile is found in map and counter is 0, close the TFile, + if TFile is found in map and counter is 0, close the TFile, decrement counter otherwise */ bool write(const std::string& filename); diff --git a/offline/framework/fun4all/SubsysReco.h b/offline/framework/fun4all/SubsysReco.h index 807d897f7a..3d6bc13df0 100644 --- a/offline/framework/fun4all/SubsysReco.h +++ b/offline/framework/fun4all/SubsysReco.h @@ -16,14 +16,14 @@ class PHCompositeNode; * from this base class and you have to implement this class methods. * None of these are strictly required as far as C++ is concerned, but as * far as your job is concerned, at least process_event(), to do the - * job, and InitRun(), to initialize, should be implemented. - * + * job, and InitRun(), to initialize, should be implemented. + * */ class SubsysReco : public Fun4AllBase { public: - /** dtor. + /** dtor. Does nothing as this is a base class only. */ ~SubsysReco() override {} diff --git a/offline/framework/fun4all/TDirectoryHelper.cc b/offline/framework/fun4all/TDirectoryHelper.cc index 8bb6c304d2..103c2524ef 100644 --- a/offline/framework/fun4all/TDirectoryHelper.cc +++ b/offline/framework/fun4all/TDirectoryHelper.cc @@ -126,7 +126,7 @@ bool TDirectoryHelper::mkpath(TDirectory* dir, const std::string& pathin) TDirectory* currentdir = dir; - for (auto & path : paths) + for (auto& path : paths) { currentdir->cd(); From 35a682f2b3077d3329f2c997d521ce193807de22 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 20 May 2023 22:20:15 -0400 Subject: [PATCH 407/468] fix circular dependency --- offline/packages/trackbase/ClusterErrorPara.cc | 7 +++---- offline/packages/trackbase/ClusterErrorPara.h | 3 +-- offline/packages/trackreco/PHActsGSF.cc | 2 +- offline/packages/trackreco/PHActsKDTreeSeeding.h | 1 + offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- offline/packages/trackreco/PHGenFitTrkFitter.cc | 4 ++-- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 4 ++-- simulation/g4simulation/g4eval/TrackEvaluation.cc | 2 +- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 676d472d75..497b12903f 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -1,5 +1,4 @@ #include "ClusterErrorPara.h" -#include #include #include @@ -501,12 +500,12 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu } //_________________________________________________________________________________ -ClusterErrorPara::error_t ClusterErrorPara::get_cluster_error(TrackSeed *seed, TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key) +ClusterErrorPara::error_t ClusterErrorPara::get_cluster_error(TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key, float qOverR, float slope) { float r = cluster_r; - float R = TMath::Abs(1.0/seed->get_qOverR()); + float R = TMath::Abs(1.0/qOverR); double alpha = (r*r) /(2*r*R); - double beta = TMath::Abs(atan(seed->get_slope())); + double beta = TMath::Abs(atan(slope)); return get_cluster_error(cluster, key, alpha, beta); } diff --git a/offline/packages/trackbase/ClusterErrorPara.h b/offline/packages/trackbase/ClusterErrorPara.h index 1755241355..54915b90c3 100644 --- a/offline/packages/trackbase/ClusterErrorPara.h +++ b/offline/packages/trackbase/ClusterErrorPara.h @@ -10,7 +10,6 @@ #include #include //class TF1; -class TrackSeed; class TrkrCluster; class ClusterErrorPara @@ -57,7 +56,7 @@ class ClusterErrorPara using error_t = std::pair; error_t get_clusterv5_modified_error(TrkrClusterv5* clusterv5, double cluster_r, TrkrDefs::cluskey key); - error_t get_cluster_error(TrackSeed *seed, TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key); + error_t get_cluster_error(TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key, float qOverR, float slope); error_t get_cluster_error(TrkrCluster* cluster, TrkrDefs::cluskey key, double alpha, double beta); error_t get_simple_cluster_error(TrkrCluster* cluster, double cluster_r, TrkrDefs::cluskey key); diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 3f7d4afd4b..77754a0cc5 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -338,7 +338,7 @@ SourceLinkVec PHActsGSF::getSourceLinks(TrackSeed* track, else if (m_cluster_version == 4) { double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_cluster_error(track, cluster, clusRadius, cluskey); + auto para_errors = _ClusErrPara.get_cluster_error(cluster, clusRadius, cluskey, track->get_qOverR(), track->get_slope()); cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.h b/offline/packages/trackreco/PHActsKDTreeSeeding.h index 545d97f7ce..630bcc3a99 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.h +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.h @@ -22,6 +22,7 @@ class TrkrClusterContainer; class TrackSeedContainer; class TrkrCluster; class PHG4CylinderGeomContainer; +class TrackSeed; class PHActsKDTreeSeeding : public SubsysReco { diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 9fce578285..7271714cd9 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -699,7 +699,7 @@ SourceLinkVec PHActsTrkFitter::getSourceLinks(TrackSeed* track, cluster->getActsLocalError(1,1) * Acts::UnitConstants::cm2; }else if(m_cluster_version==4){ double clusRadius = sqrt(global[0]*global[0] + global[1]*global[1]); - auto para_errors = _ClusErrPara.get_cluster_error(track,cluster,clusRadius,cluskey); + auto para_errors = _ClusErrPara.get_cluster_error(cluster,clusRadius,cluskey, track->get_qOverR(), track->get_slope()); cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; diff --git a/offline/packages/trackreco/PHGenFitTrkFitter.cc b/offline/packages/trackreco/PHGenFitTrkFitter.cc index 8a7a5ec569..c8fc1bc461 100644 --- a/offline/packages/trackreco/PHGenFitTrkFitter.cc +++ b/offline/packages/trackreco/PHGenFitTrkFitter.cc @@ -1186,7 +1186,7 @@ std::shared_ptr PHGenFitTrkFitter::ReFitTrack(PHCompositeNode* case TrkrDefs::mvtxId: case TrkrDefs::inttId: { - const auto errors_square = m_cluster_error_parametrization.get_cluster_error( intrack->get_silicon_seed(), cluster, cluster_r, cluster_key ); + const auto errors_square = m_cluster_error_parametrization.get_cluster_error(cluster, cluster_r, cluster_key, intrack->get_silicon_seed()->get_qOverR(), intrack->get_silicon_seed()->get_slope() ); cluster_rphi_error = std::sqrt( errors_square.first ); cluster_z_error = std::sqrt( errors_square.second ); break; @@ -1195,7 +1195,7 @@ std::shared_ptr PHGenFitTrkFitter::ReFitTrack(PHCompositeNode* case TrkrDefs::micromegasId: case TrkrDefs::tpcId: { - const auto errors_square = m_cluster_error_parametrization.get_cluster_error( intrack->get_tpc_seed(), cluster, cluster_r, cluster_key ); + const auto errors_square = m_cluster_error_parametrization.get_cluster_error(cluster, cluster_r, cluster_key, intrack->get_tpc_seed()->get_qOverR(), intrack->get_tpc_seed()->get_slope() ); cluster_rphi_error = std::sqrt( errors_square.first ); cluster_z_error = std::sqrt( errors_square.second ); break; diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index a02fd52965..1fb2404eb7 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1832,7 +1832,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) seed = track->get_tpc_seed(); } if(seed != nullptr){ - auto para_errors = ClusErrPara.get_cluster_error(seed,cluster,r,cluster_key); + auto para_errors = ClusErrPara.get_cluster_error(cluster,r,cluster_key, seed->get_qOverR(), seed->get_slope()); pephi = sqrt(para_errors.first* Acts::UnitConstants::cm2); pez =sqrt( para_errors.second* Acts::UnitConstants::cm2); } @@ -2157,7 +2157,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) seed = track->get_tpc_seed(); } if(seed != nullptr){ - auto para_errors = _ClusErrPara.get_cluster_error(seed,cluster,clusRadius,cluster_key); + auto para_errors = _ClusErrPara.get_cluster_error(cluster,clusRadius,cluster_key,seed->get_qOverR(), seed->get_slope()); pephi = sqrt(para_errors.first* Acts::UnitConstants::cm2); pez =sqrt( para_errors.second* Acts::UnitConstants::cm2); } diff --git a/simulation/g4simulation/g4eval/TrackEvaluation.cc b/simulation/g4simulation/g4eval/TrackEvaluation.cc index ce75abee52..77455a1784 100644 --- a/simulation/g4simulation/g4eval/TrackEvaluation.cc +++ b/simulation/g4simulation/g4eval/TrackEvaluation.cc @@ -697,7 +697,7 @@ TrackEvaluationContainerv1::ClusterStruct TrackEvaluation::create_cluster( TrkrD cluster_struct.trk_alpha = (r*r) /(2*r*TMath::Abs(1.0/tpc_seed->get_qOverR())); cluster_struct.trk_beta = atan(tpc_seed->get_slope()); }else{ - auto para_errors_mvtx = ClusErrPara.get_cluster_error(si_seed,cluster,r,key); + auto para_errors_mvtx = ClusErrPara.get_cluster_error(cluster,r,key,si_seed->get_qOverR(), si_seed->get_slope()); cluster_struct.phi_error = sqrt(para_errors_mvtx.first)/cluster_struct.r; cluster_struct.z_error = sqrt(para_errors_mvtx.second); // float R = TMath::Abs(1.0/si_seed->get_qOverR()); From f5b894fd0ef6adcae4a38d628ee13de8ec61e531 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 21 May 2023 03:23:18 -0400 Subject: [PATCH 408/468] build tower geom node --- .../PHG4FullProjTiltedSpacalDetector.cc | 19 + .../PHG4FullProjTiltedSpacalDetector.h | 1 + .../g4detectors/PHG4SpacalDetector.cc | 572 +++++++++++++++++- .../g4detectors/PHG4SpacalDetector.h | 19 +- .../g4detectors/PHG4SpacalSteppingAction.cc | 211 +------ .../g4detectors/PHG4SpacalSteppingAction.h | 6 +- 6 files changed, 604 insertions(+), 224 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.cc b/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.cc index 9f9b8ffb77..7120e879e3 100644 --- a/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.cc @@ -15,6 +15,8 @@ #include +#include + #include #include #include // for G4Exception @@ -55,6 +57,7 @@ class PHCompositeNode; PHG4FullProjTiltedSpacalDetector::PHG4FullProjTiltedSpacalDetector(PHG4Subsystem* subsys, PHCompositeNode* Node, const std::string& dnam, PHParameters* parameters, const int lyr) : PHG4SpacalDetector(subsys, Node, dnam, parameters, lyr, false) + , m_Params(parameters) { assert(_geom == nullptr); @@ -90,6 +93,22 @@ void PHG4FullProjTiltedSpacalDetector::ConstructMe(G4LogicalVolume* logicWorld) std::cout << "PHG4FullProjTiltedSpacalDetector::Construct::" << GetName() << " - Completed." << std::endl; } + + if (m_Params->get_int_param("saveg4hit")) return; + try + { + AddCellGeometryNode(); + AddTowerGeometryNode(); + + + } + catch (std::exception &e) + { + std::cout << e.what() << std::endl; + //exit(1); + } + + } std::pair diff --git a/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.h b/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.h index d7b590f49b..1aa26dee03 100644 --- a/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.h +++ b/simulation/g4simulation/g4detectors/PHG4FullProjTiltedSpacalDetector.h @@ -69,6 +69,7 @@ class PHG4FullProjTiltedSpacalDetector : public PHG4SpacalDetector } private: + PHParameters* m_Params = nullptr; // SpacalGeom_t* _geom; //! get the v3 cast of the geometry object SpacalGeom_t* diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc index 51e744d0ee..a01e5dc698 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc @@ -6,13 +6,23 @@ * \date $$Date: 2015/02/10 15:39:26 $$ */ #include "PHG4SpacalDetector.h" +#include "PHG4CylinderGeom_Spacalv3.h" +#include "PHG4CylinderCellGeom_Spacalv1.h" +#include "PHG4CylinderGeom_Spacalv1.h" // for PHG4CylinderGeom_Spaca... + +#include "PHG4CellDefs.h" +#include "PHG4CylinderCellGeom.h" +#include "PHG4CylinderCellGeomContainer.h" #include "PHG4CylinderGeomContainer.h" #include "PHG4SpacalDisplayAction.h" #include // for PHG4Detector #include // for PHG4DisplayAction #include +#include + +#include #include #include @@ -25,18 +35,24 @@ #include #include +#include // for convert_name_... +#include // for RawTowerGeom +#include // for RawTowerGeomC... +#include +#include + #include #include #include #include #include -#include // for G4String +#include // for G4String #include #include // for G4ThreeVector #include // for G4Transform3D, G4RotateZ3D #include -#include // for G4double +#include // for G4double #include #include @@ -47,7 +63,7 @@ class PHG4CylinderGeom; //_______________________________________________________________ -//note this inactive thickness is ~1.5% of a radiation length +// note this inactive thickness is ~1.5% of a radiation length PHG4SpacalDetector::PHG4SpacalDetector(PHG4Subsystem *subsys, PHCompositeNode *Node, const std::string &dnam, @@ -56,6 +72,7 @@ PHG4SpacalDetector::PHG4SpacalDetector(PHG4Subsystem *subsys, bool init_geom) : PHG4Detector(subsys, Node, dnam) , m_DisplayAction(dynamic_cast(subsys->GetDisplayAction())) + , m_Params(parameters) , layer(lyr) { if (init_geom) @@ -118,7 +135,6 @@ int PHG4SpacalDetector::IsInCylinderActive(const G4VPhysicalVolume *volume) void PHG4SpacalDetector::ConstructMe(G4LogicalVolume *logicWorld) { assert(_geom); - fiber_core_step_limits = new G4UserLimits(_geom->get_fiber_core_step_size() * cm); Verbosity(_geom->get_construction_verbose()); @@ -320,13 +336,7 @@ PHG4SpacalDetector::Construct_AzimuthalSeg() << "_geom->get_fiber_distance() = " << _geom->get_fiber_distance() << std::endl; std::cout << "\t" - << "fiber_length = " << fiber_length / cm << std::endl; - std::cout << "\t" - << "z_step = " << z_step << std::endl; - std::cout << "\t" - << "_geom->get_azimuthal_bin() = " << _geom->get_azimuthal_n_sec() - << std::endl; - std::cout << "\t" + << "fiber_length = " << fiber_length << "_geom->get_azimuthal_distance() = " << _geom->get_azimuthal_distance() << std::endl; std::cout << "\t" @@ -385,3 +395,543 @@ void PHG4SpacalDetector::Print(const std::string & /*what*/) const return; } +// This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco. +void PHG4SpacalDetector::AddTowerGeometryNode() +{ + PHNodeIterator iter(topNode()); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << "Run Node missing, doing nothing." << std::endl; + throw std::runtime_error("Failed to find Run node in PHG4SpacalDetector::AddGeometryNode"); + } + + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", superdetector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(superdetector); + runNode->addNode(RunDetNode); + } + + const RawTowerDefs::CalorimeterId caloid = RawTowerDefs::convert_name_to_caloid(superdetector); + + // get the cell geometry and build up the tower geometry object + std::string geonodename = "CYLINDERCELLGEOM_" + superdetector; + PHG4CylinderCellGeomContainer *cellgeos = findNode::getClass(topNode(), geonodename); + if (!cellgeos) + { + std::cout << PHWHERE << " " << geonodename + << " Node missing, doing nothing." << std::endl; + throw std::runtime_error( + "Failed to find " + geonodename + " node in PHG4SpacalDetector::AddGeometryNode"); + } + m_TowerGeomNodeName = "TOWERGEOM_" + superdetector; + m_RawTowerGeomContainer = findNode::getClass(topNode(), m_TowerGeomNodeName); + if (!m_RawTowerGeomContainer) + { + m_RawTowerGeomContainer = new RawTowerGeomContainer_Cylinderv1(caloid); + PHIODataNode *newNode = new PHIODataNode(m_RawTowerGeomContainer, m_TowerGeomNodeName, "PHObject"); + RunDetNode->addNode(newNode); + } + // fill the number of layers in the calorimeter + m_NumLayers = cellgeos->get_NLayers(); + + // Create the tower nodes on the tree + PHG4CylinderCellGeomContainer::ConstIterator miter; + PHG4CylinderCellGeomContainer::ConstRange begin_end = + cellgeos->get_begin_end(); + int ifirst = 1; + int first_layer = -1; + PHG4CylinderCellGeom *first_cellgeo = nullptr; + double inner_radius = 0; + double thickness = 0; + for (miter = begin_end.first; miter != begin_end.second; ++miter) + { + PHG4CylinderCellGeom *cellgeo = miter->second; + + if (Verbosity()) + { + cellgeo->identify(); + } + thickness += cellgeo->get_thickness(); + if (ifirst) + { + first_cellgeo = miter->second; + m_CellBinning = cellgeo->get_binning(); + m_NumPhiBins = cellgeo->get_phibins(); + m_PhiMin = cellgeo->get_phimin(); + m_PhiStep = cellgeo->get_phistep(); + if (m_CellBinning == PHG4CellDefs::etaphibinning || m_CellBinning == PHG4CellDefs::etaslatbinning) + { + m_NumEtaBins = cellgeo->get_etabins(); + m_EtaMin = cellgeo->get_etamin(); + m_EtaStep = cellgeo->get_etastep(); + } + else if (m_CellBinning == PHG4CellDefs::sizebinning) + { + m_NumEtaBins = cellgeo->get_zbins(); // bin eta in the same number of z bins + } + else if (m_CellBinning == PHG4CellDefs::spacalbinning) + { + // use eta definiton for each row of towers + m_NumEtaBins = cellgeo->get_etabins(); + } + else + { + std::cout << "PHG4SpacalDetector::AddGeometryNode::" << GetName() + << " - Fatal Error - unsupported cell binning method " + << m_CellBinning << std::endl; + } + inner_radius = cellgeo->get_radius(); + first_layer = cellgeo->get_layer(); + ifirst = 0; + } + else + { + if (m_CellBinning != cellgeo->get_binning()) + { + std::cout << "inconsistent binning method from " << m_CellBinning + << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_binning() << std::endl; + exit(1); + } + if (inner_radius > cellgeo->get_radius()) + { + std::cout << "radius of layer " << cellgeo->get_layer() << " is " + << cellgeo->get_radius() << " which smaller than radius " + << inner_radius << " of first layer in list " << first_layer + << std::endl; + } + if (m_NumPhiBins != cellgeo->get_phibins()) + { + std::cout << "mixing number of phibins, fisrt layer: " << m_NumPhiBins + << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_phibins() << std::endl; + exit(1); + } + if (m_PhiMin != cellgeo->get_phimin()) + { + std::cout << "mixing number of phimin, fisrt layer: " << m_PhiMin + << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_phimin() << std::endl; + exit(1); + } + if (m_PhiStep != cellgeo->get_phistep()) + { + std::cout << "mixing phisteps first layer: " << m_PhiStep << " layer " + << cellgeo->get_layer() << ": " << cellgeo->get_phistep() + << " diff: " << m_PhiStep - cellgeo->get_phistep() << std::endl; + exit(1); + } + if (m_CellBinning == PHG4CellDefs::etaphibinning || m_CellBinning == PHG4CellDefs::etaslatbinning) + { + if (m_NumEtaBins != cellgeo->get_etabins()) + { + std::cout << "mixing number of EtaBins , first layer: " + << m_NumEtaBins << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_etabins() << std::endl; + exit(1); + } + if (fabs(m_EtaMin - cellgeo->get_etamin()) > 1e-9) + { + std::cout << "mixing etamin, fisrt layer: " << m_EtaMin << " layer " + << cellgeo->get_layer() << ": " << cellgeo->get_etamin() + << " diff: " << m_EtaMin - cellgeo->get_etamin() << std::endl; + exit(1); + } + if (fabs(m_EtaStep - cellgeo->get_etastep()) > 1e-9) + { + std::cout << "mixing eta steps first layer: " << m_EtaStep + << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_etastep() << " diff: " + << m_EtaStep - cellgeo->get_etastep() << std::endl; + exit(1); + } + } + + else if (m_CellBinning == PHG4CellDefs::sizebinning) + { + if (m_NumEtaBins != cellgeo->get_zbins()) + { + std::cout << "mixing number of z bins , first layer: " << m_NumEtaBins + << " layer " << cellgeo->get_layer() << ": " + << cellgeo->get_zbins() << std::endl; + exit(1); + } + } + } + } + m_RawTowerGeomContainer->set_radius(inner_radius); + m_RawTowerGeomContainer->set_thickness(thickness); + m_RawTowerGeomContainer->set_phibins(m_NumPhiBins); + // m_RawTowerGeomContainer->set_phistep(m_PhiStep); + // m_RawTowerGeomContainer->set_phimin(m_PhiMin); + m_RawTowerGeomContainer->set_etabins(m_NumEtaBins); + + if (!first_cellgeo) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - ERROR - can not find first layer of cells " + << std::endl; + + exit(1); + } + + for (int ibin = 0; ibin < first_cellgeo->get_phibins(); ibin++) + { + const std::pair range = first_cellgeo->get_phibounds(ibin); + + m_RawTowerGeomContainer->set_phibounds(ibin, range); + } + + if (m_CellBinning == PHG4CellDefs::etaphibinning || m_CellBinning == PHG4CellDefs::etaslatbinning || m_CellBinning == PHG4CellDefs::spacalbinning) + { + const double r = inner_radius; + + for (int ibin = 0; ibin < first_cellgeo->get_etabins(); ibin++) + { + const std::pair range = first_cellgeo->get_etabounds(ibin); + + m_RawTowerGeomContainer->set_etabounds(ibin, range); + } + + // setup location of all towers + for (int iphi = 0; iphi < m_RawTowerGeomContainer->get_phibins(); iphi++) + { + for (int ieta = 0; ieta < m_RawTowerGeomContainer->get_etabins(); ieta++) + { + const RawTowerDefs::keytype key = + RawTowerDefs::encode_towerid(caloid, ieta, iphi); + + const double x(r * cos(m_RawTowerGeomContainer->get_phicenter(iphi))); + const double y(r * sin(m_RawTowerGeomContainer->get_phicenter(iphi))); + const double z(r / tan(PHG4Utils::get_theta(m_RawTowerGeomContainer->get_etacenter(ieta)))); + + RawTowerGeom *tg = m_RawTowerGeomContainer->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + exit(1); + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + exit(1); + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + exit(1); + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeomContainer->add_tower_geometry(tg); + } + } + } + } + else if (m_CellBinning == PHG4CellDefs::sizebinning) + { + const double r = inner_radius; + + for (int ibin = 0; ibin < first_cellgeo->get_zbins(); ibin++) + { + const std::pair z_range = first_cellgeo->get_zbounds(ibin); + // const double r = first_cellgeo->get_radius(); + const double eta1 = -log(tan(atan2(r, z_range.first) / 2.)); + const double eta2 = -log(tan(atan2(r, z_range.second) / 2.)); + m_RawTowerGeomContainer->set_etabounds(ibin, std::make_pair(eta1, eta2)); + } + + // setup location of all towers + for (int iphi = 0; iphi < m_RawTowerGeomContainer->get_phibins(); iphi++) + { + for (int ibin = 0; ibin < first_cellgeo->get_zbins(); ibin++) + { + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(caloid, ibin, iphi); + + const double x(r * cos(m_RawTowerGeomContainer->get_phicenter(iphi))); + const double y(r * sin(m_RawTowerGeomContainer->get_phicenter(iphi))); + const double z(first_cellgeo->get_zcenter(ibin)); + + RawTowerGeom *tg = m_RawTowerGeomContainer->get_tower_geometry(key); + if (tg) + { + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Tower geometry " << key << " already exists" << std::endl; + } + + if (fabs(tg->get_center_x() - x) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x + << std::endl; + + exit(1); + } + if (fabs(tg->get_center_y() - y) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y + << std::endl; + exit(1); + } + if (fabs(tg->get_center_z() - z) > 1e-4) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z + << std::endl; + exit(1); + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - building tower geometry " << key << "" << std::endl; + } + + tg = new RawTowerGeomv1(key); + + tg->set_center_x(x); + tg->set_center_y(y); + tg->set_center_z(z); + m_RawTowerGeomContainer->add_tower_geometry(tg); + } + } + } + } + else + { + std::cout << "PHG4SpacalDetector::AddGeometryNode - ERROR - unsupported cell geometry " + << m_CellBinning << std::endl; + exit(1); + } + + if (Verbosity() >= 1) + { + m_RawTowerGeomContainer->identify(); + } + + return; +} + +void PHG4SpacalDetector::AddCellGeometryNode() +{ + PHNodeIterator iter(topNode()); + std::string detector = superdetector; + // Looking for the DST node + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + exit(1); + } + + std::string geonodename = "CYLINDERGEOM_" + detector; + PHG4CylinderGeomContainer *geo = findNode::getClass(topNode(), geonodename); + if (!geo) + { + std::cout << "PHG4SpacalDetector::AddCellGeometryNode - Could not locate geometry node " + << geonodename << std::endl; + topNode()->print(); + exit(1); + } + if (Verbosity() > 0) + { + std::cout << "PHG4SpacalDetector::AddCellGeometryNode- incoming geometry:" + << std::endl; + geo->identify(); + } + std::string seggeonodename = "CYLINDERCELLGEOM_" + detector; + PHG4CylinderCellGeomContainer *seggeo = findNode::getClass(topNode(), seggeonodename); + if (!seggeo) + { + seggeo = new PHG4CylinderCellGeomContainer(); + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + PHIODataNode *newNode = new PHIODataNode(seggeo, seggeonodename, "PHObject"); + runNode->addNode(newNode); + } + + const PHG4CylinderGeom *layergeom_raw = geo->GetFirstLayerGeom(); + assert(layergeom_raw); + + // a special implimentation of PHG4CylinderGeom is required here. + const PHG4CylinderGeom_Spacalv3 *layergeom = + dynamic_cast(layergeom_raw); + + if (!layergeom) + { + std::cout << "PHG4SpacalDetector::AddCellGeometryNode- Fatal Error -" + << " require to work with a version of SPACAL geometry of PHG4CylinderGeom_Spacalv3 or higher. " + << "However the incoming geometry has version " + << layergeom_raw->ClassName() << std::endl; + exit(1); + } + if (Verbosity() > 1) + { + layergeom->identify(); + } + + layergeom->subtower_consistency_check(); + + // int layer = layergeom->get_layer(); + + // create geo object and fill with variables common to all binning methods + PHG4CylinderCellGeom_Spacalv1 *layerseggeo = new PHG4CylinderCellGeom_Spacalv1(); + layerseggeo->set_layer(layergeom->get_layer()); + layerseggeo->set_radius(layergeom->get_radius()); + layerseggeo->set_thickness(layergeom->get_thickness()); + layerseggeo->set_binning(PHG4CellDefs::spacalbinning); + + // construct a map to convert tower_ID into the older eta bins. + + const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeom->get_sector_tower_map(); + const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeom->get_sector_map(); + const int nphibin = layergeom->get_azimuthal_n_sec() // sector + * layergeom->get_max_phi_bin_in_sec() // blocks per sector + * layergeom->get_n_subtower_phi(); // subtower per block + const double deltaphi = 2. * M_PI / nphibin; + + using map_z_tower_z_ID_t = std::map; + map_z_tower_z_ID_t map_z_tower_z_ID; + double phi_min = NAN; + + for (const auto &tower_pair : tower_map) + { + const int &tower_ID = tower_pair.first; + const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; + + // inspect index in sector 0 + std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); + + const int &tower_ID_z = tower_z_phi_ID.first; + const int &tower_ID_phi = tower_z_phi_ID.second; + + if (tower_ID_phi == 0) + { + // assign phi min according phi bin 0 + phi_min = M_PI_2 - deltaphi * (layergeom->get_max_phi_bin_in_sec() * layergeom->get_n_subtower_phi() / 2) // shift of first tower in sector + + sector_map.begin()->second; + } + + if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) + { + // assign eta min according phi bin 0 + map_z_tower_z_ID[tower.centralZ] = tower_ID_z; + } + // ... + } // const auto &tower_pair: tower_map + + assert(!std::isnan(phi_min)); + layerseggeo->set_phimin(phi_min); + layerseggeo->set_phistep(deltaphi); + layerseggeo->set_phibins(nphibin); + + PHG4CylinderCellGeom_Spacalv1::tower_z_ID_eta_bin_map_t tower_z_ID_eta_bin_map; + int eta_bin = 0; + for (auto &z_tower_z_ID : map_z_tower_z_ID) + { + tower_z_ID_eta_bin_map[z_tower_z_ID.second] = eta_bin; + eta_bin++; + } + layerseggeo->set_tower_z_ID_eta_bin_map(tower_z_ID_eta_bin_map); + layerseggeo->set_etabins(eta_bin * layergeom->get_n_subtower_eta()); + layerseggeo->set_etamin(NAN); + layerseggeo->set_etastep(NAN); + + // build eta bin maps + for (const auto &tower_pair : tower_map) + { + const int &tower_ID = tower_pair.first; + const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; + + // inspect index in sector 0 + std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); + const int &tower_ID_z = tower_z_phi_ID.first; + const int &tower_ID_phi = tower_z_phi_ID.second; + const int &etabin = tower_z_ID_eta_bin_map[tower_ID_z]; + + if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) + { + // half z-range + const double dz = fabs(0.5 * (tower.pDy1 + tower.pDy2) / sin(tower.pRotationAngleX)); + const double tower_radial = layergeom->get_tower_radial_position(tower); + + auto z_to_eta = [&tower_radial](const double &z) + { return -log(tan(0.5 * atan2(tower_radial, z))); }; + + const double eta_central = z_to_eta(tower.centralZ); + // half eta-range + const double deta = (z_to_eta(tower.centralZ + dz) - z_to_eta(tower.centralZ - dz)) / 2; + assert(deta > 0); + + for (int sub_tower_ID_y = 0; sub_tower_ID_y < tower.NSubtowerY; + ++sub_tower_ID_y) + { + assert(tower.NSubtowerY <= layergeom->get_n_subtower_eta()); + // do not overlap to the next bin. + const int sub_tower_etabin = etabin * layergeom->get_n_subtower_eta() + sub_tower_ID_y; + + const std::pair etabounds(eta_central - deta + sub_tower_ID_y * 2 * deta / tower.NSubtowerY, + eta_central - deta + (sub_tower_ID_y + 1) * 2 * deta / tower.NSubtowerY); + + const std::pair zbounds(tower.centralZ - dz + sub_tower_ID_y * 2 * dz / tower.NSubtowerY, + tower.centralZ - dz + (sub_tower_ID_y + 1) * 2 * dz / tower.NSubtowerY); + + layerseggeo->set_etabounds(sub_tower_etabin, etabounds); + layerseggeo->set_zbounds(sub_tower_etabin, zbounds); + } + } + // ... + } // const auto &tower_pair: tower_map + + // add geo object filled by different binning methods + seggeo->AddLayerCellGeom(layerseggeo); + // save this to the run wise tree to store on DST + PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + //PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); + PHNodeIterator runIter(runNode); + PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); + if (!RunDetNode) + { + RunDetNode = new PHCompositeNode(detector); + runNode->addNode(RunDetNode); + } + /* + std::string paramnodename = "G4CELLPARAM_" + detector; + SaveToNodeTree(RunDetNode, paramnodename); + save this to the parNode for use + PHNodeIterator parIter(parNode); + PHCompositeNode *ParDetNode = dynamic_cast(parIter.findFirst("PHCompositeNode", detector)); + if (!ParDetNode) + { + ParDetNode = new PHCompositeNode(detector); + parNode->addNode(ParDetNode); + } + std::string cellgeonodename = "G4CELLGEO_" + detector; + PutOnParNode(ParDetNode, cellgeonodename); + */ + return; +} \ No newline at end of file diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h index 4857fcf8ba..ad115721bd 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h @@ -12,6 +12,7 @@ #ifndef G4DETECTORS_PHG4SPACALDETECTOR_H #define G4DETECTORS_PHG4SPACALDETECTOR_H +#include "PHG4CellDefs.h" #include "PHG4CylinderGeom_Spacalv1.h" #include @@ -32,6 +33,7 @@ class PHG4GDMLConfig; class PHG4SpacalDisplayAction; class PHParameters; class PHG4Subsystem; +class RawTowerGeomContainer; class PHG4SpacalDetector : public PHG4Detector { @@ -119,8 +121,11 @@ class PHG4SpacalDetector : public PHG4Detector private: PHG4SpacalDisplayAction* m_DisplayAction = nullptr; + PHParameters* m_Params = nullptr; protected: + void AddTowerGeometryNode(); + void AddCellGeometryNode(); std::map fiber_core_vol; //! map for G4VPhysicalVolume -> fiber ID @@ -136,6 +141,15 @@ class PHG4SpacalDetector : public PHG4Detector int absorberactive = 0; int layer = -9999; int m_CosmicSetupFlag = 0; + int m_CellBinning = PHG4CellDefs::undefined; + int m_NumLayers = -1; + int m_NumPhiBins = -1; + int m_NumEtaBins = -1; + double m_Emin = 1e-6; + double m_EtaMin = NAN; + double m_PhiMin = NAN; + double m_EtaStep = NAN; + double m_PhiStep = NAN; std::string detector_type; std::string superdetector; @@ -145,9 +159,12 @@ class PHG4SpacalDetector : public PHG4Detector //! registry for volumes that should not be exported, i.e. fibers PHG4GDMLConfig* gdml_config = nullptr; - //private: + // private: SpacalGeom_t* _geom = nullptr; + + RawTowerGeomContainer* m_RawTowerGeomContainer = nullptr; + std::string m_TowerGeomNodeName; }; #endif diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc index 4849b01309..06a0fe99db 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.cc @@ -73,7 +73,6 @@ class PHCompositeNode; //____________________________________________________________________________.. PHG4SpacalSteppingAction::PHG4SpacalSteppingAction(PHG4SpacalDetector *indetector, const PHParameters *parameters) : PHG4SteppingAction(indetector->GetName()) - , PHParameterInterface(indetector->GetName()) , m_Detector(indetector) , m_Params(parameters) , m_doG4Hit(m_Params->get_int_param("saveg4hit")) @@ -123,203 +122,14 @@ int PHG4SpacalSteppingAction::InitWithNode(PHCompositeNode *topNode) int PHG4SpacalSteppingAction::SetUpGeomNode(PHCompositeNode *topNode) { - if(m_geomsetup) return 0; + if (m_geomsetup) return 0; if (m_doG4Hit) return 0; PHNodeIterator iter(topNode); detector = m_Detector->SuperDetector(); - // Looking for the DST node - PHCompositeNode *dstNode; - dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - exit(1); - } geonodename = "CYLINDERGEOM_" + detector; - PHG4CylinderGeomContainer *geo = findNode::getClass(topNode, geonodename); - if (!geo) - { - std::cout << "PHG4SpacalSteppingAction::InitWithNode - Could not locate geometry node " - << geonodename << std::endl; - topNode->print(); - exit(1); - } - if (Verbosity() > 0) - { - std::cout << "PHG4SpacalSteppingAction::InitWithNode - incoming geometry:" - << std::endl; - geo->identify(); - } seggeonodename = "CYLINDERCELLGEOM_" + detector; - PHG4CylinderCellGeomContainer *seggeo = findNode::getClass(topNode, seggeonodename); - if (!seggeo) - { - seggeo = new PHG4CylinderCellGeomContainer(); - PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); - PHIODataNode *newNode = new PHIODataNode(seggeo, seggeonodename, "PHObject"); - runNode->addNode(newNode); - } - - const PHG4CylinderGeom *layergeom_raw = geo->GetFirstLayerGeom(); - assert(layergeom_raw); - - // a special implimentation of PHG4CylinderGeom is required here. - const PHG4CylinderGeom_Spacalv3 *layergeom = - dynamic_cast(layergeom_raw); - - if (!layergeom) - { - std::cout << "PHG4SpacalSteppingAction::InitWithNode - Fatal Error -" - << " require to work with a version of SPACAL geometry of PHG4CylinderGeom_Spacalv3 or higher. " - << "However the incoming geometry has version " - << layergeom_raw->ClassName() << std::endl; - exit(1); - } - if (Verbosity() > 1) - { - layergeom->identify(); - } - - layergeom->subtower_consistency_check(); - - // int layer = layergeom->get_layer(); - - // create geo object and fill with variables common to all binning methods - PHG4CylinderCellGeom_Spacalv1 *layerseggeo = new PHG4CylinderCellGeom_Spacalv1(); - layerseggeo->set_layer(layergeom->get_layer()); - layerseggeo->set_radius(layergeom->get_radius()); - layerseggeo->set_thickness(layergeom->get_thickness()); - layerseggeo->set_binning(PHG4CellDefs::spacalbinning); - - // construct a map to convert tower_ID into the older eta bins. - - const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeom->get_sector_tower_map(); - const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeom->get_sector_map(); - const int nphibin = layergeom->get_azimuthal_n_sec() // sector - * layergeom->get_max_phi_bin_in_sec() // blocks per sector - * layergeom->get_n_subtower_phi(); // subtower per block - const double deltaphi = 2. * M_PI / nphibin; - - using map_z_tower_z_ID_t = std::map; - map_z_tower_z_ID_t map_z_tower_z_ID; - double phi_min = NAN; - - for (const auto &tower_pair : tower_map) - { - const int &tower_ID = tower_pair.first; - const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; - - // inspect index in sector 0 - std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); - - const int &tower_ID_z = tower_z_phi_ID.first; - const int &tower_ID_phi = tower_z_phi_ID.second; - - if (tower_ID_phi == 0) - { - // assign phi min according phi bin 0 - phi_min = M_PI_2 - deltaphi * (layergeom->get_max_phi_bin_in_sec() * layergeom->get_n_subtower_phi() / 2) // shift of first tower in sector - + sector_map.begin()->second; - } - - if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) - { - // assign eta min according phi bin 0 - map_z_tower_z_ID[tower.centralZ] = tower_ID_z; - } - // ... - } // const auto &tower_pair: tower_map - - assert(!std::isnan(phi_min)); - layerseggeo->set_phimin(phi_min); - layerseggeo->set_phistep(deltaphi); - layerseggeo->set_phibins(nphibin); - - PHG4CylinderCellGeom_Spacalv1::tower_z_ID_eta_bin_map_t tower_z_ID_eta_bin_map; - int eta_bin = 0; - for (auto &z_tower_z_ID : map_z_tower_z_ID) - { - tower_z_ID_eta_bin_map[z_tower_z_ID.second] = eta_bin; - eta_bin++; - } - layerseggeo->set_tower_z_ID_eta_bin_map(tower_z_ID_eta_bin_map); - layerseggeo->set_etabins(eta_bin * layergeom->get_n_subtower_eta()); - layerseggeo->set_etamin(NAN); - layerseggeo->set_etastep(NAN); - - // build eta bin maps - for (const auto &tower_pair : tower_map) - { - const int &tower_ID = tower_pair.first; - const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second; - - // inspect index in sector 0 - std::pair tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0); - const int &tower_ID_z = tower_z_phi_ID.first; - const int &tower_ID_phi = tower_z_phi_ID.second; - const int &etabin = tower_z_ID_eta_bin_map[tower_ID_z]; - - if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2) - { - // half z-range - const double dz = fabs(0.5 * (tower.pDy1 + tower.pDy2) / sin(tower.pRotationAngleX)); - const double tower_radial = layergeom->get_tower_radial_position(tower); - - auto z_to_eta = [&tower_radial](const double &z) - { return -log(tan(0.5 * atan2(tower_radial, z))); }; - - const double eta_central = z_to_eta(tower.centralZ); - // half eta-range - const double deta = (z_to_eta(tower.centralZ + dz) - z_to_eta(tower.centralZ - dz)) / 2; - assert(deta > 0); - - for (int sub_tower_ID_y = 0; sub_tower_ID_y < tower.NSubtowerY; - ++sub_tower_ID_y) - { - assert(tower.NSubtowerY <= layergeom->get_n_subtower_eta()); - // do not overlap to the next bin. - const int sub_tower_etabin = etabin * layergeom->get_n_subtower_eta() + sub_tower_ID_y; - - const std::pair etabounds(eta_central - deta + sub_tower_ID_y * 2 * deta / tower.NSubtowerY, - eta_central - deta + (sub_tower_ID_y + 1) * 2 * deta / tower.NSubtowerY); - - const std::pair zbounds(tower.centralZ - dz + sub_tower_ID_y * 2 * dz / tower.NSubtowerY, - tower.centralZ - dz + (sub_tower_ID_y + 1) * 2 * dz / tower.NSubtowerY); - - layerseggeo->set_etabounds(sub_tower_etabin, etabounds); - layerseggeo->set_zbounds(sub_tower_etabin, zbounds); - } - } - // ... - } // const auto &tower_pair: tower_map - - // add geo object filled by different binning methods - seggeo->AddLayerCellGeom(layerseggeo); - // save this to the run wise tree to store on DST - PHCompositeNode *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); - PHCompositeNode *parNode = dynamic_cast(iter.findFirst("PHCompositeNode", "PAR")); - PHNodeIterator runIter(runNode); - PHCompositeNode *RunDetNode = dynamic_cast(runIter.findFirst("PHCompositeNode", detector)); - if (!RunDetNode) - { - RunDetNode = new PHCompositeNode(detector); - runNode->addNode(RunDetNode); - } - std::string paramnodename = "G4CELLPARAM_" + detector; - SaveToNodeTree(RunDetNode, paramnodename); - // save this to the parNode for use - PHNodeIterator parIter(parNode); - PHCompositeNode *ParDetNode = dynamic_cast(parIter.findFirst("PHCompositeNode", detector)); - if (!ParDetNode) - { - ParDetNode = new PHCompositeNode(detector); - parNode->addNode(ParDetNode); - } - std::string cellgeonodename = "G4CELLGEO_" + detector; - PutOnParNode(ParDetNode, cellgeonodename); - // get the private layergeo _layergeo = findNode::getClass(topNode, geonodename); if (!_layergeo) @@ -348,9 +158,6 @@ int PHG4SpacalSteppingAction::SetUpGeomNode(PHCompositeNode *topNode) return 0; } - - - bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) { // get volume of the current step @@ -443,7 +250,7 @@ bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) // get light yield double light_yield = GetVisibleEnergyDeposition(aStep); - + if (light_collection_model.use_fiber_model()) { const G4TouchableHandle &theTouchable0 = prePoint->GetTouchableHandle(); @@ -461,7 +268,6 @@ bool PHG4SpacalSteppingAction::NoHitSteppingAction(const G4Step *aStep) light_yield *= light_collection_model.get_fiber_transmission(z); } - // light yield correction from light guide collection efficiency: if (light_collection_model.use_fiber_model()) @@ -783,8 +589,8 @@ bool PHG4SpacalSteppingAction::UserSteppingAction(const G4Step *aStep, bool) //____________________________________________________________________________.. void PHG4SpacalSteppingAction::SetInterfacePointers(PHCompositeNode *topNode) { - //we can only play with the geometry node after ConstructMe is called - if(!m_geomsetup) + // we can only play with the geometry node after ConstructMe is called + if ((!m_geomsetup) && (!m_doG4Hit)) { SetUpGeomNode(topNode); } @@ -849,12 +655,3 @@ void PHG4SpacalSteppingAction::SetHitNodeName(const std::string &type, const std return; } -// not using is one, just to make the compiler happy -void PHG4SpacalSteppingAction::SetDefaultParameters() -{ - set_default_double_param("tmax", 60.0); - set_default_double_param("tmin", -20.0); - set_default_double_param("dt", 100.0); - set_default_int_param("saveg4hit", 1); - return; -} diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h index ee38401a45..31e2fb5147 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalSteppingAction.h @@ -13,8 +13,6 @@ #include "LightCollectionModel.h" -#include - #include class G4Step; @@ -31,7 +29,7 @@ class PHG4Shower; class PHParameters; class TowerInfoContainer; -class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterInterface +class PHG4SpacalSteppingAction : public PHG4SteppingAction { public: //! ctor @@ -54,8 +52,6 @@ class PHG4SpacalSteppingAction : public PHG4SteppingAction, public PHParameterIn void SetHitNodeName(const std::string &type, const std::string &name) override; - void SetDefaultParameters() override; - int SetUpGeomNode(PHCompositeNode *topNode); LightCollectionModel &get_light_collection_model() { return light_collection_model; } From 8f68faab6c1b3dbb3a2840d9a12e8db8f8d22c4b Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 21 May 2023 04:33:25 -0400 Subject: [PATCH 409/468] remove unused varible --- simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc | 2 -- simulation/g4simulation/g4detectors/PHG4SpacalDetector.h | 1 - 2 files changed, 3 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc index a01e5dc698..b163a095a7 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc @@ -22,8 +22,6 @@ #include #include -#include - #include #include #include // for PHNode diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h index ad115721bd..bc8e742f86 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h +++ b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.h @@ -121,7 +121,6 @@ class PHG4SpacalDetector : public PHG4Detector private: PHG4SpacalDisplayAction* m_DisplayAction = nullptr; - PHParameters* m_Params = nullptr; protected: void AddTowerGeometryNode(); From 63aa8a568d957b3728ebbc48ae7d15c9e858672c Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sun, 21 May 2023 06:01:30 -0400 Subject: [PATCH 410/468] remove unused varible --- simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc index b163a095a7..054943fb46 100644 --- a/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc +++ b/simulation/g4simulation/g4detectors/PHG4SpacalDetector.cc @@ -70,7 +70,6 @@ PHG4SpacalDetector::PHG4SpacalDetector(PHG4Subsystem *subsys, bool init_geom) : PHG4Detector(subsys, Node, dnam) , m_DisplayAction(dynamic_cast(subsys->GetDisplayAction())) - , m_Params(parameters) , layer(lyr) { if (init_geom) From 6c2c1681358f702fe4ccd2a0bc4e2c1b8fadae26 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 10:22:16 -0400 Subject: [PATCH 411/468] add spacal geometry dump (partial), replace goto, clang-tidy --- offline/packages/NodeDump/DumpBbcOut.cc | 2 +- .../packages/NodeDump/DumpBbcPmtContainer.cc | 2 +- .../NodeDump/DumpPHG4CylinderGeomContainer.cc | 25 +++++++++++++++++++ offline/packages/NodeDump/PHNodeDump.cc | 19 ++++++++------ offline/packages/NodeDump/PHNodeDump.h | 1 + 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/offline/packages/NodeDump/DumpBbcOut.cc b/offline/packages/NodeDump/DumpBbcOut.cc index b68d2909c4..5e682be29c 100644 --- a/offline/packages/NodeDump/DumpBbcOut.cc +++ b/offline/packages/NodeDump/DumpBbcOut.cc @@ -9,7 +9,7 @@ #include -typedef PHIODataNode MyNode_t; +using MyNode_t = PHIODataNode; DumpBbcOut::DumpBbcOut(const std::string &NodeName): DumpObject(NodeName) { diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.cc b/offline/packages/NodeDump/DumpBbcPmtContainer.cc index 521b3a016d..e9fefa4485 100644 --- a/offline/packages/NodeDump/DumpBbcPmtContainer.cc +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.cc @@ -9,7 +9,7 @@ #include -typedef PHIODataNode MyNode_t; +using MyNode_t = PHIODataNode; DumpBbcPmtContainer::DumpBbcPmtContainer(const std::string &NodeName): DumpObject(NodeName) { diff --git a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc index a95c594fc3..6be10ab5ad 100644 --- a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc +++ b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) *fout << "num layers: " << phg4geomcontainer->get_NLayers() << std::endl; for (hiter = geom_begin_end.first; hiter != geom_begin_end.second; hiter++) { + *fout << "layer: " << hiter->second->get_layer() << std::endl; *fout << "radius: " << hiter->second->get_radius() << std::endl; *fout << "thickness: " << hiter->second->get_thickness() << std::endl; @@ -49,6 +51,29 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) *fout << "pixel_z: " << hiter->second->get_pixel_z() << std::endl; *fout << "pixel_x: " << hiter->second->get_pixel_x() << std::endl; *fout << "pixel_thickness: " << hiter->second->get_pixel_thickness() << std::endl; + PHG4CylinderGeom_Spacalv1 *layergeomv1 = dynamic_cast(hiter->second); + if (layergeomv1) + { + const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeomv1->get_sector_map(); + *fout << "xpos: " << layergeomv1->get_xpos() << std::endl; + *fout << "ypos: " << layergeomv1->get_ypos() << std::endl; + *fout << "zpos: " << layergeomv1->get_zpos() << std::endl; + for (auto sectormapiter : sector_map) + { + *fout << "sector " << sectormapiter.first << ", rotation: " << sectormapiter.second << std::endl; + } + } + PHG4CylinderGeom_Spacalv3 *layergeomv3 = dynamic_cast(hiter->second); + if (layergeomv3) + { + *fout << "sidewall_outer_torr: " << layergeomv3->get_sidewall_outer_torr() << std::endl; + const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeomv3->get_sector_tower_map(); + for (const auto & towermapiter : tower_map) + { + *fout << "tower " << towermapiter.first << ", rot angle: " << towermapiter.second.pRotationAngleX << std::endl; + } + + } } } return 0; diff --git a/offline/packages/NodeDump/PHNodeDump.cc b/offline/packages/NodeDump/PHNodeDump.cc index db990c7048..1ff9e939d6 100644 --- a/offline/packages/NodeDump/PHNodeDump.cc +++ b/offline/packages/NodeDump/PHNodeDump.cc @@ -160,7 +160,6 @@ int PHNodeDump::CloseOutputFiles() int PHNodeDump::AddDumpObject(const std::string &NodeName, PHNode *node) { DumpObject *newdump; - const std::string &newnode = NodeName; if (!exclusive.empty()) { if (exclusive.find(NodeName) == exclusive.end()) @@ -168,13 +167,14 @@ int PHNodeDump::AddDumpObject(const std::string &NodeName, PHNode *node) std::cout << "Exclusive find: Ignoring " << NodeName << std::endl; newdump = new DumpObject(NodeName); newdump->NoOutput(); - goto initdump; + return initdump(NodeName, newdump); } } if (ignore.find(NodeName) != ignore.end()) { std::cout << "Ignoring " << NodeName << std::endl; newdump = new DumpObject(NodeName); + newdump->NoOutput(); } else { @@ -389,12 +389,15 @@ int PHNodeDump::AddDumpObject(const std::string &NodeName, PHNode *node) } } newdump->PrintEvtSeq(print_evtseq); + return initdump(NodeName, newdump); +} -initdump: - newdump->SetParentNodeDump(this); - newdump->SetOutDir(outdir); - newdump->SetPrecision(fp_precision); - newdump->Init(); - dumpthis[newnode] = newdump; +int PHNodeDump::initdump(const std::string &newnode, DumpObject *dmp) +{ + dmp->SetParentNodeDump(this); + dmp->SetOutDir(outdir); + dmp->SetPrecision(fp_precision); + dmp->Init(); + dumpthis[newnode] = dmp; return 0; } diff --git a/offline/packages/NodeDump/PHNodeDump.h b/offline/packages/NodeDump/PHNodeDump.h index 5a469c1e3f..7ce4312568 100644 --- a/offline/packages/NodeDump/PHNodeDump.h +++ b/offline/packages/NodeDump/PHNodeDump.h @@ -31,6 +31,7 @@ class PHNodeDump : public PHNodeOperation private: void perform(PHNode *) override; int AddDumpObject(const std::string &NodeName, PHNode *node); + int initdump(const std::string &newnode, DumpObject *dmp); std::map dumpthis; std::set ignore; std::set exclusive; From 5fa691640643e82e74b2b984b7e3a3d60de14cbf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 10:22:52 -0400 Subject: [PATCH 412/468] clang-format --- offline/packages/NodeDump/DumpBbcOut.cc | 38 +++++++++---------- offline/packages/NodeDump/DumpBbcOut.h | 4 +- .../packages/NodeDump/DumpBbcPmtContainer.cc | 32 ++++++++-------- .../packages/NodeDump/DumpBbcPmtContainer.h | 4 +- offline/packages/NodeDump/DumpEpdGeom.cc | 24 ++++++------ .../NodeDump/DumpPHG4CylinderGeomContainer.cc | 30 +++++++-------- .../NodeDump/DumpTowerInfoContainer.cc | 6 +-- offline/packages/NodeDump/PHNodeDump.cc | 2 +- 8 files changed, 65 insertions(+), 75 deletions(-) diff --git a/offline/packages/NodeDump/DumpBbcOut.cc b/offline/packages/NodeDump/DumpBbcOut.cc index 5e682be29c..ac8b81bb8c 100644 --- a/offline/packages/NodeDump/DumpBbcOut.cc +++ b/offline/packages/NodeDump/DumpBbcOut.cc @@ -1,6 +1,5 @@ #include "DumpBbcOut.h" - #include #include @@ -8,36 +7,35 @@ #include #include - using MyNode_t = PHIODataNode; -DumpBbcOut::DumpBbcOut(const std::string &NodeName): DumpObject(NodeName) +DumpBbcOut::DumpBbcOut(const std::string &NodeName) + : DumpObject(NodeName) { - return ; + return; } int DumpBbcOut::process_Node(PHNode *myNode) { BbcOut *bbcout = nullptr; - MyNode_t *thisNode = static_cast (myNode); + MyNode_t *thisNode = static_cast(myNode); if (thisNode) - { - bbcout = thisNode->getData(); - } + { + bbcout = thisNode->getData(); + } if (bbcout && bbcout->isValid()) - { - *fout << "BbcOut->get_VertexPoint: " << bbcout->get_VertexPoint() << std::endl; - *fout << "BbcOut->get_dVertexPoint: " << bbcout->get_dVertexPoint() << std::endl; - *fout << "BbcOut->get_TimeZero: " << bbcout->get_TimeZero() << std::endl; - *fout << "BbcOut->get_dTimeZero: " << bbcout->get_dTimeZero() << std::endl; + { + *fout << "BbcOut->get_VertexPoint: " << bbcout->get_VertexPoint() << std::endl; + *fout << "BbcOut->get_dVertexPoint: " << bbcout->get_dVertexPoint() << std::endl; + *fout << "BbcOut->get_TimeZero: " << bbcout->get_TimeZero() << std::endl; + *fout << "BbcOut->get_dTimeZero: " << bbcout->get_dTimeZero() << std::endl; - for (int j = 0; j < 2; j++) - { - *fout << "BbcOut->get_nPMT(" << j <<"): " << bbcout->get_nPMT(j) << std::endl; - *fout << "BbcOut->get_nCharge(" << j << "): " << bbcout->get_nCharge(j) << std::endl; - *fout << "BbcOut->get_Timing(" << j << "): " << bbcout->get_Timing(j) << std::endl; - } + for (int j = 0; j < 2; j++) + { + *fout << "BbcOut->get_nPMT(" << j << "): " << bbcout->get_nPMT(j) << std::endl; + *fout << "BbcOut->get_nCharge(" << j << "): " << bbcout->get_nCharge(j) << std::endl; + *fout << "BbcOut->get_Timing(" << j << "): " << bbcout->get_Timing(j) << std::endl; } + } return 0; } - diff --git a/offline/packages/NodeDump/DumpBbcOut.h b/offline/packages/NodeDump/DumpBbcOut.h index c30bf4780f..b4412f4d22 100644 --- a/offline/packages/NodeDump/DumpBbcOut.h +++ b/offline/packages/NodeDump/DumpBbcOut.h @@ -1,7 +1,6 @@ #ifndef NODEDUMP_DUMPBBCOUT_H #define NODEDUMP_DUMPBBCOUT_H - #include "DumpObject.h" #include @@ -15,8 +14,7 @@ class DumpBbcOut : public DumpObject virtual ~DumpBbcOut() {} protected: - int process_Node(PHNode *mynode); + int process_Node(PHNode *mynode); }; #endif - diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.cc b/offline/packages/NodeDump/DumpBbcPmtContainer.cc index e9fefa4485..227f867b1c 100644 --- a/offline/packages/NodeDump/DumpBbcPmtContainer.cc +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.cc @@ -1,6 +1,5 @@ #include "DumpBbcPmtContainer.h" - #include #include @@ -8,33 +7,32 @@ #include #include - using MyNode_t = PHIODataNode; -DumpBbcPmtContainer::DumpBbcPmtContainer(const std::string &NodeName): DumpObject(NodeName) +DumpBbcPmtContainer::DumpBbcPmtContainer(const std::string &NodeName) + : DumpObject(NodeName) { - return ; + return; } int DumpBbcPmtContainer::process_Node(PHNode *myNode) { BbcPmtContainer *bbcpmtcontainer = nullptr; - MyNode_t *thisNode = static_cast (myNode); + MyNode_t *thisNode = static_cast(myNode); if (thisNode) - { - bbcpmtcontainer = thisNode->getData(); - } + { + bbcpmtcontainer = thisNode->getData(); + } if (bbcpmtcontainer && bbcpmtcontainer->isValid()) + { + *fout << "BbcPmtContainer->get_npmt: " << bbcpmtcontainer->get_npmt() << std::endl; + for (int j = 0; j < bbcpmtcontainer->get_npmt(); j++) { - *fout << "BbcPmtContainer->get_npmt: " << bbcpmtcontainer->get_npmt() << std::endl; - for (int j = 0; j < bbcpmtcontainer->get_npmt(); j++) - { - *fout << "BbcPmtContainer->get_pmt(" << j <<"): " << bbcpmtcontainer->get_pmt(j) << std::endl; - *fout << "BbcPmtContainer->get_adc(" << j <<"): " << bbcpmtcontainer->get_adc(j) << std::endl; - *fout << "BbcPmtContainer->get_tdc0(" << j << "): " << bbcpmtcontainer->get_tdc0(j) << std::endl; - *fout << "BbcPmtContainer->get_tdc1(" << j << "): " << bbcpmtcontainer->get_tdc1(j) << std::endl; - } + *fout << "BbcPmtContainer->get_pmt(" << j << "): " << bbcpmtcontainer->get_pmt(j) << std::endl; + *fout << "BbcPmtContainer->get_adc(" << j << "): " << bbcpmtcontainer->get_adc(j) << std::endl; + *fout << "BbcPmtContainer->get_tdc0(" << j << "): " << bbcpmtcontainer->get_tdc0(j) << std::endl; + *fout << "BbcPmtContainer->get_tdc1(" << j << "): " << bbcpmtcontainer->get_tdc1(j) << std::endl; } + } return 0; } - diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.h b/offline/packages/NodeDump/DumpBbcPmtContainer.h index e50095e842..885c8b137a 100644 --- a/offline/packages/NodeDump/DumpBbcPmtContainer.h +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.h @@ -1,7 +1,6 @@ #ifndef NODEDUMP_DUMPBBCPMTCONTAINER_H #define NODEDUMP_DUMPBBCPMTCONTAINER_H - #include "DumpObject.h" #include @@ -15,8 +14,7 @@ class DumpBbcPmtContainer : public DumpObject virtual ~DumpBbcPmtContainer() {} protected: - int process_Node(PHNode *mynode); + int process_Node(PHNode *mynode); }; #endif - diff --git a/offline/packages/NodeDump/DumpEpdGeom.cc b/offline/packages/NodeDump/DumpEpdGeom.cc index 645d7e5d15..e7bef54183 100644 --- a/offline/packages/NodeDump/DumpEpdGeom.cc +++ b/offline/packages/NodeDump/DumpEpdGeom.cc @@ -27,21 +27,21 @@ int DumpEpdGeom::process_Node(PHNode *myNode) } if (epdgeom) { - for (int iarm = 0; iarm<2; iarm++) + for (int iarm = 0; iarm < 2; iarm++) { for (int irad = 0; irad < 16; irad++) { - for (int iphi = 0; iphi<24; iphi++) - { - if (irad == 0 && iphi > 11) - { - continue; - } - unsigned int key = TowerInfoDefs::encode_epd(iarm, irad, iphi); - *fout << "tile key: 0x" << std::hex << key << std::dec << std::endl; - *fout << "get_r: " << epdgeom->get_r(key) << std::endl; - *fout << "get_phi: " << epdgeom->get_phi(key) << std::endl; - *fout << "get_z: " << epdgeom->get_z(key) << std::endl; + for (int iphi = 0; iphi < 24; iphi++) + { + if (irad == 0 && iphi > 11) + { + continue; + } + unsigned int key = TowerInfoDefs::encode_epd(iarm, irad, iphi); + *fout << "tile key: 0x" << std::hex << key << std::dec << std::endl; + *fout << "get_r: " << epdgeom->get_r(key) << std::endl; + *fout << "get_phi: " << epdgeom->get_phi(key) << std::endl; + *fout << "get_z: " << epdgeom->get_z(key) << std::endl; } } } diff --git a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc index 6be10ab5ad..392de60117 100644 --- a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc +++ b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc @@ -34,7 +34,6 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) *fout << "num layers: " << phg4geomcontainer->get_NLayers() << std::endl; for (hiter = geom_begin_end.first; hiter != geom_begin_end.second; hiter++) { - *fout << "layer: " << hiter->second->get_layer() << std::endl; *fout << "radius: " << hiter->second->get_radius() << std::endl; *fout << "thickness: " << hiter->second->get_thickness() << std::endl; @@ -54,25 +53,24 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) PHG4CylinderGeom_Spacalv1 *layergeomv1 = dynamic_cast(hiter->second); if (layergeomv1) { - const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeomv1->get_sector_map(); - *fout << "xpos: " << layergeomv1->get_xpos() << std::endl; - *fout << "ypos: " << layergeomv1->get_ypos() << std::endl; - *fout << "zpos: " << layergeomv1->get_zpos() << std::endl; - for (auto sectormapiter : sector_map) - { - *fout << "sector " << sectormapiter.first << ", rotation: " << sectormapiter.second << std::endl; - } + const PHG4CylinderGeom_Spacalv3::sector_map_t §or_map = layergeomv1->get_sector_map(); + *fout << "xpos: " << layergeomv1->get_xpos() << std::endl; + *fout << "ypos: " << layergeomv1->get_ypos() << std::endl; + *fout << "zpos: " << layergeomv1->get_zpos() << std::endl; + for (auto sectormapiter : sector_map) + { + *fout << "sector " << sectormapiter.first << ", rotation: " << sectormapiter.second << std::endl; + } } PHG4CylinderGeom_Spacalv3 *layergeomv3 = dynamic_cast(hiter->second); if (layergeomv3) { - *fout << "sidewall_outer_torr: " << layergeomv3->get_sidewall_outer_torr() << std::endl; - const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeomv3->get_sector_tower_map(); - for (const auto & towermapiter : tower_map) - { - *fout << "tower " << towermapiter.first << ", rot angle: " << towermapiter.second.pRotationAngleX << std::endl; - } - + *fout << "sidewall_outer_torr: " << layergeomv3->get_sidewall_outer_torr() << std::endl; + const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeomv3->get_sector_tower_map(); + for (const auto &towermapiter : tower_map) + { + *fout << "tower " << towermapiter.first << ", rot angle: " << towermapiter.second.pRotationAngleX << std::endl; + } } } } diff --git a/offline/packages/NodeDump/DumpTowerInfoContainer.cc b/offline/packages/NodeDump/DumpTowerInfoContainer.cc index 22ffbb552f..14cfa2a2f0 100644 --- a/offline/packages/NodeDump/DumpTowerInfoContainer.cc +++ b/offline/packages/NodeDump/DumpTowerInfoContainer.cc @@ -30,9 +30,9 @@ int DumpTowerInfoContainer::process_Node(PHNode *myNode) { unsigned int nchannels = towerinfocontainer->size(); *fout << "size: " << towerinfocontainer->size() << std::endl; - for ( unsigned int channel = 0; channel < nchannels;channel++ ) - { - TowerInfo *rawtwr = towerinfocontainer->get_tower_at_channel(channel); + for (unsigned int channel = 0; channel < nchannels; channel++) + { + TowerInfo *rawtwr = towerinfocontainer->get_tower_at_channel(channel); *fout << "time: " << rawtwr->get_time() << std::endl; *fout << "energy: " << rawtwr->get_energy() << std::endl; } diff --git a/offline/packages/NodeDump/PHNodeDump.cc b/offline/packages/NodeDump/PHNodeDump.cc index 1ff9e939d6..6ee801a464 100644 --- a/offline/packages/NodeDump/PHNodeDump.cc +++ b/offline/packages/NodeDump/PHNodeDump.cc @@ -7,8 +7,8 @@ #include "DumpCaloTriggerInfo.h" #include "DumpCdbUrlSave.h" #include "DumpCentralityInfo.h" -#include "DumpEpdGeom.h" #include "DumpEpInfo.h" +#include "DumpEpdGeom.h" #include "DumpEventHeader.h" #include "DumpFlagSave.h" #include "DumpGlobalVertexMap.h" From 3be15eb4aa18b2b1bbec529ab875f8e843a492ce Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 10:29:41 -0400 Subject: [PATCH 413/468] fix cppcheck warnings --- offline/packages/NodeDump/DumpBbcOut.h | 4 ++-- offline/packages/NodeDump/DumpBbcPmtContainer.h | 4 ++-- offline/packages/NodeDump/DumpObject.h | 2 +- offline/packages/NodeDump/DumpPHG4ParticleSvtxMap.cc | 4 ++-- offline/packages/NodeDump/DumpSvtxPHG4ParticleMap.cc | 4 ++-- offline/packages/NodeDump/Dumper.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/offline/packages/NodeDump/DumpBbcOut.h b/offline/packages/NodeDump/DumpBbcOut.h index b4412f4d22..d748adf64a 100644 --- a/offline/packages/NodeDump/DumpBbcOut.h +++ b/offline/packages/NodeDump/DumpBbcOut.h @@ -10,11 +10,11 @@ class PHNode; class DumpBbcOut : public DumpObject { public: - DumpBbcOut(const std::string &NodeName); + explicit DumpBbcOut(const std::string &NodeName); virtual ~DumpBbcOut() {} protected: - int process_Node(PHNode *mynode); + int process_Node(PHNode *mynode) override; }; #endif diff --git a/offline/packages/NodeDump/DumpBbcPmtContainer.h b/offline/packages/NodeDump/DumpBbcPmtContainer.h index 885c8b137a..6c2f12453a 100644 --- a/offline/packages/NodeDump/DumpBbcPmtContainer.h +++ b/offline/packages/NodeDump/DumpBbcPmtContainer.h @@ -10,11 +10,11 @@ class PHNode; class DumpBbcPmtContainer : public DumpObject { public: - DumpBbcPmtContainer(const std::string &NodeName); + explicit DumpBbcPmtContainer(const std::string &NodeName); virtual ~DumpBbcPmtContainer() {} protected: - int process_Node(PHNode *mynode); + int process_Node(PHNode *mynode) override; }; #endif diff --git a/offline/packages/NodeDump/DumpObject.h b/offline/packages/NodeDump/DumpObject.h index c5d760be1d..38624ce8dd 100644 --- a/offline/packages/NodeDump/DumpObject.h +++ b/offline/packages/NodeDump/DumpObject.h @@ -10,7 +10,7 @@ class PHNodeDump; class DumpObject { public: - DumpObject(const std::string &NodeName = "DUMMY"); + explicit DumpObject(const std::string &NodeName = "DUMMY"); virtual ~DumpObject() {} virtual int Init(); // called during intialization diff --git a/offline/packages/NodeDump/DumpPHG4ParticleSvtxMap.cc b/offline/packages/NodeDump/DumpPHG4ParticleSvtxMap.cc index 9b18889146..6c5db18c32 100644 --- a/offline/packages/NodeDump/DumpPHG4ParticleSvtxMap.cc +++ b/offline/packages/NodeDump/DumpPHG4ParticleSvtxMap.cc @@ -29,11 +29,11 @@ int DumpPHG4ParticleSvtxMap::process_Node(PHNode *myNode) if (phg4particlesvtxmap) { *fout << "size " << phg4particlesvtxmap->size() << std::endl; - for (auto &iter : *phg4particlesvtxmap) + for (auto const &iter : *phg4particlesvtxmap) { *fout << "Cluster: " << std::hex << iter.first << std::dec << std::endl; - for (auto &iter2 : iter.second) + for (auto const &iter2 : iter.second) { *fout << "weight: " << iter2.first << std::endl; for (unsigned int iter3 : iter2.second) diff --git a/offline/packages/NodeDump/DumpSvtxPHG4ParticleMap.cc b/offline/packages/NodeDump/DumpSvtxPHG4ParticleMap.cc index dbe4c54561..6d0994e2f2 100644 --- a/offline/packages/NodeDump/DumpSvtxPHG4ParticleMap.cc +++ b/offline/packages/NodeDump/DumpSvtxPHG4ParticleMap.cc @@ -29,11 +29,11 @@ int DumpSvtxPHG4ParticleMap::process_Node(PHNode *myNode) if (svtxphg4particlemap) { *fout << "size " << svtxphg4particlemap->size() << std::endl; - for (auto &iter : *svtxphg4particlemap) + for (auto const &iter : *svtxphg4particlemap) { *fout << "Cluster: " << std::hex << iter.first << std::dec << std::endl; - for (auto &iter2 : iter.second) + for (auto const &iter2 : iter.second) { *fout << "weight: " << iter2.first << std::endl; for (int iter3 : iter2.second) diff --git a/offline/packages/NodeDump/Dumper.h b/offline/packages/NodeDump/Dumper.h index 90a523229e..ccccad34c2 100644 --- a/offline/packages/NodeDump/Dumper.h +++ b/offline/packages/NodeDump/Dumper.h @@ -11,7 +11,7 @@ class PHNodeDump; class Dumper : public SubsysReco { public: - Dumper(const std::string &name = "DUMPER"); + explicit Dumper(const std::string &name = "DUMPER"); ~Dumper() override; int End(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; From f1e7384def84b309ad6f84dc7bf58717d41df176 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 21 May 2023 10:38:19 -0400 Subject: [PATCH 414/468] iwyu --- offline/packages/trackbase/TrackFitUtils.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/trackbase/TrackFitUtils.cc b/offline/packages/trackbase/TrackFitUtils.cc index 14fa95d376..7bf68d8df8 100644 --- a/offline/packages/trackbase/TrackFitUtils.cc +++ b/offline/packages/trackbase/TrackFitUtils.cc @@ -1,6 +1,5 @@ #include "TrackFitUtils.h" -#include #include "ActsGeometry.h" #include "TrkrDefs.h" // for cluskey, getTrkrId, tpcId #include "TpcDefs.h" From 69cc49aa272fbc005bdda81ba15f785e60e6b7b8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 11:02:33 -0400 Subject: [PATCH 415/468] remove outdated east physics list --- simulation/g4simulation/g4main/Makefile.am | 1 - simulation/g4simulation/g4main/PHG4Reco.cc | 6 ------ 2 files changed, 7 deletions(-) diff --git a/simulation/g4simulation/g4main/Makefile.am b/simulation/g4simulation/g4main/Makefile.am index 2d0d45ecc9..98c37a5f23 100644 --- a/simulation/g4simulation/g4main/Makefile.am +++ b/simulation/g4simulation/g4main/Makefile.am @@ -37,7 +37,6 @@ libg4testbench_la_LDFLAGS = \ libg4testbench_la_LIBADD = \ libphg4hit.la \ -lboost_filesystem \ - -leASTPhysicsList \ -leicsmear \ -lffamodules \ -lfun4all \ diff --git a/simulation/g4simulation/g4main/PHG4Reco.cc b/simulation/g4simulation/g4main/PHG4Reco.cc index a0a2f6647f..ee6b4593fc 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.cc +++ b/simulation/g4simulation/g4main/PHG4Reco.cc @@ -16,8 +16,6 @@ #include "PHG4UIsession.h" #include "PHG4Utils.h" -#include - #include #include @@ -223,10 +221,6 @@ int PHG4Reco::Init(PHCompositeNode *topNode) setenv("AllowForHeavyElements", "1", 1); myphysicslist = new QGSP_INCLXX_HP(Verbosity()); } - else if (m_PhysicsList == "EAST") - { - myphysicslist = new eASTPhysicsList(Verbosity()); - } else { std::cout << "Physics List " << m_PhysicsList << " not implemented" << std::endl; From 53585fa9728f5d3377bd3e558be53730f5aad643 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 11:12:12 -0400 Subject: [PATCH 416/468] clang-tidy --- simulation/g4simulation/g4main/PHG4Reco.cc | 29 ++++++++++++---------- simulation/g4simulation/g4main/PHG4Reco.h | 6 ++--- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4Reco.cc b/simulation/g4simulation/g4main/PHG4Reco.cc index ee6b4593fc..0b8d6f9b78 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.cc +++ b/simulation/g4simulation/g4main/PHG4Reco.cc @@ -123,15 +123,11 @@ PHG4Reco::PHG4Reco(const std::string &name) : SubsysReco(name) , m_Fun4AllMessenger(new Fun4AllMessenger(Fun4AllServer::instance())) { - for (int i = 0; i < 3; i++) - { - m_WorldSize[i] = 1000.; - } return; } //_________________________________________________________________ -PHG4Reco::~PHG4Reco(void) +PHG4Reco::~PHG4Reco() { // one can delete null pointer (it results in a nop), so checking if // they are non zero is not needed @@ -159,11 +155,12 @@ int PHG4Reco::Init(PHCompositeNode *topNode) G4Seed(iseed); // fixed seed handled in PHRandomSeed() // create GEANT run manager - if (Verbosity() > 1) std::cout << "PHG4Reco::Init - create run manager" << std::endl; + if (Verbosity() > 1) { std::cout << "PHG4Reco::Init - create run manager" << std::endl; +} // redirect GEANT verbosity to nowhere // if (Verbosity() < 1) - if (0) + if (false) { G4UImanager *uimanager = G4UImanager::GetUIpointer(); m_UISession = new PHG4UIsession(); @@ -245,7 +242,8 @@ int PHG4Reco::Init(PHCompositeNode *topNode) std::cout << "Use EvtGen Decayer" << std::endl; G4HadronicParameters::Instance()->SetEnableBCParticles(false); //Disable the Geant4 built in HF Decay and use external decayers for them EvtGenExtDecayerPhysics *decayer = new EvtGenExtDecayerPhysics(); - if(CustomizeDecay) decayer->CustomizeEvtGenDecay(EvtGenDecayFile); + if(CustomizeDecay) { decayer->CustomizeEvtGenDecay(EvtGenDecayFile); +} myphysicslist->RegisterPhysics(decayer); } @@ -277,7 +275,8 @@ int PHG4Reco::Init(PHCompositeNode *topNode) int PHG4Reco::InitField(PHCompositeNode *topNode) { - if (Verbosity() > 1) std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; + if (Verbosity() > 1) { std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; +} std::unique_ptr default_field_cfg(nullptr); @@ -296,7 +295,8 @@ int PHG4Reco::InitField(PHCompositeNode *topNode) default_field_cfg.reset(new PHFieldConfigv2(0, 0, m_MagneticField * m_MagneticFieldRescale)); } - if (Verbosity() > 1) std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; + if (Verbosity() > 1) { std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; +} PHField *phfield = PHFieldUtility::GetFieldMapNode(default_field_cfg.get(), topNode, Verbosity() + 1); assert(phfield); @@ -363,7 +363,8 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // create phenix detector, add subsystems, and register to GEANT // create display settings before detector m_DisplayAction = new PHG4PhenixDisplayAction(Name()); - if (Verbosity() > 1) std::cout << "PHG4Reco::Init - create detector" << std::endl; + if (Verbosity() > 1) { std::cout << "PHG4Reco::Init - create detector" << std::endl; +} m_Detector = new PHG4PhenixDetector(this); m_Detector->Verbosity(Verbosity()); m_Detector->SetWorldSizeX(m_WorldSize[0] * cm); @@ -653,8 +654,9 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) for (SubsysReco *reco: m_SubsystemList) { - if (Verbosity() >= 2) + if (Verbosity() >= 2) { std::cout << "PHG4Reco::process_event - " << reco->Name() << "->process_event" << std::endl; +} try { @@ -680,8 +682,9 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) for (PHG4Subsystem *g4sub: m_SubsystemList) { - if (Verbosity() >= 2) + if (Verbosity() >= 2) { std::cout << " PHG4Reco::process_event - " << g4sub->Name() << "->process_after_geant" << std::endl; +} try { g4sub->process_after_geant(topNode); diff --git a/simulation/g4simulation/g4main/PHG4Reco.h b/simulation/g4simulation/g4main/PHG4Reco.h index f762e947bf..3eb6ce014b 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.h +++ b/simulation/g4simulation/g4main/PHG4Reco.h @@ -46,7 +46,7 @@ class PHG4Reco : public SubsysReco }; // Decayer Option for User to Choose: 0 - GEANT 4 Internal Decayer (with momentum conservation issues), 1, PYTHIA 6 Decayer, 2 - EvtGen Decayer //! constructor - PHG4Reco(const std::string &name = "PHG4RECO"); + explicit PHG4Reco(const std::string &name = "PHG4RECO"); //! destructor ~PHG4Reco() override; @@ -140,7 +140,7 @@ class PHG4Reco : public SubsysReco void setDisableUserActions(bool b = true) { m_disableUserActions = b; } void ApplyDisplayAction(); - void CustomizeEvtGenDecay(std::string& DecayFile) + void CustomizeEvtGenDecay(const std::string& DecayFile) { EvtGenDecayFile = DecayFile; if(!EvtGenDecayFile.empty()) CustomizeDecay = true; @@ -154,7 +154,7 @@ class PHG4Reco : public SubsysReco float m_MagneticField = 0.; float m_MagneticFieldRescale = 1.0; - double m_WorldSize[3]; + double m_WorldSize[3]{1000.,1000.,1000.}; //! magnetic field G4TBMagneticFieldSetup *m_Field = nullptr; From 7ecc3312562e9801b3f5326f54288ce7e5eb0df5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 11:12:55 -0400 Subject: [PATCH 417/468] clang-format --- simulation/g4simulation/g4main/PHG4Reco.cc | 176 +++++++++++---------- simulation/g4simulation/g4main/PHG4Reco.h | 21 ++- 2 files changed, 104 insertions(+), 93 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4Reco.cc b/simulation/g4simulation/g4main/PHG4Reco.cc index 0b8d6f9b78..c98e354f27 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.cc +++ b/simulation/g4simulation/g4main/PHG4Reco.cc @@ -48,8 +48,8 @@ #include +#include // for G4HadronicParameters #include -#include #include // for G4Element #include // for G4EventManager #include @@ -73,6 +73,7 @@ #include #include #include +#include #include #include // for G4String #include @@ -84,7 +85,6 @@ #include #include #include // for G4VisManager -#include // for G4HadronicParameters // physics lists #include @@ -155,8 +155,10 @@ int PHG4Reco::Init(PHCompositeNode *topNode) G4Seed(iseed); // fixed seed handled in PHRandomSeed() // create GEANT run manager - if (Verbosity() > 1) { std::cout << "PHG4Reco::Init - create run manager" << std::endl; -} + if (Verbosity() > 1) + { + std::cout << "PHG4Reco::Init - create run manager" << std::endl; + } // redirect GEANT verbosity to nowhere // if (Verbosity() < 1) @@ -228,7 +230,7 @@ int PHG4Reco::Init(PHCompositeNode *topNode) if (m_Decayer == kPYTHIA6Decayer) { std::cout << "Use PYTHIA Decayer" << std::endl; - G4HadronicParameters::Instance()->SetEnableBCParticles(false); //Disable the Geant4 built in HF Decay and use external decayers for them + G4HadronicParameters::Instance()->SetEnableBCParticles(false); // Disable the Geant4 built in HF Decay and use external decayers for them P6DExtDecayerPhysics *decayer = new P6DExtDecayerPhysics(); if (m_ActiveForceDecayFlag) { @@ -240,12 +242,14 @@ int PHG4Reco::Init(PHCompositeNode *topNode) if (m_Decayer == kEvtGenDecayer) { std::cout << "Use EvtGen Decayer" << std::endl; - G4HadronicParameters::Instance()->SetEnableBCParticles(false); //Disable the Geant4 built in HF Decay and use external decayers for them - EvtGenExtDecayerPhysics *decayer = new EvtGenExtDecayerPhysics(); - if(CustomizeDecay) { decayer->CustomizeEvtGenDecay(EvtGenDecayFile); -} + G4HadronicParameters::Instance()->SetEnableBCParticles(false); // Disable the Geant4 built in HF Decay and use external decayers for them + EvtGenExtDecayerPhysics *decayer = new EvtGenExtDecayerPhysics(); + if (CustomizeDecay) + { + decayer->CustomizeEvtGenDecay(EvtGenDecayFile); + } - myphysicslist->RegisterPhysics(decayer); + myphysicslist->RegisterPhysics(decayer); } if (m_Decayer == kGEANTInternalDecayer) @@ -261,7 +265,7 @@ int PHG4Reco::Init(PHCompositeNode *topNode) DefineRegions(); // initialize registered subsystems - for (SubsysReco *reco: m_SubsystemList) + for (SubsysReco *reco : m_SubsystemList) { reco->Init(topNode); } @@ -275,8 +279,10 @@ int PHG4Reco::Init(PHCompositeNode *topNode) int PHG4Reco::InitField(PHCompositeNode *topNode) { - if (Verbosity() > 1) { std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; -} + if (Verbosity() > 1) + { + std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; + } std::unique_ptr default_field_cfg(nullptr); @@ -295,8 +301,10 @@ int PHG4Reco::InitField(PHCompositeNode *topNode) default_field_cfg.reset(new PHFieldConfigv2(0, 0, m_MagneticField * m_MagneticFieldRescale)); } - if (Verbosity() > 1) { std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; -} + if (Verbosity() > 1) + { + std::cout << "PHG4Reco::InitField - create magnetic field setup" << std::endl; + } PHField *phfield = PHFieldUtility::GetFieldMapNode(default_field_cfg.get(), topNode, Verbosity() + 1); assert(phfield); @@ -330,9 +338,9 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) recoConsts *rc = recoConsts::instance(); rc->set_StringFlag("WorldMaterial", m_WorldMaterial); -// build world material - so in subsequent code we can call -// G4Material::GetMaterial(rc->get_StringFlag("WorldMaterial")) -// if the world material is not in the nist DB, we need to implement it here + // build world material - so in subsequent code we can call + // G4Material::GetMaterial(rc->get_StringFlag("WorldMaterial")) + // if the world material is not in the nist DB, we need to implement it here G4NistManager::Instance()->FindOrBuildMaterial(m_WorldMaterial); // G4NistManager::Instance()->FindOrBuildMaterial("G4_Galactic"); // G4NistManager::Instance()->FindOrBuildMaterial("G4_Be"); @@ -342,7 +350,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) rc->set_FloatFlag("WorldSizey", m_WorldSize[1]); rc->set_FloatFlag("WorldSizez", m_WorldSize[2]); - //setup the global field + // setup the global field const int field_ret = InitField(topNode); if (field_ret != Fun4AllReturnCodes::EVENT_OK) { @@ -351,7 +359,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) } // initialize registered subsystems - for (SubsysReco *reco: m_SubsystemList) + for (SubsysReco *reco : m_SubsystemList) { if (Verbosity() >= 1) { @@ -363,8 +371,10 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // create phenix detector, add subsystems, and register to GEANT // create display settings before detector m_DisplayAction = new PHG4PhenixDisplayAction(Name()); - if (Verbosity() > 1) { std::cout << "PHG4Reco::Init - create detector" << std::endl; -} + if (Verbosity() > 1) + { + std::cout << "PHG4Reco::Init - create detector" << std::endl; + } m_Detector = new PHG4PhenixDetector(this); m_Detector->Verbosity(Verbosity()); m_Detector->SetWorldSizeX(m_WorldSize[0] * cm); @@ -373,7 +383,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) m_Detector->SetWorldShape(m_WorldShape); m_Detector->SetWorldMaterial(m_WorldMaterial); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { if (g4sub->GetDetector()) { @@ -385,15 +395,15 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) if (m_disableUserActions) { std::cout << "PHG4Reco::InitRun - WARNING - event/track/stepping action disabled! " - << "This is aimed to reduce resource consumption for G4 running only. E.g. dose analysis. " - << "Meanwhile, it will disable all Geant4 based analysis. Toggle this feature on/off with PHG4Reco::setDisableUserActions()" << std::endl; + << "This is aimed to reduce resource consumption for G4 running only. E.g. dose analysis. " + << "Meanwhile, it will disable all Geant4 based analysis. Toggle this feature on/off with PHG4Reco::setDisableUserActions()" << std::endl; } setupInputEventNodeReader(topNode); // create main event action, add subsystemts and register to GEANT m_EventAction = new PHG4PhenixEventAction(); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { PHG4EventAction *evtact = g4sub->GetEventAction(); if (evtact) @@ -409,7 +419,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // create main stepping action, add subsystems and register to GEANT m_StackingAction = new PHG4PhenixStackingAction(); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { PHG4StackingAction *action = g4sub->GetStackingAction(); if (action) @@ -429,7 +439,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // create main stepping action, add subsystems and register to GEANT m_SteppingAction = new PHG4PhenixSteppingAction(); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { PHG4SteppingAction *action = g4sub->GetSteppingAction(); if (action) @@ -450,7 +460,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // create main tracking action, add subsystems and register to GEANT m_TrackingAction = new PHG4PhenixTrackingAction(); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { m_TrackingAction->AddAction(g4sub->GetTrackingAction()); @@ -480,12 +490,12 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) std::cout << PHWHERE << "Could not initialize EmSaturation, Birks constants will fail" << std::endl; } #endif - + // add cerenkov and optical photon processes // std::cout << std::endl << "Ignore the next message - we implemented this correctly" << std::endl; G4Cerenkov *theCerenkovProcess = new G4Cerenkov("Cerenkov"); // std::cout << "End of bogus warning message" << std::endl << std::endl; - G4Scintillation* theScintillationProcess = new G4Scintillation("Scintillation"); + G4Scintillation *theScintillationProcess = new G4Scintillation("Scintillation"); /* if (Verbosity() > 0) @@ -528,7 +538,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) pmanager->SetProcessOrderingToLast(theScintillationProcess, idxAtRest); pmanager->SetProcessOrderingToLast(theScintillationProcess, idxPostStep); } - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { g4sub->AddProcesses(particle); } @@ -545,7 +555,7 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) // needs large amount of memory which kills central hijing events // store generated trajectories - //if( G4TrackingManager* trackingManager = G4EventManager::GetEventManager()->GetTrackingManager() ){ + // if( G4TrackingManager* trackingManager = G4EventManager::GetEventManager()->GetTrackingManager() ){ // trackingManager->SetStoreTrajectory( true ); //} @@ -577,13 +587,13 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) } // dump geometry to root file - if( m_ExportGeometry ) + if (m_ExportGeometry) { std::cout << "PHG4Reco::InitRun - writing geometry to " << m_ExportGeomFilename << std::endl; PHGeomUtility::ExportGeomtry(topNode, m_ExportGeomFilename); } - if (PHRandomSeed::Verbosity()>=2) + if (PHRandomSeed::Verbosity() >= 2) { // at high verbosity, to save the random number to file G4RunManager::GetRunManager()->SetRandomNumberStore(true); @@ -592,14 +602,14 @@ int PHG4Reco::InitRun(PHCompositeNode *topNode) } //________________________________________________________________ -//Dump TGeo File +// Dump TGeo File void PHG4Reco::Dump_GDML(const std::string &filename) { PHG4GDMLUtility ::Dump_GDML(filename, m_Detector->GetPhysicalVolume()); } //________________________________________________________________ -//Dump TGeo File using native Geant4 tools +// Dump TGeo File using native Geant4 tools void PHG4Reco::Dump_G4_GDML(const std::string &filename) { PHG4GDMLUtility::Dump_G4_GDML(filename, m_Detector->GetPhysicalVolume()); @@ -643,7 +653,7 @@ int PHG4Reco::InitUImanager() //_________________________________________________________________ int PHG4Reco::process_event(PHCompositeNode *topNode) { - if (PHRandomSeed::Verbosity()>=2) + if (PHRandomSeed::Verbosity() >= 2) { G4Random::showEngineStatus(); } @@ -652,11 +662,12 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) PHG4InEvent *ineve = findNode::getClass(topNode, "PHG4INEVENT"); m_GeneratorAction->SetInEvent(ineve); - for (SubsysReco *reco: m_SubsystemList) + for (SubsysReco *reco : m_SubsystemList) { - if (Verbosity() >= 2) { + if (Verbosity() >= 2) + { std::cout << "PHG4Reco::process_event - " << reco->Name() << "->process_event" << std::endl; -} + } try { @@ -665,7 +676,7 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) catch (const std::exception &e) { std::cout << PHWHERE << " caught exception thrown during process_event from " - << reco->Name() << std::endl; + << reco->Name() << std::endl; std::cout << "error: " << e.what() << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -675,16 +686,17 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) if (Verbosity() >= 2) { std::cout << " PHG4Reco::process_event - " - << "run one event :" << std::endl; + << "run one event :" << std::endl; ineve->identify(); } m_RunManager->BeamOn(1); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { - if (Verbosity() >= 2) { + if (Verbosity() >= 2) + { std::cout << " PHG4Reco::process_event - " << g4sub->Name() << "->process_after_geant" << std::endl; -} + } try { g4sub->process_after_geant(topNode); @@ -692,7 +704,7 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) catch (const std::exception &e) { std::cout << PHWHERE << " caught exception thrown during process_after_geant from " - << g4sub->Name() << std::endl; + << g4sub->Name() << std::endl; std::cout << "error: " << e.what() << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -702,7 +714,7 @@ int PHG4Reco::process_event(PHCompositeNode *topNode) int PHG4Reco::ResetEvent(PHCompositeNode *topNode) { - for (SubsysReco *reco: m_SubsystemList) + for (SubsysReco *reco : m_SubsystemList) { reco->ResetEvent(topNode); } @@ -711,7 +723,7 @@ int PHG4Reco::ResetEvent(PHCompositeNode *topNode) void PHG4Reco::Print(const std::string &what) const { - for (SubsysReco *reco: m_SubsystemList) + for (SubsysReco *reco : m_SubsystemList) { if (what.empty() || what == "ALL" || (reco->Name()).find(what) != std::string::npos) { @@ -755,7 +767,7 @@ void PHG4Reco::G4Seed(const unsigned int i) { CLHEP::HepRandom::setTheSeed(i); - if (PHRandomSeed::Verbosity()>=2) + if (PHRandomSeed::Verbosity() >= 2) { G4Random::showEngineStatus(); } @@ -766,10 +778,10 @@ void PHG4Reco::G4Seed(const unsigned int i) //____________________________________________________________________________ void PHG4Reco::DefineMaterials() { - G4String symbol,name; //a=mass of a mole; - G4double density; //z=mean number of protons; - G4double fractionmass,a; - G4int ncomponents, natoms,z; + G4String symbol, name; // a=mass of a mole; + G4double density; // z=mean number of protons; + G4double fractionmass, a; + G4int ncomponents, natoms, z; // this is for FTFP_BERT_HP where the neutron code barfs // if the z difference to the last known element (U) is too large // home made compounds @@ -915,7 +927,7 @@ void PHG4Reco::DefineMaterials() // E864 Pb-Scifi calorimeter // E864 Calorimeter is 99% Pb, 1% Antimony - //Nuclear Instruments and Methods in Physics Research A 406 (1998) 227 258 + // Nuclear Instruments and Methods in Physics Research A 406 (1998) 227 258 G4double density_e864 = (0.99 * 11.34 + 0.01 * 6.697) * g / cm3; G4Material *absorber_e864 = new G4Material("E864_Absorber", density_e864, 2); absorber_e864->AddMaterial(G4NistManager::Instance()->FindOrBuildMaterial("G4_Pb"), 0.99); @@ -930,14 +942,14 @@ void PHG4Reco::DefineMaterials() W_Epoxy->AddMaterial(G4NistManager::Instance()->FindOrBuildMaterial("G4_W"), fractionmass = 0.5); W_Epoxy->AddMaterial(G4NistManager::Instance()->FindOrBuildMaterial("G4_POLYSTYRENE"), fractionmass = 0.5); - //from http://www.physi.uni-heidelberg.de/~adler/TRD/TRDunterlagen/RadiatonLength/tgc2.htm - //Epoxy (for FR4 ) - //density = 1.2*g/cm3; + // from http://www.physi.uni-heidelberg.de/~adler/TRD/TRDunterlagen/RadiatonLength/tgc2.htm + // Epoxy (for FR4 ) + // density = 1.2*g/cm3; G4Material *Epoxy = new G4Material("Epoxy", 1.2 * g / cm3, ncomponents = 2); Epoxy->AddElement(G4NistManager::Instance()->FindOrBuildElement("H"), natoms = 2); Epoxy->AddElement(G4NistManager::Instance()->FindOrBuildElement("C"), natoms = 2); - //FR4 (Glass + Epoxy) + // FR4 (Glass + Epoxy) density = 1.86 * g / cm3; G4Material *FR4 = new G4Material("FR4", density, ncomponents = 2); FR4->AddMaterial(quartz, fractionmass = 0.528); @@ -975,7 +987,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 PMMA->AddElement(G4NistManager::Instance()->FindOrBuildElement("H"), 5.7 / (3.6 + 5.7 + 1.4)); PMMA->AddElement(G4NistManager::Instance()->FindOrBuildElement("O"), 1.4 / (3.6 + 5.7 + 1.4)); - //scintillator for HCal, use a new name in order to change the Birks' constant + // scintillator for HCal, use a new name in order to change the Birks' constant G4Material *Uniplast_scintillator = new G4Material("Uniplast_scintillator", 1.06 * g / cm3, ncomponents = 1); Uniplast_scintillator->AddMaterial(G4NistManager::Instance()->FindOrBuildMaterial("G4_POLYSTYRENE"), fractionmass = 1.); @@ -1001,10 +1013,10 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 CF4->AddElement(G4NistManager::Instance()->FindOrBuildElement("C"), natoms = 1); CF4->AddElement(G4NistManager::Instance()->FindOrBuildElement("F"), natoms = 4); - G4Element* elLu = new G4Element(name="Lutetium", symbol="Lu", z=71., a=174.97*g/mole); - G4Material *LSO = new G4Material("LSO", //its name - density = 7.4*g/cm3, //its density - ncomponents = 3); //number of components + G4Element *elLu = new G4Element(name = "Lutetium", symbol = "Lu", z = 71., a = 174.97 * g / mole); + G4Material *LSO = new G4Material("LSO", // its name + density = 7.4 * g / cm3, // its density + ncomponents = 3); // number of components LSO->AddElement(G4NistManager::Instance()->FindOrBuildElement("Si"), natoms = 1); LSO->AddElement(elLu, natoms = 2); @@ -1096,8 +1108,8 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 G4MaterialPropertiesTable *MPT_CF4 = new G4MaterialPropertiesTable(); #if G4VERSION_NUMBER >= 1100 - MPT_CF4->AddProperty("RINDEX", PhotonEnergy_CF4, RefractiveIndex_CF4, nEntries_CF4,false,true); - MPT_CF4->AddProperty("ABSLENGTH", PhotonEnergy_CF4, Absorption_CF4, nEntries_CF4,false,true); + MPT_CF4->AddProperty("RINDEX", PhotonEnergy_CF4, RefractiveIndex_CF4, nEntries_CF4, false, true); + MPT_CF4->AddProperty("ABSLENGTH", PhotonEnergy_CF4, Absorption_CF4, nEntries_CF4, false, true); #else MPT_CF4->AddProperty("RINDEX", PhotonEnergy_CF4, RefractiveIndex_CF4, nEntries_CF4)->SetSpline(true); MPT_CF4->AddProperty("ABSLENGTH", PhotonEnergy_CF4, Absorption_CF4, nEntries_CF4)->SetSpline(true); @@ -1159,8 +1171,8 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 G4MaterialPropertiesTable *MPT_LiF = new G4MaterialPropertiesTable(); #if G4VERSION_NUMBER >= 1100 - MPT_LiF->AddProperty("RINDEX", PhotonEnergy_LiF, RefractiveIndex_LiF, nEntries_LiF,false,true); - MPT_LiF->AddProperty("ABSLENGTH", PhotonEnergy_LiF, Absorption_LiF, nEntries_LiF,false,true); + MPT_LiF->AddProperty("RINDEX", PhotonEnergy_LiF, RefractiveIndex_LiF, nEntries_LiF, false, true); + MPT_LiF->AddProperty("ABSLENGTH", PhotonEnergy_LiF, Absorption_LiF, nEntries_LiF, false, true); #else MPT_LiF->AddProperty("RINDEX", PhotonEnergy_LiF, RefractiveIndex_LiF, nEntries_LiF)->SetSpline(true); MPT_LiF->AddProperty("ABSLENGTH", PhotonEnergy_LiF, Absorption_LiF, nEntries_LiF)->SetSpline(true); @@ -1211,8 +1223,8 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 G4MaterialPropertiesTable *MPT_CsI = new G4MaterialPropertiesTable(); #if G4VERSION_NUMBER >= 1100 - MPT_CsI->AddProperty("RINDEX", PhotonEnergy_CsI, RefractiveIndex_CsI, nEntries_CsI,false,true); - MPT_CsI->AddProperty("ABSLENGTH", PhotonEnergy_CsI, Absorption_CsI, nEntries_CsI,false,true); + MPT_CsI->AddProperty("RINDEX", PhotonEnergy_CsI, RefractiveIndex_CsI, nEntries_CsI, false, true); + MPT_CsI->AddProperty("ABSLENGTH", PhotonEnergy_CsI, Absorption_CsI, nEntries_CsI, false, true); #else MPT_CsI->AddProperty("RINDEX", PhotonEnergy_CsI, RefractiveIndex_CsI, nEntries_CsI)->SetSpline(true); MPT_CsI->AddProperty("ABSLENGTH", PhotonEnergy_CsI, Absorption_CsI, nEntries_CsI)->SetSpline(true); @@ -1248,7 +1260,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 // mRICH_Acrylic --------------- const int mRICH_nEntries1 = 32; - //same photon energy array as aerogel 1 + // same photon energy array as aerogel 1 G4double mRICH_PhotonEnergy[mRICH_nEntries1] = {2.034 * eV, 2.068 * eV, 2.103 * eV, 2.139 * eV, // 610, 600, 590, 580, (nm) 2.177 * eV, 2.216 * eV, 2.256 * eV, 2.298 * eV, // 570, 560, 550, 540, @@ -1300,7 +1312,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 1.02572, 1.0258, 1.02585, 1.0259, 1.02595, 1.026, 1.02608}; - G4double mRICH_Agel1Absorption[mRICH_nEntries1] = //from Hubert + G4double mRICH_Agel1Absorption[mRICH_nEntries1] = // from Hubert {3.448 * m, 4.082 * m, 6.329 * m, 9.174 * m, 12.346 * m, 13.889 * m, 15.152 * m, 17.241 * m, 18.868 * m, 20.000 * m, 26.316 * m, 35.714 * m, 45.455 * m, 47.619 * m, 52.632 * m, 52.632 * m, 55.556 * m, 52.632 * m, @@ -1309,7 +1321,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 17.500 * m, 14.500 * m}; G4double mRICH_Agel1Rayleigh[mRICH_nEntries1]; - //const G4double AerogelTypeAClarity = 0.00719*micrometer*micrometer*micrometer*micrometer/cm; + // const G4double AerogelTypeAClarity = 0.00719*micrometer*micrometer*micrometer*micrometer/cm; const G4double AerogelTypeAClarity = 0.0020 * micrometer * micrometer * micrometer * micrometer / cm; G4double Cparam = AerogelTypeAClarity * cm / (micrometer * micrometer * micrometer * micrometer); G4double PhotMomWaveConv = 1239 * eV * nm; @@ -1319,7 +1331,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 for (int i = 0; i < mRICH_nEntries1; i++) { G4double ephoton = mRICH_PhotonEnergy[i]; - //In the following the 1000 is to convert form nm to micrometer + // In the following the 1000 is to convert form nm to micrometer G4double wphoton = (PhotMomWaveConv / ephoton) / (1000.0 * nm); mRICH_Agel1Rayleigh[i] = (std::pow(wphoton, 4)) / Cparam; } @@ -1328,7 +1340,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 G4MaterialPropertiesTable *mRICH_Agel1_myMPT = new G4MaterialPropertiesTable(); mRICH_Agel1_myMPT->AddProperty("RINDEX", mRICH_PhotonEnergy, mRICH_Agel1RefractiveIndex, mRICH_nEntries1); mRICH_Agel1_myMPT->AddProperty("ABSLENGTH", mRICH_PhotonEnergy, mRICH_Agel1Absorption, mRICH_nEntries1); - mRICH_Agel1_myMPT->AddProperty("RAYLEIGH", mRICH_PhotonEnergy, mRICH_Agel1Rayleigh, mRICH_nEntries1); //Need table of rayleigh Scattering!!! + mRICH_Agel1_myMPT->AddProperty("RAYLEIGH", mRICH_PhotonEnergy, mRICH_Agel1Rayleigh, mRICH_nEntries1); // Need table of rayleigh Scattering!!! mRICH_Agel1_myMPT->AddConstProperty("SCINTILLATIONYIELD", 0. / MeV); mRICH_Agel1_myMPT->AddConstProperty("RESOLUTIONSCALE", 1.0); @@ -1364,7 +1376,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 1.03196, 1.03212, 1.03228, 1.03244, 1.03261, 1.03279, 1.03297, 1.03315, 1.03334, 1.03354}; - G4double mRICH_Agel2Absorption[mRICH_nEntries2] = //from Marco + G4double mRICH_Agel2Absorption[mRICH_nEntries2] = // from Marco {17.5000 * cm, 17.7466 * cm, 17.9720 * cm, 18.1789 * cm, 18.3694 * cm, 18.5455 * cm, 18.7086 * cm, 18.8602 * cm, 19.0015 * cm, 19.1334 * cm, 19.2569 * cm, 19.3728 * cm, 19.4817 * cm, 19.5843 * cm, 19.6810 * cm, @@ -1376,7 +1388,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 1.7296 * cm, 1.5696 * cm, 1.4266 * cm, 1.2986 * cm, 1.1837 * cm, 1.0806 * cm, 0.9877 * cm, 0.9041 * cm, 0.8286 * cm, 0.7603 * cm}; - G4double mRICH_Agel2Rayleigh[mRICH_nEntries2] = //from Marco + G4double mRICH_Agel2Rayleigh[mRICH_nEntries2] = // from Marco {35.1384 * cm, 29.24805 * cm, 24.5418 * cm, 20.7453 * cm, 17.6553 * cm, 15.1197 * cm, 13.02345 * cm, 11.2782 * cm, 9.81585 * cm, 8.58285 * cm, 7.53765 * cm, 6.6468 * cm, 5.88375 * cm, 5.22705 * cm, 4.6596 * cm, @@ -1401,7 +1413,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 mRICH_Aerogel2->SetMaterialPropertiesTable(mRICH_Agel2MPT); // mRICH_Borosilicate ---------- - //using the same photon energy array as mRICH_Acrylic + // using the same photon energy array as mRICH_Acrylic G4double mRICH_glassRefractiveIndex[mRICH_nEntries1] = {1.47, 1.47, 1.47, 1.47, 1.47, @@ -1423,7 +1435,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 00.001 * cm, 00.001 * cm, 00.001 * cm, 00.001 * cm}; G4MaterialPropertiesTable *mRICH_glass_myMPT = new G4MaterialPropertiesTable(); - //same photon energy array as aerogel 1 + // same photon energy array as aerogel 1 mRICH_glass_myMPT->AddProperty("RINDEX", mRICH_PhotonEnergy, mRICH_glassRefractiveIndex, mRICH_nEntries1); mRICH_glass_myMPT->AddProperty("ABSLENGTH", mRICH_PhotonEnergy, mRICH_glassAbsorption, mRICH_nEntries1); @@ -1432,7 +1444,7 @@ PMMA -3 12.01 1.008 15.99 6. 1. 8. 1.19 3.6 5.7 1.4 mRICH_Borosilicate->SetMaterialPropertiesTable(mRICH_glass_myMPT); // mRICH_Air ------------------ - //using same photon energy array as mRICH_Acrylic + // using same photon energy array as mRICH_Acrylic G4double mRICH_AirRefractiveIndex[mRICH_nEntries1] = {1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, @@ -1470,7 +1482,7 @@ void PHG4Reco::DefineRegions() PHG4Subsystem * PHG4Reco::getSubsystem(const std::string &name) { - for (PHG4Subsystem *subsys: m_SubsystemList) + for (PHG4Subsystem *subsys : m_SubsystemList) { if (subsys->Name() == name) { @@ -1501,7 +1513,7 @@ void PHG4Reco::ApplyDisplayAction() } G4VPhysicalVolume *physworld = m_Detector->GetPhysicalVolume(); m_DisplayAction->ApplyDisplayAction(physworld); - for (PHG4Subsystem *g4sub: m_SubsystemList) + for (PHG4Subsystem *g4sub : m_SubsystemList) { PHG4DisplayAction *action = g4sub->GetDisplayAction(); if (action) diff --git a/simulation/g4simulation/g4main/PHG4Reco.h b/simulation/g4simulation/g4main/PHG4Reco.h index 3eb6ce014b..180ae3966e 100644 --- a/simulation/g4simulation/g4main/PHG4Reco.h +++ b/simulation/g4simulation/g4main/PHG4Reco.h @@ -103,15 +103,15 @@ class PHG4Reco : public SubsysReco m_ForceDecayType = force_decay_type; } - void set_decayer(DecayerOptions type) {m_Decayer = type;} + void set_decayer(DecayerOptions type) { m_Decayer = type; } //! export geometry to root file - void export_geometry( bool b, const std::string& filename = "sPHENIXGeom.root" ) + void export_geometry(bool b, const std::string &filename = "sPHENIXGeom.root") { m_ExportGeometry = b; m_ExportGeomFilename = filename; } - + //! Save geometry from Geant4 to DST void save_DST_geometry(bool b) { m_SaveDstGeometryFlag = b; } void SetWorldSizeX(const double sx) { m_WorldSize[0] = sx; } @@ -140,10 +140,10 @@ class PHG4Reco : public SubsysReco void setDisableUserActions(bool b = true) { m_disableUserActions = b; } void ApplyDisplayAction(); - void CustomizeEvtGenDecay(const std::string& DecayFile) + void CustomizeEvtGenDecay(const std::string &DecayFile) { - EvtGenDecayFile = DecayFile; - if(!EvtGenDecayFile.empty()) CustomizeDecay = true; + EvtGenDecayFile = DecayFile; + if (!EvtGenDecayFile.empty()) CustomizeDecay = true; } private: @@ -154,7 +154,7 @@ class PHG4Reco : public SubsysReco float m_MagneticField = 0.; float m_MagneticFieldRescale = 1.0; - double m_WorldSize[3]{1000.,1000.,1000.}; + double m_WorldSize[3]{1000., 1000., 1000.}; //! magnetic field G4TBMagneticFieldSetup *m_Field = nullptr; @@ -207,14 +207,13 @@ class PHG4Reco : public SubsysReco bool m_ExportGeometry = false; std::string m_ExportGeomFilename = "sPHENIXGeom.root"; - + // settings for the external Pythia6 decayer - //bool m_ActiveDecayerFlag = true; //< turn on/off decayer + // bool m_ActiveDecayerFlag = true; //< turn on/off decayer bool m_ActiveForceDecayFlag = false; //< turn on/off force decay channels - DecayerOptions m_Decayer = kEvtGenDecayer; // Here we use EvtGen as default - std::string EvtGenDecayFile = ""; + std::string EvtGenDecayFile = ""; bool CustomizeDecay = false; EDecayType m_ForceDecayType = kAll; //< forced decay channel setting From 836c9788d42e75adc8b370681b65e8b7380ebc87 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 21 May 2023 15:15:04 -0400 Subject: [PATCH 418/468] fix module --- offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index 572bcffa8c..ed507b66b7 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -969,7 +969,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } if (seed != nullptr) { - auto para_errors = ClusErrPara.get_cluster_error(seed, cluster, r, cluster_key); + auto para_errors = ClusErrPara.get_cluster_error(cluster, r, cluster_key, seed->get_qOverR(), seed->get_slope()); pephi = sqrt(para_errors.first * Acts::UnitConstants::cm2); pez = sqrt(para_errors.second * Acts::UnitConstants::cm2); } From 2ae979d14f0730597042229c9f332008ec463906 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 18:14:50 -0400 Subject: [PATCH 419/468] move to new client --- offline/database/sphenixnpc/sphenixnpc.cc | 140 ++++++++-------------- offline/database/sphenixnpc/sphenixnpc.h | 22 ++-- 2 files changed, 58 insertions(+), 104 deletions(-) diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/sphenixnpc.cc index 7ba789ed87..d03827034c 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/sphenixnpc.cc @@ -9,13 +9,46 @@ sphenixnpc::sphenixnpc() {} -sphenixnpc::sphenixnpc(const std::string &globaltag) +sphenixnpc::sphenixnpc(const std::string >_name): nopayloadclient::NoPayloadClient(gt_name) { - cache_set_GlobalTag(globaltag); +//cache_set_GlobalTag(globaltag); } +nlohmann::json sphenixnpc::getPayloadIOVs(long long iov) { + return nopayloadclient::NoPayloadClient::getPayloadIOVs(0, iov); +} +nlohmann::json sphenixnpc::getUrl(const std::string& pl_type, long long iov) { + nlohmann::json resp = getPayloadIOVs(iov); + if (resp["code"] != 0) return resp; + nlohmann::json payload_iovs = resp["msg"]; + if (!payload_iovs.contains(pl_type)) { + return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); + } + nlohmann::json payload_iov = payload_iovs[pl_type]; + if (payload_iov["minor_iov_end"] < iov) { + return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); + } + return makeResp(payload_iov["payload_url"]); +} +nlohmann::json sphenixnpc::insertPayload(const std::string& pl_type, const std::string& file_url, + long long iov_start) { + return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start); +} + +nlohmann::json sphenixnpc::insertPayload(const std::string& pl_type, const std::string& file_url, + long long iov_start, long long iov_end) { + return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); +} -nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) +nlohmann::json sphenixnpc::setGlobalTag(const std::string& name) { + return nopayloadclient::NoPayloadClient::setGlobalTag(name); +} + +nlohmann::json sphenixnpc::clearCache() { + return nopayloadclient::NoPayloadClient::clearCache(); +} + +nlohmann::json sphenixnpc::createGlobalTag1(const std::string &tagname) { if (tagname == m_CachedGlobalTag) // global tag already set { @@ -24,7 +57,7 @@ nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) } // check if the global tag exists already bool found_gt = false; - nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; for (auto &it : msgcont.items()) { @@ -41,7 +74,7 @@ nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) std::string message = "global tag " + tagname + " already exists"; return {{"code", 0}, {"msg", message}}; } - resp = nopayloadclient::Client::createGlobalTag(tagname); + resp = nopayloadclient::NoPayloadClient::createGlobalTag(tagname); int iret = resp["code"]; if (iret != 0) { @@ -49,7 +82,7 @@ nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) } else { - nopayloadclient::Client::setGlobalTag(tagname); + nopayloadclient::NoPayloadClient::setGlobalTag(tagname); m_CachedGlobalTag = tagname; clearCache(); std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; @@ -57,47 +90,15 @@ nlohmann::json sphenixnpc::createGlobalTag(const std::string &tagname) return resp; } -nlohmann::json sphenixnpc::getUrlDict(long long iov) -{ - return nopayloadclient::Client::getUrlDict(iov,iov); -} - -nlohmann::json sphenixnpc::getUrlDict(long long iov1, long long iov2) -{ - return nopayloadclient::Client::getUrlDict(iov1,iov2); -} - -nlohmann::json sphenixnpc::get(const std::string &pl_type, long long iov) -{ - if (url_dict_.is_null()) - { - nlohmann::json resp = getUrlDict(iov); - std::cout << "response" << std::endl; - std::cout << resp << std::endl; - std::cout << "end response" << std::endl; - if (resp["code"] != 0) - { - return resp; - } - url_dict_ = resp["msg"]; - } - if (not url_dict_.contains(pl_type)) - { - return nopayloadclient::DataBaseException("No payload with type " + pl_type + " exists.").jsonify(); - } - return makeResp(url_dict_[pl_type]); -} - -nlohmann::json sphenixnpc::setGlobalTag(const std::string &tagname) +nlohmann::json sphenixnpc::setGlobalTag1(const std::string &tagname) { if (tagname == m_CachedGlobalTag) // global tag already set { std::string message = "global tag already set to " + tagname; return {{"code", 0}, {"msg", message}}; } - url_dict_ = nlohmann::json{}; bool found_gt = false; - nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; for (auto &it : msgcont.items()) { @@ -112,7 +113,7 @@ nlohmann::json sphenixnpc::setGlobalTag(const std::string &tagname) if (found_gt) { m_CachedGlobalTag = tagname; - resp = nopayloadclient::Client::setGlobalTag(tagname); + resp = nopayloadclient::NoPayloadClient::setGlobalTag(tagname); return resp; } std::string message = "global tag " + tagname + " does not exist"; @@ -126,11 +127,10 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) { return iret; } - url_dict_ = nlohmann::json{}; m_CachedGlobalTag = tagname; - nopayloadclient::Client::setGlobalTag(tagname); + nopayloadclient::NoPayloadClient::setGlobalTag(tagname); bool found_gt = false; - nlohmann::json resp = nopayloadclient::Client::getGlobalTags(); + nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; for (auto &it : msgcont.items()) { @@ -144,7 +144,7 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) } if (!found_gt) { - resp = nopayloadclient::Client::createGlobalTag(); + resp = nopayloadclient::NoPayloadClient::createGlobalTag(); iret = resp["code"]; if (iret != 0) { @@ -158,59 +158,13 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) return iret; } -nlohmann::json sphenixnpc::clearCache() -{ - url_dict_ = nlohmann::json{}; - return nopayloadclient::Client::clearCache(); -} - -std::string sphenixnpc::getUrl(const std::string &type, uint64_t iov) -{ - if (iov != m_CachedIOV) - { - clearCache(); - m_CachedIOV = iov; - } - nlohmann::json result = get(type, iov); - std::string fullUrl = result.at("msg"); - if (fullUrl.find("Exception") != std::string::npos) - { - if (Verbosity()) - { - std::cout << fullUrl << std::endl; - } - return std::string(""); - } - return fullUrl; -} - -nlohmann::json sphenixnpc::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start) -{ - nlohmann::json resp = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start); - if (Verbosity()) - { - std::cout << resp << std::endl; - } - return resp; -} - -nlohmann::json sphenixnpc::insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end) -{ - nlohmann::json ret = nopayloadclient::Client::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); - if (Verbosity()) - { - std::cout << ret << std::endl; - } - return ret; -} - int sphenixnpc::createDomain(const std::string &domain) { int iret = -1; nlohmann::json resp; if (m_DomainCache.empty()) { - resp = nopayloadclient::Client::getPayloadTypes(); + resp = nopayloadclient::NoPayloadClient::getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; for (auto &it : msgcont.items()) { @@ -220,7 +174,7 @@ int sphenixnpc::createDomain(const std::string &domain) } if (m_DomainCache.find(domain) == m_DomainCache.end()) { - resp = nopayloadclient::Client::createPayloadType(domain); + resp = nopayloadclient::NoPayloadClient::createPayloadType(domain); iret = resp["code"]; if (iret == 0) { diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/sphenixnpc.h index 5cdb5daef3..3cb35d0747 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/sphenixnpc.h @@ -5,28 +5,29 @@ #include + #include #include #include #include -class sphenixnpc : public nopayloadclient::Client +class sphenixnpc : public nopayloadclient::NoPayloadClient { public: sphenixnpc(); sphenixnpc(const std::string &globaltag); virtual ~sphenixnpc() = default; - nlohmann::json getUrlDict(long long iov); - nlohmann::json getUrlDict(long long iov1, long long iov2) override; - nlohmann::json createGlobalTag(const std::string &tagname) override; + nlohmann::json getPayloadIOVs(long long iov); + nlohmann::json getUrl(const std::string& pl_type, long long iov); + nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start); + nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end); + nlohmann::json setGlobalTag1(const std::string& name); + nlohmann::json clearCache(); + + nlohmann::json createGlobalTag1(const std::string &tagname); int createDomain(const std::string &domain); - nlohmann::json setGlobalTag(const std::string &tagname) override; - nlohmann::json get(const std::string &pl_type, long long iov); + nlohmann::json setGlobalTag(const std::string &tagname); int cache_set_GlobalTag(const std::string &name); - nlohmann::json clearCache() override; - std::string getUrl(const std::string &type, uint64_t iov); - nlohmann::json insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); - nlohmann::json insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } @@ -34,7 +35,6 @@ class sphenixnpc : public nopayloadclient::Client private: int m_Verbosity = 0; uint64_t m_CachedIOV = 0; - nlohmann::json url_dict_; // valid until global tag is switched std::string m_CachedGlobalTag; std::set m_DomainCache; }; From 8ce049bcab7054e23d62ecdb509f777e7a1fa8a1 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 18:18:27 -0400 Subject: [PATCH 420/468] rename sphenixnpc to SphenixClient to follow Linos implementation --- offline/database/sphenixnpc/CDBUtils.cc | 6 ++-- offline/database/sphenixnpc/CDBUtils.h | 6 ++-- offline/database/sphenixnpc/Makefile.am | 4 +-- .../{sphenixnpc.cc => SphenixClient.cc} | 32 +++++++++---------- .../{sphenixnpc.h => SphenixClient.h} | 14 ++++---- 5 files changed, 31 insertions(+), 31 deletions(-) rename offline/database/sphenixnpc/{sphenixnpc.cc => SphenixClient.cc} (81%) rename offline/database/sphenixnpc/{sphenixnpc.h => SphenixClient.h} (79%) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index c3c236578f..0ee6974bf9 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -1,6 +1,6 @@ #include "CDBUtils.h" -#include "sphenixnpc.h" +#include "SphenixClient.h" #include @@ -8,11 +8,11 @@ #include CDBUtils::CDBUtils() - : cdbclient(new sphenixnpc()) + : cdbclient(new SphenixClient()) {} CDBUtils::CDBUtils(const std::string &globaltag) - : cdbclient(new sphenixnpc(globaltag)) + : cdbclient(new SphenixClient(globaltag)) { } diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index df9e55fdf8..30046c1164 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -6,7 +6,7 @@ #include #include -class sphenixnpc; +class SphenixClient; class CDBUtils { @@ -34,9 +34,9 @@ class CDBUtils private: int m_Verbosity = 0; - sphenixnpc *cdbclient = nullptr; + SphenixClient *cdbclient = nullptr; std::string m_CachedGlobalTag; std::set m_DomainCache; }; -#endif // SPHENIXNPC_SPHENIXNPC_H +#endif // SPHENIXNPC_CDBUTILS_H diff --git a/offline/database/sphenixnpc/Makefile.am b/offline/database/sphenixnpc/Makefile.am index 80e6b2344f..10b7d1188f 100644 --- a/offline/database/sphenixnpc/Makefile.am +++ b/offline/database/sphenixnpc/Makefile.am @@ -16,7 +16,7 @@ AM_LDFLAGS = \ libsphenixnpc_la_SOURCES = \ CDBUtils.cc \ - sphenixnpc.cc + SphenixClient.cc libsphenixnpc_la_LIBADD = \ @@ -27,7 +27,7 @@ libsphenixnpc_la_LIBADD = \ pkginclude_HEADERS = \ CDBUtils.h \ - sphenixnpc.h + SphenixClient.h ################################################ # linking tests diff --git a/offline/database/sphenixnpc/sphenixnpc.cc b/offline/database/sphenixnpc/SphenixClient.cc similarity index 81% rename from offline/database/sphenixnpc/sphenixnpc.cc rename to offline/database/sphenixnpc/SphenixClient.cc index d03827034c..5a1907581a 100644 --- a/offline/database/sphenixnpc/sphenixnpc.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -1,4 +1,4 @@ -#include "sphenixnpc.h" +#include "SphenixClient.h" #include @@ -6,18 +6,18 @@ #include #include -sphenixnpc::sphenixnpc() +SphenixClient::SphenixClient() {} -sphenixnpc::sphenixnpc(const std::string >_name): nopayloadclient::NoPayloadClient(gt_name) +SphenixClient::SphenixClient(const std::string >_name): nopayloadclient::NoPayloadClient(gt_name) { //cache_set_GlobalTag(globaltag); } -nlohmann::json sphenixnpc::getPayloadIOVs(long long iov) { +nlohmann::json SphenixClient::getPayloadIOVs(long long iov) { return nopayloadclient::NoPayloadClient::getPayloadIOVs(0, iov); } -nlohmann::json sphenixnpc::getUrl(const std::string& pl_type, long long iov) { +nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) { nlohmann::json resp = getPayloadIOVs(iov); if (resp["code"] != 0) return resp; nlohmann::json payload_iovs = resp["msg"]; @@ -30,25 +30,25 @@ nlohmann::json sphenixnpc::getUrl(const std::string& pl_type, long long iov) { } return makeResp(payload_iov["payload_url"]); } -nlohmann::json sphenixnpc::insertPayload(const std::string& pl_type, const std::string& file_url, +nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start) { return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start); } -nlohmann::json sphenixnpc::insertPayload(const std::string& pl_type, const std::string& file_url, +nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end) { return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); } -nlohmann::json sphenixnpc::setGlobalTag(const std::string& name) { +nlohmann::json SphenixClient::setGlobalTag(const std::string& name) { return nopayloadclient::NoPayloadClient::setGlobalTag(name); } -nlohmann::json sphenixnpc::clearCache() { +nlohmann::json SphenixClient::clearCache() { return nopayloadclient::NoPayloadClient::clearCache(); } -nlohmann::json sphenixnpc::createGlobalTag1(const std::string &tagname) +nlohmann::json SphenixClient::createGlobalTag1(const std::string &tagname) { if (tagname == m_CachedGlobalTag) // global tag already set { @@ -85,12 +85,12 @@ nlohmann::json sphenixnpc::createGlobalTag1(const std::string &tagname) nopayloadclient::NoPayloadClient::setGlobalTag(tagname); m_CachedGlobalTag = tagname; clearCache(); - std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; + std::cout << "SphenixClient: Created new global tag " << tagname << std::endl; } return resp; } -nlohmann::json sphenixnpc::setGlobalTag1(const std::string &tagname) +nlohmann::json SphenixClient::setGlobalTag1(const std::string &tagname) { if (tagname == m_CachedGlobalTag) // global tag already set { @@ -120,7 +120,7 @@ std::string message = "global tag " + tagname + " does not exist"; return {{"code", -1}, {"msg", message}}; } -int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) +int SphenixClient::cache_set_GlobalTag(const std::string &tagname) { int iret = 0; if (tagname == m_CachedGlobalTag) // global tag already set @@ -152,13 +152,13 @@ int sphenixnpc::cache_set_GlobalTag(const std::string &tagname) } else { - std::cout << "sphenixnpc: Created new global tag " << tagname << std::endl; + std::cout << "SphenixClient: Created new global tag " << tagname << std::endl; } } return iret; } -int sphenixnpc::createDomain(const std::string &domain) +int SphenixClient::createDomain(const std::string &domain) { int iret = -1; nlohmann::json resp; @@ -188,7 +188,7 @@ int sphenixnpc::createDomain(const std::string &domain) return iret; } -bool sphenixnpc::isGlobalTagSet() +bool SphenixClient::isGlobalTagSet() { if (m_CachedGlobalTag.empty()) { diff --git a/offline/database/sphenixnpc/sphenixnpc.h b/offline/database/sphenixnpc/SphenixClient.h similarity index 79% rename from offline/database/sphenixnpc/sphenixnpc.h rename to offline/database/sphenixnpc/SphenixClient.h index 3cb35d0747..6ffd9ff2a9 100644 --- a/offline/database/sphenixnpc/sphenixnpc.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -1,5 +1,5 @@ -#ifndef SPHENIXNPC_SPHENIXNPC_H -#define SPHENIXNPC_SPHENIXNPC_H +#ifndef SPHENIXNPC_SPHENIXCLIENT_H +#define SPHENIXNPC_SPHENIXCLIENT_H #include @@ -11,12 +11,12 @@ #include #include -class sphenixnpc : public nopayloadclient::NoPayloadClient +class SphenixClient : public nopayloadclient::NoPayloadClient { public: - sphenixnpc(); - sphenixnpc(const std::string &globaltag); - virtual ~sphenixnpc() = default; + SphenixClient(); + SphenixClient(const std::string &globaltag); + virtual ~SphenixClient() = default; nlohmann::json getPayloadIOVs(long long iov); nlohmann::json getUrl(const std::string& pl_type, long long iov); nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start); @@ -39,4 +39,4 @@ class sphenixnpc : public nopayloadclient::NoPayloadClient std::set m_DomainCache; }; -#endif // SPHENIXNPC_SPHENIXNPC_H +#endif // SPHENIXNPC_SPHENIXCLIENT_H From dc990dbb0d8a5eaae47a3c5832a08132bc005d61 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 May 2023 18:41:21 -0400 Subject: [PATCH 421/468] remove eASTPhysicsList --- .../g4simulation/eASTPhysicsList/Makefile.am | 61 --- .../g4simulation/eASTPhysicsList/autogen.sh | 9 - .../g4simulation/eASTPhysicsList/configure.ac | 19 - .../eASTPhysicsList/eASTAntiBaryonPhysics.cc | 433 ------------------ .../eASTPhysicsList/eASTAntiBaryonPhysics.hh | 43 -- .../eASTGammaLeptoNuclearPhysics.cc | 134 ------ .../eASTGammaLeptoNuclearPhysics.hh | 43 -- .../eASTPhysicsList/eASTHyperonPhysics.cc | 257 ----------- .../eASTPhysicsList/eASTHyperonPhysics.hh | 42 -- .../eASTPhysicsList/eASTIonPhysics.cc | 206 --------- .../eASTPhysicsList/eASTIonPhysics.hh | 46 -- .../eASTPhysicsList/eASTKaonPhysics.cc | 205 --------- .../eASTPhysicsList/eASTKaonPhysics.hh | 42 -- .../eASTPhysicsList/eASTNeutronPhysics.cc | 136 ------ .../eASTPhysicsList/eASTNeutronPhysics.hh | 41 -- .../eASTPhysicsList/eASTPhysicsList.cc | 254 ---------- .../eASTPhysicsList/eASTPhysicsList.hh | 87 ---- .../eASTPhysicsListMessenger.cc | 286 ------------ .../eASTPhysicsListMessenger.hh | 53 --- .../eASTPhysicsList/eASTPionPhysics.cc | 151 ------ .../eASTPhysicsList/eASTPionPhysics.hh | 41 -- .../eASTPhysicsList/eASTProtonPhysics.cc | 109 ----- .../eASTPhysicsList/eASTProtonPhysics.hh | 41 -- 23 files changed, 2739 deletions(-) delete mode 100644 simulation/g4simulation/eASTPhysicsList/Makefile.am delete mode 100755 simulation/g4simulation/eASTPhysicsList/autogen.sh delete mode 100644 simulation/g4simulation/eASTPhysicsList/configure.ac delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.hh delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.cc delete mode 100644 simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.hh diff --git a/simulation/g4simulation/eASTPhysicsList/Makefile.am b/simulation/g4simulation/eASTPhysicsList/Makefile.am deleted file mode 100644 index 2df119efa1..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CXXFLAGS = `geant4-config --cflags` - -lib_LTLIBRARIES = \ - libeASTPhysicsList.la - -# set in configure.in to check if gcc version >= 4.8 -# leave this here to show how it can be done, -std=c++11 is now -# enabled by default in our config.site -#if GCC_GE_48 -# AM_CXXFLAGS = -std=c++11 -#endif - -AM_CPPFLAGS = \ - -I$(includedir) \ - -I$(OFFLINE_MAIN)/include - -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - `geant4-config --libs` - -libeASTPhysicsList_la_SOURCES = \ - eASTAntiBaryonPhysics.cc \ - eASTGammaLeptoNuclearPhysics.cc \ - eASTHyperonPhysics.cc \ - eASTIonPhysics.cc \ - eASTKaonPhysics.cc \ - eASTNeutronPhysics.cc \ - eASTPhysicsList.cc \ - eASTPhysicsListMessenger.cc \ - eASTPionPhysics.cc \ - eASTProtonPhysics.cc - -pkginclude_HEADERS = \ - eASTPhysicsList.hh - -################################################ -# linking tests - -noinst_PROGRAMS = \ - testexternals - -BUILT_SOURCES = testexternals.cc - -testexternals_SOURCES = \ - testexternals.cc - -testexternals_LDADD = \ - libeASTPhysicsList.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ - -clean-local: - rm -f $(BUILT_SOURCES) diff --git a/simulation/g4simulation/eASTPhysicsList/autogen.sh b/simulation/g4simulation/eASTPhysicsList/autogen.sh deleted file mode 100755 index 333dd3b499..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/autogen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) - -$srcdir/configure "$@" - diff --git a/simulation/g4simulation/eASTPhysicsList/configure.ac b/simulation/g4simulation/eASTPhysicsList/configure.ac deleted file mode 100644 index bfdbb10498..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/configure.ac +++ /dev/null @@ -1,19 +0,0 @@ -AC_INIT(eastphysicslist, [1.00]) -AC_CONFIG_SRCDIR([configure.ac]) - -AM_INIT_AUTOMAKE - -AC_PROG_CXX(CC g++) -LT_INIT([disable-static]) - -CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" - -case $CXX in - clang++) - CXXFLAGS="$CXXFLAGS -Wno-final-dtor-non-final-class" - ;; -esac -dnl AM_CONDITIONAL(GCC_GE_48, test `g++ -dumpversion | awk '{print $1>=4.8?"1":"0"}'` = 1) - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.cc deleted file mode 100644 index 23593fcaa6..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.cc +++ /dev/null @@ -1,433 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTAntiBaryonPhysics.cc -// Anti-baryon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.02.2021 : migration to Geant4 version 10.7 - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTAntiBaryonPhysics.hh" - -#include "G4ProcessManager.hh" - -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4AntiProtonInelasticProcess.hh" -#include "G4AntiNeutronInelasticProcess.hh" -#include "G4AntiLambdaInelasticProcess.hh" -#include "G4AntiSigmaPlusInelasticProcess.hh" -#include "G4AntiSigmaMinusInelasticProcess.hh" -#include "G4AntiXiZeroInelasticProcess.hh" -#include "G4AntiXiMinusInelasticProcess.hh" -#include "G4AntiOmegaMinusInelasticProcess.hh" -#include "G4AntiDeuteronInelasticProcess.hh" -#include "G4AntiTritonInelasticProcess.hh" -#include "G4AntiHe3InelasticProcess.hh" -#include "G4AntiAlphaInelasticProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#endif - -#include "G4HadronElasticProcess.hh" - -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4HadronElastic.hh" -#include "G4AntiNuclElastic.hh" -#include "G4HadronicAbsorptionFritiof.hh" - -#include "G4ChipsAntiBaryonElasticXS.hh" -#include "G4ChipsHyperonInelasticXS.hh" -#include "G4ComponentAntiNuclNuclearXS.hh" -#include "G4ChipsAntiBaryonElasticXS.hh" -#include "G4CrossSectionInelastic.hh" -#include "G4CrossSectionElastic.hh" - -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTAntiBaryonPhysics::eASTAntiBaryonPhysics() -{} - -eASTAntiBaryonPhysics::~eASTAntiBaryonPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; - - delete theAntiNucleonXS; -} -#else -eASTAntiBaryonPhysics::eASTAntiBaryonPhysics() -: G4VPhysicsConstructor("eASTAntiBaryon") -{;} - -eASTAntiBaryonPhysics::~eASTAntiBaryonPhysics() -{;} -#endif - -void eASTAntiBaryonPhysics::ConstructParticle() -{} - - -void eASTAntiBaryonPhysics::ConstructProcess() -{ - G4ProcessManager* procMan = 0; - - // One elastic model for all anti-hyperon and anti-neutron energies - G4HadronElastic* elModel = new G4HadronElastic(); - - // Elastic models for anti-(p, d, t, He3, alpha) - G4HadronElastic* loelModel = new G4HadronElastic(); - loelModel->SetMaxEnergy(100.1*MeV); - - G4AntiNuclElastic* anucEl = new G4AntiNuclElastic(); - anucEl->SetMinEnergy(100.0*MeV); - - // Use FTFP for all energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(0.0); - ftfp->SetMaxEnergy(100*TeV); - - // Elastic data sets - G4CrossSectionElastic* anucElxs = - new G4CrossSectionElastic(anucEl->GetComponentCrossSection() ); - G4VCrossSectionDataSet* abaryElXs = new G4ChipsAntiBaryonElasticXS; - - G4VCrossSectionDataSet* anucnucElxs = - new G4CrossSectionElastic(new G4ComponentAntiNuclNuclearXS); - - // Inelastic cross section sets - theAntiNucleonXS = new G4ComponentAntiNuclNuclearXS; - G4VCrossSectionDataSet* antiNucleonData = - new G4CrossSectionInelastic(theAntiNucleonXS); - - G4ChipsHyperonInelasticXS* hchipsInelastic = new G4ChipsHyperonInelasticXS; - - ////////////////////////////////////////////////////////////////////////////// - // Anti-proton // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiProton::AntiProton()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* apProcEl = new G4HadronElasticProcess; - apProcEl->RegisterMe(loelModel); - apProcEl->RegisterMe(anucEl); - apProcEl->AddDataSet(anucElxs); - procMan->AddDiscreteProcess(apProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiProtonInelasticProcess* apProcInel = new G4AntiProtonInelasticProcess; -#else - auto* apProcInel = new G4HadronInelasticProcess("AntiProtonInelasticProcess", - G4AntiProton::AntiProton() ); -#endif - apProcInel->RegisterMe(ftfp); - apProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(apProcInel); - - // stopping - G4HadronicAbsorptionFritiof* apAbsorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(apAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-neutron // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiNeutron::AntiNeutron()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* anProcEl = new G4HadronElasticProcess; - anProcEl->RegisterMe(elModel); - anProcEl->AddDataSet(anucnucElxs); - procMan->AddDiscreteProcess(anProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiNeutronInelasticProcess* anProcInel = new G4AntiNeutronInelasticProcess; -#else - auto* anProcInel = new G4HadronInelasticProcess("AntiNeutronInelasticProcess", - G4AntiNeutron::AntiNeutron() ); -#endif - anProcInel->RegisterMe(ftfp); - anProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(anProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-deuteron // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiDeuteron::AntiDeuteron()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* adProcEl = new G4HadronElasticProcess; - adProcEl->RegisterMe(loelModel); - adProcEl->RegisterMe(anucEl); - adProcEl->AddDataSet(anucElxs); - procMan->AddDiscreteProcess(adProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiDeuteronInelasticProcess* adProcInel = new G4AntiDeuteronInelasticProcess; -#else - auto* adProcInel = new G4HadronInelasticProcess("AntiDeuteronInelasticProcess", - G4AntiDeuteron::AntiDeuteron() ); -#endif - adProcInel->RegisterMe(ftfp); - adProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(adProcInel); - - // stopping - G4HadronicAbsorptionFritiof* adAbsorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(adAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-triton // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiTriton::AntiTriton()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* atProcEl = new G4HadronElasticProcess; - atProcEl->RegisterMe(loelModel); - atProcEl->RegisterMe(anucEl); - atProcEl->AddDataSet(anucElxs); - procMan->AddDiscreteProcess(atProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiTritonInelasticProcess* atProcInel = new G4AntiTritonInelasticProcess; -#else - auto* atProcInel = new G4HadronInelasticProcess("AntiTritonInelasticProcess", - G4AntiTriton::AntiTriton() ); -#endif - atProcInel->RegisterMe(ftfp); - atProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(atProcInel); - - // stopping - G4HadronicAbsorptionFritiof* atAbsorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(atAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-He3 // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiHe3::AntiHe3()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* ahe3ProcEl = new G4HadronElasticProcess; - ahe3ProcEl->RegisterMe(loelModel); - ahe3ProcEl->RegisterMe(anucEl); - ahe3ProcEl->AddDataSet(anucElxs); - procMan->AddDiscreteProcess(ahe3ProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiHe3InelasticProcess* ahe3ProcInel = new G4AntiHe3InelasticProcess; -#else - auto* ahe3ProcInel = new G4HadronInelasticProcess("Anti3HeInelasticProcess", - G4AntiHe3::AntiHe3() ); -#endif - ahe3ProcInel->RegisterMe(ftfp); - ahe3ProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(ahe3ProcInel); - - // stopping - G4HadronicAbsorptionFritiof* ahe3Absorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(ahe3Absorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-alpha // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiAlpha::AntiAlpha()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* aaProcEl = new G4HadronElasticProcess; - aaProcEl->RegisterMe(loelModel); - aaProcEl->RegisterMe(anucEl); - aaProcEl->AddDataSet(anucElxs); - procMan->AddDiscreteProcess(aaProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiAlphaInelasticProcess* aaProcInel = new G4AntiAlphaInelasticProcess; -#else - auto* aaProcInel = new G4HadronInelasticProcess("AntiAlphaInelasticProcess", - G4AntiAlpha::AntiAlpha() ); -#endif - aaProcInel->RegisterMe(ftfp); - aaProcInel->AddDataSet(antiNucleonData); - procMan->AddDiscreteProcess(aaProcInel); - - // stopping - G4HadronicAbsorptionFritiof* aaAbsorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(aaAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-lambda // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiLambda::AntiLambda()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* alamProcEl = new G4HadronElasticProcess; - alamProcEl->RegisterMe(elModel); - alamProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(alamProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiLambdaInelasticProcess* alamProcInel = new G4AntiLambdaInelasticProcess; -#else - auto* alamProcInel = new G4HadronInelasticProcess("AntiLambdaInelasticProcess", - G4AntiLambda::AntiLambda() ); -#endif - alamProcInel->RegisterMe(ftfp); - alamProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(alamProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-sigma+ // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiSigmaPlus::AntiSigmaPlus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* aspProcEl = new G4HadronElasticProcess; - aspProcEl->RegisterMe(elModel); - aspProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(aspProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiSigmaPlusInelasticProcess* aspProcInel = new G4AntiSigmaPlusInelasticProcess; -#else - auto* aspProcInel = new G4HadronInelasticProcess("AntiSigmaPInelasticProcess", - G4AntiSigmaPlus::AntiSigmaPlus() ); -#endif - aspProcInel->RegisterMe(ftfp); - aspProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(aspProcInel); - - // stopping - G4HadronicAbsorptionFritiof* aspAbsorb = new G4HadronicAbsorptionFritiof(); - procMan->AddRestProcess(aspAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-sigma- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiSigmaMinus::AntiSigmaMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* asmProcEl = new G4HadronElasticProcess; - asmProcEl->RegisterMe(elModel); - asmProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(asmProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiSigmaMinusInelasticProcess* asmProcInel = new G4AntiSigmaMinusInelasticProcess; -#else - auto* asmProcInel = new G4HadronInelasticProcess("AntiSigmaMInelasticProcess", - G4AntiSigmaMinus::AntiSigmaMinus() ); -#endif - asmProcInel->RegisterMe(ftfp); - asmProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(asmProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-xi0 // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiXiZero::AntiXiZero()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* axzProcEl = new G4HadronElasticProcess; - axzProcEl->RegisterMe(elModel); - axzProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(axzProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiXiZeroInelasticProcess* axzProcInel = new G4AntiXiZeroInelasticProcess; -#else - auto* axzProcInel = new G4HadronInelasticProcess("AntiXi0InelasticProcess", - G4AntiXiZero::AntiXiZero() ); -#endif - axzProcInel->RegisterMe(ftfp); - axzProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(axzProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-xi- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiXiMinus::AntiXiMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* axmProcEl = new G4HadronElasticProcess; - axmProcEl->RegisterMe(elModel); - axmProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(axmProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiXiMinusInelasticProcess* axmProcInel = new G4AntiXiMinusInelasticProcess; -#else - auto* axmProcInel = new G4HadronInelasticProcess("AntiXiMInelasticProcess", - G4AntiXiMinus::AntiXiMinus() ); -#endif - axmProcInel->RegisterMe(ftfp); - axmProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(axmProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Anti-omega- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4AntiOmegaMinus::AntiOmegaMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* aomProcEl = new G4HadronElasticProcess; - aomProcEl->RegisterMe(elModel); - aomProcEl->AddDataSet(abaryElXs); - procMan->AddDiscreteProcess(aomProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4AntiOmegaMinusInelasticProcess* aomProcInel = new G4AntiOmegaMinusInelasticProcess; -#else - auto* aomProcInel = new G4HadronInelasticProcess("AntiOmegaMInelasticProcess", - G4AntiOmegaMinus::AntiOmegaMinus() ); -#endif - aomProcInel->RegisterMe(ftfp); - aomProcInel->AddDataSet(hchipsInelastic); - procMan->AddDiscreteProcess(aomProcInel); - -} - -void eASTAntiBaryonPhysics::TerminateWorker() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.hh deleted file mode 100644 index c8957c8336..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTAntiBaryonPhysics.hh +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTAntiBaryonPhysics.hh -// Anti-baryon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTAntiBaryonPhysics_h -#define eASTAntiBaryonPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; -class G4ComponentAntiNuclNuclearXS; - -class eASTAntiBaryonPhysics: public G4VPhysicsConstructor -{ - public: - eASTAntiBaryonPhysics(); - ~eASTAntiBaryonPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - virtual void TerminateWorker() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - - G4ComponentAntiNuclNuclearXS* theAntiNucleonXS = nullptr; -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.cc deleted file mode 100644 index 5722df185f..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.cc +++ /dev/null @@ -1,134 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTGammaLeptoNuclearPhysics.cc -// Description: Gamma-nuclear, electro-nuclear and muon-nuclear physics -// constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTGammaLeptoNuclearPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4PhotoNuclearProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#include "G4PhotoNuclearCrossSection.hh" -#include "G4HadronicProcess.hh" -#endif -#include "G4ElectronNuclearProcess.hh" -#include "G4PositronNuclearProcess.hh" -#include "G4MuonNuclearProcess.hh" - -#include "G4CascadeInterface.hh" -#include "G4ElectroVDNuclearModel.hh" -#include "G4MuonVDNuclearModel.hh" - -#include "G4TheoFSGenerator.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4QGSMFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" - -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTGammaLeptoNuclearPhysics::eASTGammaLeptoNuclearPhysics() -{} - -eASTGammaLeptoNuclearPhysics::~eASTGammaLeptoNuclearPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTGammaLeptoNuclearPhysics::eASTGammaLeptoNuclearPhysics() -: G4VPhysicsConstructor("eASTGammaLeptoNuclear") -{;} - -eASTGammaLeptoNuclearPhysics::~eASTGammaLeptoNuclearPhysics() -{;} -#endif - -void eASTGammaLeptoNuclearPhysics::ConstructProcess() -{ - // Use Bertini cascade for low energies - G4CascadeInterface* theGammaReaction = new G4CascadeInterface; - theGammaReaction->SetMinEnergy(0.0); - theGammaReaction->SetMaxEnergy(3.5*GeV); - - // Use QGSP for high energies - qgsp = new G4TheoFSGenerator("QGSP"); - stringModel = new G4QGSModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4QGSMFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - qgsp->SetHighEnergyGenerator(stringModel); - qgsp->SetTransport(preCompoundModel); - qgsp->SetMinEnergy(3*GeV); - qgsp->SetMaxEnergy(100*TeV); - - // Lepto-nuclear models - G4ElectroVDNuclearModel* evdn = new G4ElectroVDNuclearModel; - G4MuonVDNuclearModel* mvdn = new G4MuonVDNuclearModel; - - - G4ProcessManager* procMan = 0; - - // Gamma - procMan = G4Gamma::Gamma()->GetProcessManager(); -#if G4VERSION_NUMBER < 1100 - G4PhotoNuclearProcess* pnProc = new G4PhotoNuclearProcess; -#else - auto* pnProc = new G4HadronInelasticProcess("PhotoNuclearProcess", - G4Gamma::Gamma() ); - pnProc->AddDataSet(new G4PhotoNuclearCrossSection); -#endif - pnProc->RegisterMe(theGammaReaction); - pnProc->RegisterMe(qgsp); - procMan->AddDiscreteProcess(pnProc); - -//#if G4VERSION_NUMBER >= 1100 -// auto* photonCapture = new G4HadronicProcess( "photonNuclear", fCapture ); -// auto* photonFission = new G4HadronicProcess( "photonFission", fFission ); -// procMan->AddDiscreteProcess(photonCapture); -// procMan->AddDiscreteProcess(photonFission); -//#endif - - // Electron - procMan = G4Electron::Electron()->GetProcessManager(); - G4ElectronNuclearProcess* emn = new G4ElectronNuclearProcess; - emn->RegisterMe(evdn); - procMan->AddDiscreteProcess(emn); - - // Positron - procMan = G4Positron::Positron()->GetProcessManager(); - G4PositronNuclearProcess* epn = new G4PositronNuclearProcess; - epn->RegisterMe(evdn); - procMan->AddDiscreteProcess(epn); - - // Muon- - procMan = G4MuonMinus::MuonMinus()->GetProcessManager(); - G4MuonNuclearProcess* mun = new G4MuonNuclearProcess; - mun->RegisterMe(mvdn); - procMan->AddDiscreteProcess(mun); - - // Muon+ - procMan = G4MuonPlus::MuonPlus()->GetProcessManager(); - procMan->AddDiscreteProcess(mun); - -} - - -void eASTGammaLeptoNuclearPhysics::ConstructParticle() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.hh deleted file mode 100644 index 4f01426a58..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTGammaLeptoNuclearPhysics.hh +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTGammaLeptoNuclearPhysics.hh -// Description: Gamma-nuclear, electro-nuclear and muon-nuclear physics -// constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTGammaLeptoNuclearPhysics_h -#define eASTGammaLeptoNuclearPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" -#include "G4GammaParticipants.hh" -#include "G4QGSModel.hh" - -class G4TheoFSGenerator; -class G4ExcitedStringDecay; -class G4QGSMFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTGammaLeptoNuclearPhysics: public G4VPhysicsConstructor -{ - public: - eASTGammaLeptoNuclearPhysics(); - ~eASTGammaLeptoNuclearPhysics(); - - virtual void ConstructProcess() override; - virtual void ConstructParticle() override; - - private: - G4TheoFSGenerator* qgsp = nullptr; - G4QGSModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4QGSMFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.cc deleted file mode 100644 index b658f01aef..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.cc +++ /dev/null @@ -1,257 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTHyperonPhysics.cc -// Hyperon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.02.2021 : migration to Geant4 version 10.7 - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTHyperonPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4LambdaInelasticProcess.hh" -#include "G4SigmaPlusInelasticProcess.hh" -#include "G4SigmaMinusInelasticProcess.hh" -#include "G4XiZeroInelasticProcess.hh" -#include "G4XiMinusInelasticProcess.hh" -#include "G4OmegaMinusInelasticProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#endif - -#include "G4HadronElasticProcess.hh" -#include "G4HadronicAbsorptionBertini.hh" - -#include "G4CascadeInterface.hh" -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4HadronElastic.hh" - -#include "G4ChipsHyperonElasticXS.hh" -#include "G4ChipsHyperonInelasticXS.hh" -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTHyperonPhysics::eASTHyperonPhysics() -{} - -eASTHyperonPhysics::~eASTHyperonPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTHyperonPhysics::eASTHyperonPhysics() -: G4VPhysicsConstructor("eASTHyperon") -{;} - -eASTHyperonPhysics::~eASTHyperonPhysics() -{;} -#endif - -void eASTHyperonPhysics::ConstructParticle() -{} - - -void eASTHyperonPhysics::ConstructProcess() -{ - G4ProcessManager* procMan = 0; - - // One elastic model for all hyperon energies - G4HadronElastic* elModel = new G4HadronElastic(); - - // Use Bertini cascade for low energies - G4CascadeInterface* loInelModel = new G4CascadeInterface; - loInelModel->SetMinEnergy(0.0); - loInelModel->SetMaxEnergy(6.0*GeV); - - // Use FTFP for high energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(4*GeV); - ftfp->SetMaxEnergy(100*TeV); - - // Elastic and inelastic cross section sets - G4ChipsHyperonElasticXS* chipsElastic = new G4ChipsHyperonElasticXS; - G4ChipsHyperonInelasticXS* chipsInelastic = new G4ChipsHyperonInelasticXS; - - ////////////////////////////////////////////////////////////////////////////// - // Lambda // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4Lambda::Lambda()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* lamProcEl = new G4HadronElasticProcess; - lamProcEl->RegisterMe(elModel); - lamProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(lamProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4LambdaInelasticProcess* lamProcInel = new G4LambdaInelasticProcess; -#else - auto* lamProcInel = new G4HadronInelasticProcess("LambdaInelasticProcess", - G4Lambda::Lambda() ); -#endif - lamProcInel->RegisterMe(loInelModel); - lamProcInel->RegisterMe(ftfp); - lamProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(lamProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Sigma+ // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4SigmaPlus::SigmaPlus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* spProcEl = new G4HadronElasticProcess; - spProcEl->RegisterMe(elModel); - spProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(spProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4SigmaPlusInelasticProcess* spProcInel = new G4SigmaPlusInelasticProcess; -#else - auto* spProcInel = new G4HadronInelasticProcess("SigmaPlusInelasticProcess", - G4SigmaPlus::SigmaPlus() ); -#endif - spProcInel->RegisterMe(loInelModel); - spProcInel->RegisterMe(ftfp); - spProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(spProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Sigma- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4SigmaMinus::SigmaMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* smProcEl = new G4HadronElasticProcess; - smProcEl->RegisterMe(elModel); - smProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(smProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4SigmaMinusInelasticProcess* smProcInel = new G4SigmaMinusInelasticProcess; -#else - auto* smProcInel = new G4HadronInelasticProcess("SigmaMinusInelasticProcess", - G4SigmaMinus::SigmaMinus() ); -#endif - smProcInel->RegisterMe(loInelModel); - smProcInel->RegisterMe(ftfp); - smProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(smProcInel); - - // stopping - G4HadronicAbsorptionBertini* smAbsorb = new G4HadronicAbsorptionBertini; - procMan->AddRestProcess(smAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Xi0 // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4XiZero::XiZero()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* xzProcEl = new G4HadronElasticProcess; - xzProcEl->RegisterMe(elModel); - xzProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(xzProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4XiZeroInelasticProcess* xzProcInel = new G4XiZeroInelasticProcess; -#else - auto* xzProcInel = new G4HadronInelasticProcess("XiZeroInelasticProcess", - G4XiZero::XiZero() ); -#endif - xzProcInel->RegisterMe(loInelModel); - xzProcInel->RegisterMe(ftfp); - xzProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(xzProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Xi- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4XiMinus::XiMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* xmProcEl = new G4HadronElasticProcess; - xmProcEl->RegisterMe(elModel); - xmProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(xmProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4XiMinusInelasticProcess* xmProcInel = new G4XiMinusInelasticProcess; -#else - auto* xmProcInel = new G4HadronInelasticProcess("XiMinusInelasticProcess", - G4XiMinus::XiMinus() ); -#endif - xmProcInel->RegisterMe(loInelModel); - xmProcInel->RegisterMe(ftfp); - xmProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(xmProcInel); - - // stopping - G4HadronicAbsorptionBertini* xmAbsorb = new G4HadronicAbsorptionBertini; - procMan->AddRestProcess(xmAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // Omega- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4OmegaMinus::OmegaMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* omProcEl = new G4HadronElasticProcess; - omProcEl->RegisterMe(elModel); - omProcEl->AddDataSet(chipsElastic); - procMan->AddDiscreteProcess(omProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4OmegaMinusInelasticProcess* omProcInel = new G4OmegaMinusInelasticProcess; -#else - auto* omProcInel = new G4HadronInelasticProcess("OmegaMinusInelasticProcess", - G4OmegaMinus::OmegaMinus() ); -#endif - omProcInel->RegisterMe(loInelModel); - omProcInel->RegisterMe(ftfp); - omProcInel->AddDataSet(chipsInelastic); - procMan->AddDiscreteProcess(omProcInel); - - // stopping - G4HadronicAbsorptionBertini* omAbsorb = new G4HadronicAbsorptionBertini; - procMan->AddRestProcess(omAbsorb); - -} - -void eASTHyperonPhysics::TerminateWorker() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.hh deleted file mode 100644 index 9991dbb0cc..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTHyperonPhysics.hh +++ /dev/null @@ -1,42 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTHyperonPhysics.hh -// Hyperon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTHyperonPhysics_h -#define eASTHyperonPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTHyperonPhysics: public G4VPhysicsConstructor -{ - public: - eASTHyperonPhysics(); - ~eASTHyperonPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - virtual void TerminateWorker() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.cc deleted file mode 100644 index 3ba6c62214..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.cc +++ /dev/null @@ -1,206 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTIonPhysics.cc -// Ion hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTIonPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4HadronElasticProcess.hh" -#include "G4HadronInelasticProcess.hh" - -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4QMDReaction.hh" -#include "G4HadronicInteractionRegistry.hh" -#include "G4PreCompoundModel.hh" -#include "G4BinaryLightIonReaction.hh" -#include "G4HadronElastic.hh" -#include "G4NuclNuclDiffuseElastic.hh" - -#include "G4CrossSectionElastic.hh" -#include "G4CrossSectionInelastic.hh" -#include "G4ComponentGGNuclNuclXsc.hh" -#include "G4SystemOfUnits.hh" - -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -eASTIonPhysics::eASTIonPhysics() -{} - -eASTIonPhysics::~eASTIonPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; - - delete theGGNuclNuclXS; - delete ionGGXS; -} -#else -eASTIonPhysics::eASTIonPhysics() -: G4VPhysicsConstructor("eASTIon") -{;} - -eASTIonPhysics::~eASTIonPhysics() -{;} -#endif - -void eASTIonPhysics::ConstructParticle() -{} - - -void eASTIonPhysics::ConstructProcess() -{ - G4ProcessManager* procMan = 0; - - // Elastic model for generic ions (z > 2) - G4NuclNuclDiffuseElastic* ionElastic = new G4NuclNuclDiffuseElastic; - ionElastic->SetMinEnergy(0.0); - - // FTFP ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(10.01*GeV); - ftfp->SetMaxEnergy(1.0*TeV); - - // QMD model - G4QMDReaction* qmd = new G4QMDReaction; - qmd->SetMinEnergy(100.0*MeV); - qmd->SetMaxEnergy(10.0*GeV); - - // BIC ion model - G4HadronicInteraction* p = - G4HadronicInteractionRegistry::Instance()->FindModel("PRECO"); - G4PreCompoundModel* thePreCompound = static_cast(p); - if(!thePreCompound) { thePreCompound = new G4PreCompoundModel; } - - G4BinaryLightIonReaction* ionBC = new G4BinaryLightIonReaction(thePreCompound); - ionBC->SetMinEnergy(0.0*MeV); - ionBC->SetMaxEnergy(110.0*MeV); - - // Elastic cross section set - ionGGXS = new G4ComponentGGNuclNuclXsc; - G4VCrossSectionDataSet* ionElasticXS = new G4CrossSectionElastic(ionGGXS); - ionElasticXS->SetMinKinEnergy(0.0); - - // Inelastic cross section set - theGGNuclNuclXS = new G4ComponentGGNuclNuclXsc(); - G4VCrossSectionDataSet* nuclNuclXS = - new G4CrossSectionInelastic(theGGNuclNuclXS); - - ////////////////////////////////////////////////////////////////////////////// - // Deuteron // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4Deuteron::Deuteron()->GetProcessManager(); - - // elastic - // no model available - - // inelastic - G4HadronInelasticProcess* deutProcInel = - new G4HadronInelasticProcess("DeuteronInelProcess", G4Deuteron::Deuteron() ); - deutProcInel->RegisterMe(ionBC); - deutProcInel->RegisterMe(qmd); - deutProcInel->RegisterMe(ftfp); - deutProcInel->AddDataSet(nuclNuclXS); - procMan->AddDiscreteProcess(deutProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Triton // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4Triton::Triton()->GetProcessManager(); - - // elastic - // no model available - - // inelastic - G4HadronInelasticProcess* tritProcInel = - new G4HadronInelasticProcess("TritonInelProcess", G4Triton::Triton() ); - tritProcInel->RegisterMe(ionBC); - tritProcInel->RegisterMe(qmd); - tritProcInel->RegisterMe(ftfp); - tritProcInel->AddDataSet(nuclNuclXS); - procMan->AddDiscreteProcess(tritProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // He3 // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4He3::He3()->GetProcessManager(); - - // elastic - // no model available - - // inelastic - G4HadronInelasticProcess* he3ProcInel = - new G4HadronInelasticProcess("He3InelProcess", G4He3::He3() ); - he3ProcInel->RegisterMe(ionBC); - he3ProcInel->RegisterMe(qmd); - he3ProcInel->RegisterMe(ftfp); - he3ProcInel->AddDataSet(nuclNuclXS); - procMan->AddDiscreteProcess(he3ProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Alpha // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4Alpha::Alpha()->GetProcessManager(); - - // elastic - // no model available - - // inelastic - G4HadronInelasticProcess* alphProcInel = - new G4HadronInelasticProcess("AlphaInelProcess", G4Alpha::Alpha() ); - alphProcInel->RegisterMe(ionBC); - alphProcInel->RegisterMe(qmd); - alphProcInel->RegisterMe(ftfp); - alphProcInel->AddDataSet(nuclNuclXS); - procMan->AddDiscreteProcess(alphProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // Generic ion // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4GenericIon::GenericIon()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* ionProcEl = new G4HadronElasticProcess; - ionProcEl->RegisterMe(ionElastic); - ionProcEl->AddDataSet(ionElasticXS); - procMan->AddDiscreteProcess(ionProcEl); - - // inelastic - G4HadronInelasticProcess* genIonProcInel = - new G4HadronInelasticProcess("IonInelProcess", G4GenericIon::GenericIon() ); - genIonProcInel->RegisterMe(ionBC); - genIonProcInel->RegisterMe(qmd); - genIonProcInel->RegisterMe(ftfp); - genIonProcInel->AddDataSet(nuclNuclXS); - procMan->AddDiscreteProcess(genIonProcInel); - -} - -void eASTIonPhysics::TerminateWorker() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.hh deleted file mode 100644 index f712cc695c..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTIonPhysics.hh +++ /dev/null @@ -1,46 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTIonPhysics.hh -// Ion hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTIonPhysics_h -#define eASTIonPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; -class G4VComponentCrossSection; -class G4ComponentGGNuclNuclXsc; - - -class eASTIonPhysics: public G4VPhysicsConstructor -{ - public: - eASTIonPhysics(); - ~eASTIonPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - virtual void TerminateWorker() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - - G4VComponentCrossSection* theGGNuclNuclXS = nullptr; - G4ComponentGGNuclNuclXsc* ionGGXS = nullptr; -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.cc deleted file mode 100644 index 17216cebf4..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.cc +++ /dev/null @@ -1,205 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTKaonPhysics.hh -// Kaon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.02.2021 : migration to Genat4 version 10.7 - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTKaonPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4KaonPlusInelasticProcess.hh" -#include "G4KaonMinusInelasticProcess.hh" -#include "G4KaonZeroLInelasticProcess.hh" -#include "G4KaonZeroSInelasticProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#endif -#include "G4HadronElasticProcess.hh" -#include "G4HadronicAbsorptionBertini.hh" - -#include "G4CascadeInterface.hh" -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4HadronElastic.hh" - -#include "G4ChipsKaonPlusInelasticXS.hh" -#include "G4ChipsKaonMinusInelasticXS.hh" -#include "G4ChipsKaonZeroInelasticXS.hh" -#include "G4CrossSectionElastic.hh" -#include "G4ComponentGGHadronNucleusXsc.hh" -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTKaonPhysics::eASTKaonPhysics() -{} - -eASTKaonPhysics::~eASTKaonPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTKaonPhysics::eASTKaonPhysics() -: G4VPhysicsConstructor("eASTKaon") -{;} - -eASTKaonPhysics::~eASTKaonPhysics() -{;} -#endif - -void eASTKaonPhysics::ConstructParticle() -{} - - -void eASTKaonPhysics::ConstructProcess() -{ - G4ProcessManager* procMan; - - // One elastic model for all kaon energies - G4HadronElastic* elModel = new G4HadronElastic(); - - // Use Bertini cascade for low energies - G4CascadeInterface* loInelModel = new G4CascadeInterface; - loInelModel->SetMinEnergy(0.0); - loInelModel->SetMaxEnergy(12.0*GeV); - - // Use FTFP for high energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(10*GeV); - ftfp->SetMaxEnergy(100*TeV); - - // Inelastic cross section sets - G4VCrossSectionDataSet* kpCS = new G4ChipsKaonPlusInelasticXS; - G4VCrossSectionDataSet* kmCS = new G4ChipsKaonMinusInelasticXS; - G4VCrossSectionDataSet* kzCS = new G4ChipsKaonZeroInelasticXS; - - // Elastic cross section - G4VCrossSectionDataSet* kelCS = - new G4CrossSectionElastic(new G4ComponentGGHadronNucleusXsc); - - ////////////////////////////////////////////////////////////////////////////// - // K+ // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4KaonPlus::KaonPlus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* kpProcEl = new G4HadronElasticProcess; - kpProcEl->RegisterMe(elModel); - kpProcEl->AddDataSet(kelCS); - procMan->AddDiscreteProcess(kpProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4KaonPlusInelasticProcess* kpProcInel = new G4KaonPlusInelasticProcess; -#else - auto* kpProcInel = new G4HadronInelasticProcess("KaonPlusInelasticProcess", - G4KaonPlus::KaonPlus() ); -#endif - kpProcInel->RegisterMe(loInelModel); - kpProcInel->RegisterMe(ftfp); - kpProcInel->AddDataSet(kpCS); - procMan->AddDiscreteProcess(kpProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // K- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4KaonMinus::KaonMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* kmProcEl = new G4HadronElasticProcess; - kmProcEl->RegisterMe(elModel); - kmProcEl->AddDataSet(kelCS); - procMan->AddDiscreteProcess(kmProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4KaonMinusInelasticProcess* kmProcInel = new G4KaonMinusInelasticProcess; -#else - auto* kmProcInel = new G4HadronInelasticProcess("KaonMinusInelasticProcess", - G4KaonMinus::KaonMinus() ); -#endif - kmProcInel->RegisterMe(loInelModel); - kmProcInel->RegisterMe(ftfp); - kmProcInel->AddDataSet(kmCS); - procMan->AddDiscreteProcess(kmProcInel); - - // stopping - G4HadronicAbsorptionBertini* bertAbsorb = new G4HadronicAbsorptionBertini; - procMan->AddRestProcess(bertAbsorb); - - ////////////////////////////////////////////////////////////////////////////// - // K0L // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4KaonZeroLong::KaonZeroLong()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* k0LProcEl = new G4HadronElasticProcess; - k0LProcEl->RegisterMe(elModel); - k0LProcEl->AddDataSet(kelCS); - procMan->AddDiscreteProcess(k0LProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4KaonZeroLInelasticProcess* k0LProcInel = new G4KaonZeroLInelasticProcess; -#else - auto* k0LProcInel = new G4HadronInelasticProcess("Kaon0LongInelasticProcess", - G4KaonZeroLong::KaonZeroLong() ); -#endif - k0LProcInel->RegisterMe(loInelModel); - k0LProcInel->RegisterMe(ftfp); - k0LProcInel->AddDataSet(kzCS); - procMan->AddDiscreteProcess(k0LProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // K0S // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4KaonZeroShort::KaonZeroShort()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* k0SProcEl = new G4HadronElasticProcess; - k0SProcEl->RegisterMe(elModel); - k0SProcEl->AddDataSet(kelCS); - procMan->AddDiscreteProcess(k0SProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4KaonZeroSInelasticProcess* k0SProcInel = new G4KaonZeroSInelasticProcess; -#else - auto* k0SProcInel = new G4HadronInelasticProcess("Kaon0ShortInelasticProcess", - G4KaonZeroShort::KaonZeroShort() ); -#endif - k0SProcInel->RegisterMe(loInelModel); - k0SProcInel->RegisterMe(ftfp); - k0SProcInel->AddDataSet(kzCS); - procMan->AddDiscreteProcess(k0SProcInel); -} - -void eASTKaonPhysics::TerminateWorker() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.hh deleted file mode 100644 index 23e103e547..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTKaonPhysics.hh +++ /dev/null @@ -1,42 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTKaonPhysics.hh -// Kaon hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTKaonPhysics_h -#define eASTKaonPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTKaonPhysics: public G4VPhysicsConstructor -{ - public: - eASTKaonPhysics(); - ~eASTKaonPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - virtual void TerminateWorker() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.cc deleted file mode 100644 index 5d6ec14c96..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.cc +++ /dev/null @@ -1,136 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTNeutronPhysics.cc -// Neutron hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTNeutronPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4NeutronInelasticProcess.hh" -#include "G4HadronCaptureProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#include "G4NeutronCaptureProcess.hh" -#endif -#include "G4HadronElasticProcess.hh" -#include "G4NeutronKiller.hh" - -#include "G4CascadeInterface.hh" -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4ChipsElasticModel.hh" -#include "G4NeutronRadCapture.hh" - -#include "G4BGGNucleonInelasticXS.hh" -#include "G4NeutronElasticXS.hh" -#include "G4NeutronCaptureXS.hh" - -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTNeutronPhysics::eASTNeutronPhysics() -{ -} - -eASTNeutronPhysics::~eASTNeutronPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTNeutronPhysics::eASTNeutronPhysics() -: G4VPhysicsConstructor("eASTNeutron") -{;} - -eASTNeutronPhysics::~eASTNeutronPhysics() -{;} -#endif - -void eASTNeutronPhysics::ConstructParticle() -{} - - -void eASTNeutronPhysics::ConstructProcess() -{ - // Low energy elastic model - G4ChipsElasticModel* elMod = new G4ChipsElasticModel(); - - // Use Bertini cascade for low energies - G4CascadeInterface* loInelModel = new G4CascadeInterface; - loInelModel->SetMinEnergy(0.0); - loInelModel->SetMaxEnergy(12.0*GeV); - - // Capture model - G4NeutronRadCapture* capModel = new G4NeutronRadCapture(); - - // Use FTFP for high energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(5*GeV); - ftfp->SetMaxEnergy(100*TeV); - - // Cross section sets - G4BGGNucleonInelasticXS* inelCS = new G4BGGNucleonInelasticXS(G4Neutron::Neutron() ); - G4NeutronElasticXS* elCS = new G4NeutronElasticXS; - G4NeutronCaptureXS* capCS = new G4NeutronCaptureXS; - - G4ProcessManager* procMan = G4Neutron::Neutron()->GetProcessManager(); - - // Elastic process - G4HadronElasticProcess* nProcEl = new G4HadronElasticProcess; - nProcEl->RegisterMe(elMod); - nProcEl->AddDataSet(elCS); - procMan->AddDiscreteProcess(nProcEl); - - // Inelastic process -#if G4VERSION_NUMBER < 1100 - G4NeutronInelasticProcess* nProcInel = new G4NeutronInelasticProcess; -#else - auto* nProcInel = new G4HadronInelasticProcess("NeutronInelasticProcess", - G4Neutron::Neutron() ); -#endif - nProcInel->RegisterMe(loInelModel); - nProcInel->RegisterMe(ftfp); - nProcInel->AddDataSet(inelCS); - procMan->AddDiscreteProcess(nProcInel); - - // Capture process -#if G4VERSION_NUMBER < 1100 - G4HadronCaptureProcess* nProcCap = new G4HadronCaptureProcess("nCapture"); -#else - auto* nProcCap = new G4NeutronCaptureProcess("nCapture"); -#endif - nProcCap->RegisterMe(capModel); - nProcCap->AddDataSet(capCS); - procMan->AddDiscreteProcess(nProcCap); - - // Neutron cut (kill neutrons that live too long or have too little energy) - G4NeutronKiller* nKiller = new G4NeutronKiller(); - nKiller->SetKinEnergyLimit(0.0*MeV); - nKiller->SetTimeLimit(10.*microsecond); - procMan->AddDiscreteProcess(nKiller); - -} - - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.hh deleted file mode 100644 index 84edc65ac3..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTNeutronPhysics.hh +++ /dev/null @@ -1,41 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTNeutronPhysics.hh -// Neutron hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTNeutronPhysics_h -#define eASTNeutronPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTNeutronPhysics: public G4VPhysicsConstructor -{ - public: - eASTNeutronPhysics(); - ~eASTNeutronPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.cc b/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.cc deleted file mode 100644 index 25cda95f86..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.cc +++ /dev/null @@ -1,254 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTPhysicsList.cc -// Geant4 physics list for Electron Ion Collider detector simulation -// -// History -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.05.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - -#include "eASTPhysicsList.hh" -#include "eASTPhysicsListMessenger.hh" - -#include "G4SystemOfUnits.hh" -#include "G4UnitsTable.hh" -#include "G4ProcessTable.hh" -#include "G4RegionStore.hh" - -#include "G4EmStandardPhysics.hh" -#include "G4EmExtraPhysics.hh" -#include "G4EmParameters.hh" -#include "G4HadronicParameters.hh" -#include "G4DecayPhysics.hh" -#include "G4NuclideTable.hh" - -#include "G4RadioactiveDecayPhysics.hh" -#include "G4OpticalPhysics.hh" -#include "G4StepLimiterPhysics.hh" - -#include "eASTProtonPhysics.hh" -#include "eASTNeutronPhysics.hh" -#include "eASTPionPhysics.hh" -#include "eASTKaonPhysics.hh" -#include "eASTHyperonPhysics.hh" -#include "eASTAntiBaryonPhysics.hh" -#include "eASTIonPhysics.hh" -#include "eASTGammaLeptoNuclearPhysics.hh" - -// particles - -#include "G4BosonConstructor.hh" -#include "G4LeptonConstructor.hh" -#include "G4MesonConstructor.hh" -#include "G4BaryonConstructor.hh" -#include "G4IonConstructor.hh" -#include "G4ShortLivedConstructor.hh" - -#include "G4Version.hh" - -eASTPhysicsList::eASTPhysicsList(G4int verb) - :G4VModularPhysicsList() -{ - SetVerboseLevel(verb); - - //add new units for radioActive decays - // - new G4UnitDefinition( "millielectronVolt", "meV", "Energy", 1.e-3*eV); - // -#if G4VERSION_NUMBER < 1100 - const G4double minute = 60*second; - const G4double hour = 60*minute; - const G4double day = 24*hour; - const G4double year = 365*day; - new G4UnitDefinition("minute", "min", "Time", minute); - new G4UnitDefinition("hour", "h", "Time", hour); - new G4UnitDefinition("day", "d", "Time", day); - new G4UnitDefinition("year", "y", "Time", year); -#endif - - // Mandatory for G4NuclideTable - // Half-life threshold must be set small or many short-lived isomers - // will not be assigned life times (default to 0) - G4NuclideTable::GetInstance()->SetThresholdOfHalfLife(0.1*picosecond); - G4NuclideTable::GetInstance()->SetLevelTolerance(1.0*eV); - - globalCuts[2] = 0.7*mm; //gamma - globalCuts[0] = 0.7*mm; //e- - globalCuts[1] = 0.7*mm; //e+ - globalCuts[3] = 0.7*mm; //proton - - pMessenger = new eASTPhysicsListMessenger(this); -} - - -eASTPhysicsList::~eASTPhysicsList() -{ delete pMessenger; } - -void eASTPhysicsList::ConstructParticle() -{ - if(!processesAreRegistered) SetupProcesses(); - - G4BosonConstructor pBosonConstructor; - pBosonConstructor.ConstructParticle(); - - G4LeptonConstructor pLeptonConstructor; - pLeptonConstructor.ConstructParticle(); - - G4MesonConstructor pMesonConstructor; - pMesonConstructor.ConstructParticle(); - - G4BaryonConstructor pBaryonConstructor; - pBaryonConstructor.ConstructParticle(); - - G4IonConstructor pIonConstructor; - pIonConstructor.ConstructParticle(); - - G4ShortLivedConstructor pShortLivedConstructor; - pShortLivedConstructor.ConstructParticle(); -} - -void eASTPhysicsList::SetupProcesses() -{ - // EM physics - RegisterPhysics(new G4EmStandardPhysics()); - G4EmParameters* param = G4EmParameters::Instance(); - param->SetAugerCascade(true); - param->SetStepFunction(1., 1.*CLHEP::mm); - param->SetStepFunctionMuHad(1., 1.*CLHEP::mm); - - // Decay - RegisterPhysics(new G4DecayPhysics()); - - // Radioactive decay - if(addRDM) - { RegisterPhysics(new G4RadioactiveDecayPhysics()); } - - // Hadronic physics - RegisterPhysics(new eASTProtonPhysics() ); - RegisterPhysics(new eASTNeutronPhysics() ); - RegisterPhysics(new eASTPionPhysics() ); - RegisterPhysics(new eASTKaonPhysics() ); - RegisterPhysics(new eASTHyperonPhysics() ); - RegisterPhysics(new eASTAntiBaryonPhysics() ); - RegisterPhysics(new eASTIonPhysics() ); - RegisterPhysics(new eASTGammaLeptoNuclearPhysics() ); - - // Optical physics - if(addOptical) - { RegisterPhysics(new G4OpticalPhysics() ); } - - // Step limiter - if(stepLimit_opt>=0) - { RegisterPhysics(new G4StepLimiterPhysics()); } - - processesAreRegistered = true; -} - -void eASTPhysicsList::ConstructProcess() -{ - auto verbose = G4ProcessTable::GetProcessTable()->GetVerboseLevel(); - SetVerboseLevel(verbose); - G4EmParameters::Instance()->SetVerbose(verbose); - -#if G4VERSION_NUMBER >= 1100 - G4HadronicParameters::Instance()->SetVerboseLevel(verbose); -#endif - G4VModularPhysicsList::ConstructProcess(); -} - -void eASTPhysicsList::SetCuts() -{ - SetCutValue(globalCuts[2],"gamma"); // gamma should be defined first! - SetCutValue(globalCuts[0],"e-"); - SetCutValue(globalCuts[1],"e+"); - SetCutValue(globalCuts[3],"proton"); -} - -G4Region* eASTPhysicsList::FindRegion(const G4String& reg) const -{ - auto store = G4RegionStore::GetInstance(); - return store->GetRegion(reg); -} - -void eASTPhysicsList::SetGlobalCuts(G4double val) -{ - for(G4int i=0; i<4; i++) - { SetGlobalCut(i,val); } - SetCuts(); -} - -void eASTPhysicsList::SetGlobalCut(G4int i, G4double val) -{ - globalCuts[i] = val; - SetCuts(); -} - -G4Region* eASTPhysicsList::SetLocalCut(const G4String& reg,G4int i,G4double val) -{ - auto regPtr = FindRegion(reg); - if(!regPtr) return regPtr; - - auto cuts = regPtr->GetProductionCuts(); - if(!cuts) - { - cuts = new G4ProductionCuts(); - regPtr->SetProductionCuts(cuts); - } - - cuts->SetProductionCut(val,i); - return regPtr; -} - -G4double eASTPhysicsList::GetLocalCut(const G4String& reg,G4int i) const -{ - auto regPtr = FindRegion(reg); - G4double val = -1.0; - if(regPtr) - { - auto cuts = regPtr->GetProductionCuts(); - if(cuts) val = cuts->GetProductionCut(i); - } - return val; -} - -#include "G4UserLimits.hh" - -G4Region* eASTPhysicsList::SetLocalStepLimit(const G4String& reg,G4double val) -{ - auto regPtr = FindRegion(reg); - if(!regPtr) return regPtr; - - auto uLim = regPtr->GetUserLimits(); - if(!uLim) - { - uLim = new G4UserLimits(val); - regPtr->SetUserLimits(uLim); - } - else - { uLim->SetMaxAllowedStep(val); } - return regPtr; -} - -#include "G4Track.hh" -G4double eASTPhysicsList::GetLocalStepLimit(const G4String& reg) const -{ - static G4Track dummyTrack; - auto regPtr = FindRegion(reg); - G4double val = -1.0; - if(regPtr) - { - auto uLim = regPtr->GetUserLimits(); - if(uLim) val = uLim->GetMaxAllowedStep(dummyTrack); - } - return val; -} - -void eASTPhysicsList::SetGlobalStepLimit(G4double val) -{ SetLocalStepLimit("DefaultRegionForTheWorld",val); } - -G4double eASTPhysicsList::GetGlobalStepLimit() const -{ return GetLocalStepLimit("DefaultRegionForTheWorld"); } - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.hh b/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.hh deleted file mode 100644 index 4b40f9c839..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsList.hh +++ /dev/null @@ -1,87 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTPhysicsList.hh -// Geant4 physics list for Electron Ion Collider detector simulation -// -// History -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTPhysicsList_h -#define eASTPhysicsList_h 1 - -#include "G4VModularPhysicsList.hh" -#include "globals.hh" - -class eASTPhysicsListMessenger; -class G4Region; -class G4ProductionCuts; - -#include - -class eASTPhysicsList: public G4VModularPhysicsList -{ - public: - eASTPhysicsList(G4int verb=0); - ~eASTPhysicsList(); - - virtual void ConstructParticle(); - virtual void ConstructProcess(); - virtual void SetCuts(); - - private: - void SetupProcesses(); - - private: - G4bool processesAreRegistered = false; - eASTPhysicsListMessenger* pMessenger; - - //G4bool addHP = false; // add Neutron_HP - G4bool addRDM = false; // add Radioactive Decay Module - G4bool addOptical = false; // add optical physics - - G4int stepLimit_opt = -1; // step limiter option (0:charged, 1:neutral, 2:all, 3:e+/e-) - std::map localStepLimits; // map of region name and limit value - G4double globalCuts[4]; // for e-, e+ gamma, proton - std::map localCuts; // map of region name and cuts - - public: - // Neutron_HP needs further implementation - //void AddHP(G4bool val = true) { addHP = val; } - //G4bool IfHP() const { return addHP; } - void AddRDM(G4bool val = true) { addRDM = val; } - G4bool IfRDM() const { return addRDM; } - void AddOptical(G4bool val = true) { addOptical = val; } - G4bool IfOptical() const { return addOptical; } - - void AddStepLimit(G4int val = 0) { stepLimit_opt = val; } - G4int IfStepLimit() const { return stepLimit_opt; } - void SetGlobalStepLimit(G4double); - G4double GetGlobalStepLimit() const; - G4Region* SetLocalStepLimit(const G4String&,G4double); - G4double GetLocalStepLimit(const G4String&) const; - void SetGlobalCuts(G4double); - G4double GetGlobalCuts() const { return GetGlobalCut(0); } - void SetGlobalCut(G4int, G4double); - G4double GetGlobalCut(G4int i) const { return globalCuts[i]; } - G4Region* SetLocalCuts(const G4String& reg,G4double val) - { - G4Region* regPtr = nullptr; - for(G4int i=0; i<4; i++) - { - regPtr = SetLocalCut(reg,i,val); - if(!regPtr) return regPtr; - } - return regPtr; - } - G4double GetLocalCuts(const G4String& reg) const { return GetLocalCut(reg,0); } - G4Region* SetLocalCut(const G4String&,G4int,G4double); - G4double GetLocalCut(const G4String&,G4int) const; - - private: - G4Region* FindRegion(const G4String&) const; -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.cc b/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.cc deleted file mode 100644 index 756542fd79..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.cc +++ /dev/null @@ -1,286 +0,0 @@ -// ******************************************************************** -// -// eASTPhysicsListMessenger.cc -// A messenger class that handles physics list options. -// -// History -// September 8th, 2020 : first implementation -// -// ******************************************************************** - -#include "eASTPhysicsListMessenger.hh" - -#include "eASTPhysicsList.hh" -#include "G4UIcommand.hh" -#include "G4UIparameter.hh" -#include "G4UIdirectory.hh" -#include "G4UIcmdWithAString.hh" -#include "G4UIcmdWithADoubleAndUnit.hh" -#include "G4UIcmdWithoutParameter.hh" - -eASTPhysicsListMessenger::eASTPhysicsListMessenger(eASTPhysicsList* pl) -: pPL(pl) -{ - G4UIparameter* param = nullptr; - - physDir = new G4UIdirectory("/eAST/physics/"); - physDir->SetGuidance("eAST physics selection"); - - //addHPCmd = new G4UIcmdWithoutParameter("/eAST/physics/addHP",this); - //addHPCmd->AvailableForStates(G4State_PreInit); - //addHPCmd->SetToBeBroadcasted(false); - //addHPCmd->SetGuidance("Add High-Precision neutron model."); - //addHPCmd->SetGuidance(" Note: Shielding option has already had HP. This command does not make effect to Shielding option."); - - addRDMCmd = new G4UIcmdWithoutParameter("/eAST/physics/addRDM",this); - addRDMCmd->AvailableForStates(G4State_PreInit); - addRDMCmd->SetToBeBroadcasted(false); - addRDMCmd->SetGuidance("Add Radioactive Decay model."); - addRDMCmd->SetGuidance(" Note: Shielding option has already had RDM. This command does not make effect to Shielding option."); - - addOpticalCmd = new G4UIcmdWithoutParameter("/eAST/physics/addOptical",this); - addOpticalCmd->AvailableForStates(G4State_PreInit); - addOpticalCmd->SetToBeBroadcasted(false); - addOpticalCmd->SetGuidance("Add Optical physics"); - - addStepLimitCmd = new G4UIcmdWithAString("/eAST/physics/addStepLimit",this); - addStepLimitCmd->AvailableForStates(G4State_PreInit); - addStepLimitCmd->SetToBeBroadcasted(false); - addStepLimitCmd->SetGuidance("Add step-limiter process to artificially limit step length."); - addStepLimitCmd->SetGuidance("Specify particle types to be applied."); - addStepLimitCmd->SetGuidance(" charged (default) : applied only to the charged particles"); - addStepLimitCmd->SetGuidance(" neutral : applied only to the neutral particles"); - addStepLimitCmd->SetGuidance(" all : applied to all particle types"); - addStepLimitCmd->SetGuidance(" e+/- : applied only to e+/e-"); - addStepLimitCmd->SetGuidance(" Note: In addition to this command, you need to specify the limitation value by"); - addStepLimitCmd->SetGuidance(" /eAST/physics/limit/stepLimit or /eAST/physics/limit/localStepLimt command."); - addStepLimitCmd->SetParameterName("particle",true); - addStepLimitCmd->SetDefaultValue("charged"); - addStepLimitCmd->SetCandidates("charged neutral all e+/-"); - - physLimitDir = new G4UIdirectory("/eAST/physics/limit/"); - physLimitDir->SetGuidance("Specify step limitation"); - - setStepLimitCmd = new G4UIcmdWithADoubleAndUnit("/eAST/physics/limit/stepLimit",this); - setStepLimitCmd->AvailableForStates(G4State_Idle); - setStepLimitCmd->SetToBeBroadcasted(false); - setStepLimitCmd->SetParameterName("length",false); - setStepLimitCmd->SetDefaultUnit("mm"); - setStepLimitCmd->SetGuidance("Define the limitation of the step length"); - setStepLimitCmd->SetGuidance("This limitation is applied to the entire geometry except regions that has its dedicated limit."); - - setRegionStepLimitCmd = new G4UIcommand("/eAST/physics/limit/regionStepLimit",this); - setRegionStepLimitCmd->AvailableForStates(G4State_Idle); - setRegionStepLimitCmd->SetToBeBroadcasted(false); - setRegionStepLimitCmd->SetGuidance("Define the limitation of the step length for the specified region"); - setRegionStepLimitCmd->SetGuidance(" [usage] /eAST/physics/limit/regionStepLimit region length [unit]"); - setRegionStepLimitCmd->SetGuidance(" region (string) : region name"); - setRegionStepLimitCmd->SetGuidance(" Note: Region has to be defined in advance to this command."); - setRegionStepLimitCmd->SetGuidance(" If new region is necessary, use /eAST/geometry/createRegion to create it."); - param = new G4UIparameter("region",'s',false); - setRegionStepLimitCmd->SetParameter(param); - param = new G4UIparameter("length",'d',false); - setRegionStepLimitCmd->SetParameter(param); - param = new G4UIparameter("unit",'s',true); - param->SetDefaultUnit("mm"); - setRegionStepLimitCmd->SetParameter(param); - - physCutDir = new G4UIdirectory("/eAST/physics/cuts/"); - physCutDir->SetGuidance("Specify production thresholds (a.k.a. cuts)"); - - setCutCmd = new G4UIcmdWithADoubleAndUnit("/eAST/physics/cuts/setCuts",this); - setCutCmd->AvailableForStates(G4State_PreInit, G4State_Idle); - setCutCmd->SetToBeBroadcasted(false); - setCutCmd->SetParameterName("length",false); - setCutCmd->SetDefaultUnit("mm"); - setCutCmd->SetGuidance("Specify production thresholds (a.k.a. cuts) that is applied to the entire geometry"); - setCutCmd->SetGuidance("This threshold is applied to all of e-, e+, gamma and proton."); - setCutCmd->SetGuidance("Threshold of each particle can be overwitted by /eAST/physics/cuts/setParticleCut command"); - - setCutParticleCmd = new G4UIcommand("/eAST/physics/cuts/setParticleCut",this); - setCutParticleCmd->AvailableForStates(G4State_PreInit, G4State_Idle); - setCutParticleCmd->SetToBeBroadcasted(false); - setCutParticleCmd->SetGuidance("Specify production threshold (a.k.a. cut) for the specified particle that is applied to the entire geometry"); - setCutParticleCmd->SetGuidance(" [usage] /eAST/physics/setParticleCut particle cut unit"); - param = new G4UIparameter("particle",'s',false); - param->SetParameterCandidates("e- e+ gamma proton"); - setCutParticleCmd->SetParameter(param); - param = new G4UIparameter("cut",'d',false); - setCutParticleCmd->SetParameter(param); - param = new G4UIparameter("unit",'s',true); - param->SetDefaultUnit("mm"); - setCutParticleCmd->SetParameter(param); - - setCutRegionCmd = new G4UIcommand("/eAST/physics/cuts/setRegionCut",this); - setCutRegionCmd->AvailableForStates(G4State_Idle); - setCutRegionCmd->SetToBeBroadcasted(false); - setCutRegionCmd->SetGuidance("Specify production threshold (a.k.a. cut) that is applied to the specified region"); - setCutRegionCmd->SetGuidance(" [usage] /eAST/physics/setRegionCut region cut unit"); - setCutRegionCmd->SetGuidance("This threshold is applied to all of e-, e+, gamma and proton."); - setCutRegionCmd->SetGuidance("Threshold of each particle can be overwitted by /eAST/physics/cuts/setRegionParticleCut command"); - setCutRegionCmd->SetGuidance(" Note: Region has to be defined in advance to this command."); - setCutRegionCmd->SetGuidance(" If new region is necessary, use /eAST/geometry/createRegion to create it."); - param = new G4UIparameter("region",'s',false); - setCutRegionCmd->SetParameter(param); - param = new G4UIparameter("cut",'d',false); - setCutRegionCmd->SetParameter(param); - param = new G4UIparameter("unit",'s',true); - param->SetDefaultUnit("mm"); - setCutRegionCmd->SetParameter(param); - - setCutRegionParticleCmd = new G4UIcommand("/eAST/physics/cuts/setRegionParticleCut",this); - setCutRegionParticleCmd->AvailableForStates(G4State_Idle); - setCutRegionParticleCmd->SetToBeBroadcasted(false); - setCutRegionParticleCmd->SetGuidance("Specify production threshold (a.k.a. cut) that is applied to the specified region"); - setCutRegionParticleCmd->SetGuidance(" [usage] /eAST/physics/setRegionParticleCut region particle cut unit"); - setCutRegionParticleCmd->SetGuidance(" Note: Region has to be defined in advance to this command."); - setCutRegionParticleCmd->SetGuidance(" If new region is necessary, use /eAST/geometry/createRegion to create it."); - param = new G4UIparameter("region",'s',false); - setCutRegionParticleCmd->SetParameter(param); - param = new G4UIparameter("particle",'s',false); - param->SetParameterCandidates("e- e+ gamma proton"); - setCutRegionParticleCmd->SetParameter(param); - param = new G4UIparameter("cut",'d',false); - setCutRegionParticleCmd->SetParameter(param); - param = new G4UIparameter("unit",'s',true); - param->SetDefaultUnit("mm"); - setCutRegionParticleCmd->SetParameter(param); - -} - -eASTPhysicsListMessenger::~eASTPhysicsListMessenger() -{ - //delete addHPCmd; - delete addRDMCmd; - delete addOpticalCmd; - delete addStepLimitCmd; - delete setStepLimitCmd; - delete setRegionStepLimitCmd; - delete setCutCmd; - delete setCutParticleCmd; - delete setCutRegionCmd; - delete setCutRegionParticleCmd; - - delete physLimitDir; - delete physCutDir; - delete physDir; -} - -#include "G4Tokenizer.hh" - -void eASTPhysicsListMessenger::SetNewValue(G4UIcommand* cmd, G4String val) -{ - //if(cmd==addHPCmd) - //{ pPL->AddHP(); } - //else - if(cmd==addRDMCmd) - { pPL->AddRDM(); } - else if(cmd==addOpticalCmd) - { pPL->AddOptical(); } - else if(cmd==addStepLimitCmd) - { - G4int opt = 0; - if(val=="neutral") opt = 1; - else if(val=="all") opt = 2; - else if(val=="e+/-") opt = 3; - pPL->AddStepLimit(opt); - } - else if(cmd==setStepLimitCmd) - { pPL->SetGlobalStepLimit(setStepLimitCmd->GetNewDoubleValue(val)); } - else if(cmd==setRegionStepLimitCmd) - { - G4Tokenizer next(val); - G4String reg = next(); - G4String newVal = next(); - newVal += " "; - newVal += next(); - auto regPtr = pPL->SetLocalStepLimit(reg,setRegionStepLimitCmd->ConvertToDimensionedDouble(newVal)); - if(!regPtr) - { - G4ExceptionDescription ed; - ed << "Region <" << reg << "> is not defined."; - setRegionStepLimitCmd->CommandFailed(ed); - } - } - else if(cmd==setCutCmd) - { pPL->SetGlobalCuts(setCutCmd->GetNewDoubleValue(val)); } - else if(cmd==setCutParticleCmd) - { - G4Tokenizer next(val); - G4String pat = next(); - G4String newVal = next(); - newVal += " "; - newVal += next(); - G4int i = 0; - if(pat=="e-") i = 0; - else if(pat=="e+") i = 1; - else if(pat=="gamma") i = 2; - else if(pat=="proton") i = 3; - pPL->SetGlobalCut(i,setCutParticleCmd->ConvertToDimensionedDouble(newVal)); - } - else if(cmd==setCutRegionCmd) - { - G4Tokenizer next(val); - G4String reg = next(); - G4String newVal = next(); - newVal += " "; - newVal += next(); - auto regPtr = pPL->SetLocalCuts(reg,setCutRegionCmd->ConvertToDimensionedDouble(newVal)); - if(!regPtr) - { - G4ExceptionDescription ed; - ed << "Region <" << reg << "> is not defined."; - setRegionStepLimitCmd->CommandFailed(ed); - } - } - else if(cmd==setCutRegionParticleCmd) - { - G4Tokenizer next(val); - G4String reg = next(); - G4String pat = next(); - G4int i = 0; - if(pat=="e-") i = 0; - else if(pat=="e+") i = 1; - else if(pat=="gamma") i = 2; - else if(pat=="proton") i = 3; - G4String newVal = next(); - newVal += " "; - newVal += next(); - auto regPtr = pPL->SetLocalCut(reg,i,setCutRegionParticleCmd->ConvertToDimensionedDouble(newVal)); - if(!regPtr) - { - G4ExceptionDescription ed; - ed << "Region <" << reg << "> is not defined."; - setRegionStepLimitCmd->CommandFailed(ed); - } - } - -} - -G4String eASTPhysicsListMessenger::GetCurrentValue(G4UIcommand* cmd) -{ - G4String val(""); - - //if(cmd==addHPCmd) - //{ val = cmd->ConvertToString(pPL->IfHP()); } - //else - if(cmd==addRDMCmd) - { val = cmd->ConvertToString(pPL->IfRDM()); } - else if(cmd==addOpticalCmd) - { val = cmd->ConvertToString(pPL->IfOptical()); } - else if(cmd==addStepLimitCmd) - { - auto opt = pPL->IfStepLimit(); - switch(opt) - { - case 0: val = "charged"; break; - case 1: val = "neutral"; break; - case 2: val = "all"; break; - case 3: val = "e+/-"; break; - default : val = "undefined"; break; - } - } - return val; -} - - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.hh b/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.hh deleted file mode 100644 index 6bf16e71ae..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPhysicsListMessenger.hh +++ /dev/null @@ -1,53 +0,0 @@ -// ******************************************************************** -// -// eASTPhysicsListMessenger.hh -// Header file of a messenger class that handles physics options. -// -// History -// May 8th, 2021 : first implementation -// -// ******************************************************************** - -#ifndef eASTPhysicsListMessenger_H -#define eASTPhysicsListMessenger_H 1 - -#include "G4UImessenger.hh" -#include "globals.hh" - -class eASTPhysicsList; -class G4UIcommand; -class G4UIdirectory; -class G4UIcmdWithAString; -class G4UIcmdWithADoubleAndUnit; -class G4UIcmdWithoutParameter; - -class eASTPhysicsListMessenger: public G4UImessenger -{ - public: - eASTPhysicsListMessenger(eASTPhysicsList*); - virtual ~eASTPhysicsListMessenger(); - virtual void SetNewValue(G4UIcommand*,G4String); - virtual G4String GetCurrentValue(G4UIcommand*); - - private: - eASTPhysicsList* pPL; - G4UIdirectory* physDir; - //G4UIcmdWithoutParameter* addHPCmd; - G4UIcmdWithoutParameter* addRDMCmd; - G4UIcmdWithoutParameter* addOpticalCmd; - G4UIcmdWithAString* addStepLimitCmd; - - G4UIdirectory* physLimitDir; - G4UIcmdWithADoubleAndUnit* setStepLimitCmd; - G4UIcommand* setRegionStepLimitCmd; - - G4UIdirectory* physCutDir; - G4UIcmdWithADoubleAndUnit* setCutCmd; - G4UIcommand* setCutParticleCmd; - G4UIcommand* setCutRegionCmd; - G4UIcommand* setCutRegionParticleCmd; - -}; - -#endif - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.cc deleted file mode 100644 index 6cab5086da..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.cc +++ /dev/null @@ -1,151 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTPionPhysics.hh -// Pion hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.02.2021 : migration to Geant4 version 10.7 - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTPionPhysics.hh" -#include "G4MesonConstructor.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4PionPlusInelasticProcess.hh" -#include "G4PionMinusInelasticProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#endif -#include "G4HadronElasticProcess.hh" -#include "G4HadronicAbsorptionBertini.hh" - -#include "G4CascadeInterface.hh" -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4HadronElastic.hh" -#include "G4ElasticHadrNucleusHE.hh" - -#include "G4BGGPionElasticXS.hh" -#include "G4BGGPionInelasticXS.hh" - -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTPionPhysics::eASTPionPhysics() -{} - -eASTPionPhysics::~eASTPionPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTPionPhysics::eASTPionPhysics() -: G4VPhysicsConstructor("eASTPion") -{;} - -eASTPionPhysics::~eASTPionPhysics() -{;} -#endif - -void eASTPionPhysics::ConstructParticle() -{} - - -void eASTPionPhysics::ConstructProcess() -{ - G4ProcessManager* procMan; - - // Low energy elastic model - G4HadronElastic* loElModel = new G4HadronElastic(); - loElModel->SetMaxEnergy(1.0001*GeV); - - // High energy elastic model - G4ElasticHadrNucleusHE* hiElModel = new G4ElasticHadrNucleusHE(); - hiElModel->SetMinEnergy(1.0*GeV); - - // Use Bertini cascade for low energies - G4CascadeInterface* loInelModel = new G4CascadeInterface; - loInelModel->SetMinEnergy(0.0); - loInelModel->SetMaxEnergy(12.0*GeV); - - // Use FTFP for high energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(10*GeV); - ftfp->SetMaxEnergy(100*TeV); - - ////////////////////////////////////////////////////////////////////////////// - // pi+ // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4PionPlus::PionPlus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* pipProcEl = new G4HadronElasticProcess; - pipProcEl->RegisterMe(loElModel); - pipProcEl->RegisterMe(hiElModel); - pipProcEl->AddDataSet(new G4BGGPionElasticXS(G4PionPlus::PionPlus() ) ); - procMan->AddDiscreteProcess(pipProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4PionPlusInelasticProcess* pipProcInel = new G4PionPlusInelasticProcess; -#else - auto* pipProcInel = new G4HadronInelasticProcess("PionPlusInelasticProcess", - G4PionPlus::PionPlus() ); -#endif - pipProcInel->RegisterMe(loInelModel); - pipProcInel->RegisterMe(ftfp); - pipProcInel->AddDataSet(new G4BGGPionInelasticXS(G4PionPlus::PionPlus() ) ); - procMan->AddDiscreteProcess(pipProcInel); - - ////////////////////////////////////////////////////////////////////////////// - // pi- // - ////////////////////////////////////////////////////////////////////////////// - - procMan = G4PionMinus::PionMinus()->GetProcessManager(); - - // elastic - G4HadronElasticProcess* pimProcEl = new G4HadronElasticProcess; - pimProcEl->RegisterMe(loElModel); - pimProcEl->RegisterMe(hiElModel); - pimProcEl->AddDataSet(new G4BGGPionElasticXS(G4PionMinus::PionMinus() ) ); - procMan->AddDiscreteProcess(pimProcEl); - - // inelastic -#if G4VERSION_NUMBER < 1100 - G4PionMinusInelasticProcess* pimProcInel = new G4PionMinusInelasticProcess; -#else - auto* pimProcInel = new G4HadronInelasticProcess("PionMinusInelasticProcess", - G4PionMinus::PionMinus() ); -#endif - pimProcInel->RegisterMe(loInelModel); - pimProcInel->RegisterMe(ftfp); - pimProcInel->AddDataSet(new G4BGGPionInelasticXS(G4PionMinus::PionMinus() ) ); - procMan->AddDiscreteProcess(pimProcInel); - - // stopping - G4HadronicAbsorptionBertini* bertAbsorb = new G4HadronicAbsorptionBertini; - procMan->AddRestProcess(bertAbsorb); - -} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.hh deleted file mode 100644 index 3fa3b77533..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTPionPhysics.hh +++ /dev/null @@ -1,41 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTPionPhysics.hh -// Pion hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTPionPhysics_h -#define eASTPionPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTPionPhysics: public G4VPhysicsConstructor -{ - public: - eASTPionPhysics(); - ~eASTPionPhysics(); - - virtual void ConstructParticle() override; - virtual void ConstructProcess() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif diff --git a/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.cc b/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.cc deleted file mode 100644 index d17755cd38..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.cc +++ /dev/null @@ -1,109 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTProtonPhysics.cc -// Proton hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// Dec.22.2021 : migration to Geant4 version 11.0 - Makoto Asai (JLab) -// -//////////////////////////////////////////////////////////////////////////////// - - -#include "eASTProtonPhysics.hh" - -#include "G4ProcessManager.hh" -#include "G4Version.hh" -#if G4VERSION_NUMBER < 1100 -#include "G4ProtonInelasticProcess.hh" -#else -#include "G4HadronInelasticProcess.hh" -#endif -#include "G4HadronElasticProcess.hh" - -#include "G4CascadeInterface.hh" -#include "G4TheoFSGenerator.hh" -#include "G4FTFModel.hh" -#include "G4ExcitedStringDecay.hh" -#include "G4LundStringFragmentation.hh" -#include "G4GeneratorPrecompoundInterface.hh" -#include "G4ChipsElasticModel.hh" - -#include "G4BGGNucleonInelasticXS.hh" -#include "G4ChipsProtonElasticXS.hh" - -#include "G4SystemOfUnits.hh" - -#if G4VERSION_NUMBER < 1100 -eASTProtonPhysics::eASTProtonPhysics() -{} - -eASTProtonPhysics::~eASTProtonPhysics() -{ - delete stringDecay; - delete stringModel; - delete fragModel; - delete preCompoundModel; -} -#else -eASTProtonPhysics::eASTProtonPhysics() -: G4VPhysicsConstructor("eASTProton") -{;} - -eASTProtonPhysics::~eASTProtonPhysics() -{;} -#endif - -void eASTProtonPhysics::ConstructProcess() -{ - // Low energy elastic model - G4ChipsElasticModel* elMod = new G4ChipsElasticModel(); - - // Use Bertini cascade for low energies - G4CascadeInterface* loInelModel = new G4CascadeInterface; - loInelModel->SetMinEnergy(0.0); - loInelModel->SetMaxEnergy(12.0*GeV); - - // Use FTFP for high energies ==>> eventually replace this with new class FTFPInterface - ftfp = new G4TheoFSGenerator("FTFP"); - stringModel = new G4FTFModel; - stringDecay = - new G4ExcitedStringDecay(fragModel = new G4LundStringFragmentation); - stringModel->SetFragmentationModel(stringDecay); - preCompoundModel = new G4GeneratorPrecompoundInterface(); - - ftfp->SetHighEnergyGenerator(stringModel); - ftfp->SetTransport(preCompoundModel); - ftfp->SetMinEnergy(5*GeV); - ftfp->SetMaxEnergy(100*TeV); - - // Inelastic cross section - G4BGGNucleonInelasticXS* inelCS = new G4BGGNucleonInelasticXS(G4Proton::Proton() ); - G4ChipsProtonElasticXS* elCS = new G4ChipsProtonElasticXS; - - G4ProcessManager* procMan = G4Proton::Proton()->GetProcessManager(); - - // Elastic process - G4HadronElasticProcess* pProcEl = new G4HadronElasticProcess; - pProcEl->RegisterMe(elMod); - pProcEl->AddDataSet(elCS); - procMan->AddDiscreteProcess(pProcEl); - - // Inelastic process -#if G4VERSION_NUMBER < 1100 - G4ProtonInelasticProcess* pProcInel = new G4ProtonInelasticProcess; -#else - auto* pProcInel = new G4HadronInelasticProcess("ProtonInelasticProcess", - G4Proton::Proton() ); -#endif - pProcInel->RegisterMe(loInelModel); - pProcInel->RegisterMe(ftfp); - pProcInel->AddDataSet(inelCS); - procMan->AddDiscreteProcess(pProcInel); - -} - - -void eASTProtonPhysics::ConstructParticle() -{} - diff --git a/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.hh b/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.hh deleted file mode 100644 index 5057fb6a39..0000000000 --- a/simulation/g4simulation/eASTPhysicsList/eASTProtonPhysics.hh +++ /dev/null @@ -1,41 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// eASTProtonPhysics.hh -// Proton hadronic physics constructor for eASTPhysicsList -// -// Jun.21.2018 : original implementation - Dennis H. Wright (SLAC) -// May.06.2021 : migration to eAST - Makoto Asai (SLAC) -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef eASTProtonPhysics_h -#define eASTProtonPhysics_h 1 - -#include "G4VPhysicsConstructor.hh" - -class G4TheoFSGenerator; -class G4FTFModel; -class G4ExcitedStringDecay; -class G4LundStringFragmentation; -class G4GeneratorPrecompoundInterface; - - -class eASTProtonPhysics: public G4VPhysicsConstructor -{ - public: - eASTProtonPhysics(); - ~eASTProtonPhysics(); - - virtual void ConstructProcess() override; - virtual void ConstructParticle() override; - - private: - G4TheoFSGenerator* ftfp = nullptr; - G4FTFModel* stringModel = nullptr; - G4ExcitedStringDecay* stringDecay = nullptr; - G4LundStringFragmentation* fragModel = nullptr; - G4GeneratorPrecompoundInterface* preCompoundModel = nullptr; - -}; - -#endif From 3425fb78afc9c6f175f8b4aee7e6912f38ebc4fa Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sun, 21 May 2023 18:49:29 -0400 Subject: [PATCH 422/468] TPC raw data dump for online debug --- offline/packages/tpc/Makefile.am | 2 + offline/packages/tpc/TpcRawDataTree.cc | 142 +++++++++++++++++++++++++ offline/packages/tpc/TpcRawDataTree.h | 73 +++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 offline/packages/tpc/TpcRawDataTree.cc create mode 100644 offline/packages/tpc/TpcRawDataTree.h diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index 8dcc7a04b3..f575bea662 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -19,6 +19,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 pkginclude_HEADERS = \ + TpcRawDataTree.h \ TpcClusterCleaner.h \ TpcClusterizer.h \ TpcClusterMover.h \ @@ -33,6 +34,7 @@ pcmdir = $(libdir) # sources for tpc library libtpc_la_SOURCES = \ + TpcRawDataTree.cc \ TpcClusterCleaner.cc \ TpcClusterizer.cc \ TpcLoadDistortionCorrection.cc \ diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc new file mode 100644 index 0000000000..e412875136 --- /dev/null +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -0,0 +1,142 @@ + +#include "TpcRawDataTree.h" + +#include +#include +#include // for PHIODataNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +//____________________________________________________________________________.. +TpcRawDataTree::TpcRawDataTree(const std::string &name) + : SubsysReco("TpcRawDataTree") + , m_fname(name) +{ + // reserve memory for max ADC samples + m_adcSamples.resize(1024, 0); +} + +//____________________________________________________________________________.. +int TpcRawDataTree::InitRun(PHCompositeNode *) +{ + m_file = TFile::Open(m_fname.c_str(), "recreate"); + assert(m_file->IsOpen()); + + m_PacketTree = new TTree("PacketTree", "Each entry is one packet"); + + m_PacketTree->Branch("packet", &m_packet, "packet/I"); + m_PacketTree->Branch("frame", &m_frame, "frame/I"); + m_PacketTree->Branch("nWaveormInFrame", &m_nWaveormInFrame, "nWaveormInFrame/I"); + m_PacketTree->Branch("maxFEECount", &m_maxFEECount, "maxFEECount/I"); + + m_SampleTree = new TTree("SampleTree", "Each entry is one waveform"); + + m_SampleTree->Branch("packet", &m_packet, "packet/I"); + m_SampleTree->Branch("frame", &m_frame, "frame/I"); + m_SampleTree->Branch("nWaveormInFrame", &m_nWaveormInFrame, "nWaveormInFrame/I"); + m_SampleTree->Branch("maxFEECount", &m_maxFEECount, "maxFEECount/I"); + + m_SampleTree->Branch("nSamples", &m_nSamples, "nSamples/I"); + m_SampleTree->Branch("adcSamples", &m_adcSamples[0], "adcSamples[nSamples]/s"); + m_SampleTree->Branch("fee", &m_fee, "fee/I"); + m_SampleTree->Branch("sampaAddress", &m_sampaAddress, "sampaAddress/I"); + m_SampleTree->Branch("sampaChannel", &m_sampaChannel, "sampaChannel/I"); + m_SampleTree->Branch("Channel", &m_Channel, "Channel/I"); + m_SampleTree->Branch("BCO", &m_BCO, "BCO/I"); + m_SampleTree->Branch("checksum", &m_checksum, "checksum/I"); + m_SampleTree->Branch("checksumError", &m_checksumError, "checksumError/I"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TpcRawDataTree::process_event(PHCompositeNode *topNode) +{ + Event *_event = findNode::getClass(topNode, "PRDF"); + if (_event == nullptr) + { + std::cout << "TpcRawDataTree::Process_Event - Event not found" << std::endl; + return -1; + } + if (_event->getEvtType() >= 8) /// special events + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + + m_frame = _event->getEvtSequence(); + + for (int packet : m_packets) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : decoding packet " << packet << std::endl; + } + + m_packet = packet; + + std::unique_ptr p (_event->getPacket(m_packet)); + if (!p) + { + if (Verbosity()) + { + std::cout << __PRETTY_FUNCTION__ << " : missing packet " << packet << std::endl; + } + + continue; + } + + m_nWaveormInFrame = p->iValue(0, "NR_WF"); + m_maxFEECount = p->iValue(0, "MAX_FEECOUNT"); + + for (int wf = 0; wf < m_nWaveormInFrame; wf++) + { + m_BCO = p->iValue(wf, "BCO"); + m_nSamples = p->iValue(wf, "SAMPLES"); + m_fee = p->iValue(wf, "FEE"); + + m_sampaAddress = p->iValue(wf, "SAMPAADDRESS"); + m_sampaChannel = p->iValue(wf, "SAMPACHANNEL"); + m_Channel = p->iValue(wf, "CHANNEL"); + m_checksum = p->iValue(wf, "CHECKSUM"); + m_checksumError = p->iValue(wf, "CHECKSUMERROR"); + + assert(m_nSamples < (int) m_adcSamples.size()); // no need for movements in memory allocation + for (int s = 0; s < m_nSamples; s++) + { + m_adcSamples[s] = p->iValue(wf, s); + } + + m_SampleTree->Fill(); + } + + m_PacketTree->Fill(); + } // for (int packet : m_packets) + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TpcRawDataTree::End(PHCompositeNode * /*topNode*/) +{ + m_file->Write(); + + std::cout << __PRETTY_FUNCTION__ << " : completed saving to " << m_file->GetName() << std::endl; + m_file->ls(); + + m_file->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/tpc/TpcRawDataTree.h b/offline/packages/tpc/TpcRawDataTree.h new file mode 100644 index 0000000000..735fd59e47 --- /dev/null +++ b/offline/packages/tpc/TpcRawDataTree.h @@ -0,0 +1,73 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TpcRawDataTree_H +#define TpcRawDataTree_H + +#include + +#include +#include + +class PHCompositeNode; +class TFile; +class TTree; + +//! Dump TPC raw data in PRDF format to a TTree for online debugging and seeding formal Fun4All reco/calib modules +class TpcRawDataTree : public SubsysReco +{ + public: + explicit TpcRawDataTree(const std::string &fname = "TpcRawDataTree.root"); + + ~TpcRawDataTree() override {} + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. A place + to book histograms which have to know the run number. + */ + int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void AddPacket(int packet) + { + m_packets.push_back(packet); + } + void RemoveAllPackets() + { + m_packets.clear(); + } + + protected: + //! which packet to decode + std::vector m_packets; + + private: + + std::string m_fname; + TFile * m_file = nullptr; + TTree * m_SampleTree = nullptr; + TTree * m_PacketTree = nullptr; + + int m_packet = 0; + int m_frame = 0; + int m_nWaveormInFrame = 0; + int m_maxFEECount = 0; + int m_nSamples = 0; + int m_fee = 0; + int m_sampaAddress = 0; + int m_sampaChannel = 0; + int m_Channel = 0; + int m_BCO = 0; + int m_checksum = 0; + int m_checksumError = 0; + std::vector m_adcSamples; +}; + +#endif // TpcRawDataTree_H From 990ed6d760b8e35aab288e93da9ce37709321750 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 21 May 2023 20:51:51 -0400 Subject: [PATCH 423/468] last ones --- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- offline/packages/tpccalib/TpcSpaceChargeReconstruction.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 118b7d4337..33b9d4dc04 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -329,7 +329,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) double clusZErr = 0; if( m_cluster_version == 4 ) { - const auto errors_square = m_cluster_error_parametrization.get_cluster_error( track->get_tpc_seed(), cluster, clusR, cluskey ); + const auto errors_square = m_cluster_error_parametrization.get_cluster_error( cluster, clusR, cluskey, track->get_tpc_seed()->get_qOverR(), track->get_tpc_seed()->get_slope() ); clusRPhiErr = std::sqrt( errors_square.first ); clusZErr = std::sqrt( errors_square.second ); } else { diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstruction.cc b/offline/packages/tpccalib/TpcSpaceChargeReconstruction.cc index 8cabb6afd8..b5821c32b2 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstruction.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstruction.cc @@ -448,7 +448,7 @@ void TpcSpaceChargeReconstruction::process_track( SvtxTrack* track ) double cluster_z_error = 0; if( m_cluster_version >= 4 ) { - const auto errors_square = m_cluster_error_parametrization.get_cluster_error( track->get_tpc_seed(), cluster, cluster_r, cluster_key ); + const auto errors_square = m_cluster_error_parametrization.get_cluster_error(cluster, cluster_r, cluster_key, track->get_tpc_seed()->get_qOverR(), track->get_tpc_seed()->get_slope() ); cluster_rphi_error = std::sqrt( errors_square.first ); cluster_z_error = std::sqrt( errors_square.second ); } else { From 95461209e9fe68b7b3325d5b85360f6b20f20c57 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 22 May 2023 00:32:27 -0400 Subject: [PATCH 424/468] add default list of packets --- offline/packages/tpc/TpcRawDataTree.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index e412875136..d84fd6a1b6 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -16,9 +16,9 @@ #include #include -#include #include #include +#include //____________________________________________________________________________.. TpcRawDataTree::TpcRawDataTree(const std::string &name) @@ -27,6 +27,13 @@ TpcRawDataTree::TpcRawDataTree(const std::string &name) { // reserve memory for max ADC samples m_adcSamples.resize(1024, 0); + + // add all possible TPC packet that we need to analyze + // if a subset is needed, call RemoveAllPackets() + for (int packet = 4001; packet <= 4231; packet += 10) + { + m_packets.push_back(packet); + } } //____________________________________________________________________________.. @@ -68,7 +75,7 @@ int TpcRawDataTree::process_event(PHCompositeNode *topNode) Event *_event = findNode::getClass(topNode, "PRDF"); if (_event == nullptr) { - std::cout << "TpcRawDataTree::Process_Event - Event not found" << std::endl; + std::cout << "TpcRawDataTree::Process_Event Event not found" << std::endl; return -1; } if (_event->getEvtType() >= 8) /// special events @@ -87,7 +94,7 @@ int TpcRawDataTree::process_event(PHCompositeNode *topNode) m_packet = packet; - std::unique_ptr p (_event->getPacket(m_packet)); + std::unique_ptr p(_event->getPacket(m_packet)); if (!p) { if (Verbosity()) From 5363d6d073c9cfb1b56f36914b95342fe52d08c5 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Mon, 22 May 2023 04:42:28 -0400 Subject: [PATCH 425/468] add MBD to TowerBuilder --- .../packages/CaloBase/TowerInfoContainer.h | 3 + .../packages/CaloBase/TowerInfoContainerv1.cc | 24 + .../packages/CaloBase/TowerInfoContainerv1.h | 2 + offline/packages/CaloBase/TowerInfoDefs.cc | 845 +++++++++--------- offline/packages/CaloBase/TowerInfoDefs.h | 7 + offline/packages/CaloReco/CaloTowerBuilder.cc | 139 +-- offline/packages/CaloReco/CaloTowerBuilder.h | 3 +- 7 files changed, 541 insertions(+), 482 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index bf6b87f78c..d5ae275e5e 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -20,6 +20,7 @@ class TowerInfoContainer : public PHObject EMCAL = 0, HCAL = 1, SEPD = 2, + MBD = 3, DETECTOR_INVALID = 9999 }; @@ -37,10 +38,12 @@ class TowerInfoContainer : public PHObject virtual unsigned int encode_epd(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int encode_hcal(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int encode_emcal(unsigned int /*towerIndex*/) { return UINT_MAX; } + virtual unsigned int encode_mbd(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int decode_epd(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int decode_hcal(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int decode_emcal(unsigned int /*towerIndex*/) { return UINT_MAX; } + virtual unsigned int decode_mbd(unsigned int /*towerIndex*/) { return UINT_MAX; } virtual unsigned int getTowerPhiBin(unsigned int /*towerIndex*/) { return UINT_MAX; } diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index ee67a4fd01..655aac66b1 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -26,6 +26,10 @@ TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) { nchannels = 1536; } + else if (_detector == DETECTOR::MBD) + { + nchannels = 256; + } _clones = new TClonesArray("TowerInfov1", nchannels); _clones->SetOwner(); _clones->SetName("TowerInfoContainerv1"); @@ -98,6 +102,12 @@ unsigned int TowerInfoContainerv1::encode_hcal(unsigned int towerIndex) return key; } +unsigned int TowerInfoContainerv1::encode_mbd(unsigned int towerIndex) +{ + unsigned int key = TowerInfoDefs::encode_mbd(towerIndex); + return key; +} + unsigned int TowerInfoContainerv1::encode_key(unsigned int towerIndex) { int key = 0; @@ -113,6 +123,10 @@ unsigned int TowerInfoContainerv1::encode_key(unsigned int towerIndex) { key = TowerInfoContainerv1::encode_epd(towerIndex); } + else if (_detector == DETECTOR::MBD) + { + key = TowerInfoContainerv1::encode_mbd(towerIndex); + } return key; } @@ -135,6 +149,12 @@ unsigned int TowerInfoContainerv1::decode_hcal(unsigned int tower_key) return index; } +unsigned int TowerInfoContainerv1::decode_mbd(unsigned int tower_key) +{ + unsigned int index = TowerInfoDefs::decode_mbd(tower_key); + return index; +} + unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) { int index = 0; @@ -151,6 +171,10 @@ unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) { index = TowerInfoContainerv1::decode_epd(tower_key); } + else if (_detector == DETECTOR::MBD) + { + index = TowerInfoContainerv1::decode_mbd(tower_key); + } return index; } diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.h b/offline/packages/CaloBase/TowerInfoContainerv1.h index 3d9fe88b11..44d8e53123 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerv1.h @@ -29,10 +29,12 @@ class TowerInfoContainerv1 : public TowerInfoContainer unsigned int encode_epd(unsigned int towerIndex) override; unsigned int encode_hcal(unsigned int towerIndex) override; unsigned int encode_emcal(unsigned int towerIndex) override; + unsigned int encode_mbd(unsigned int towerIndex) override; unsigned int decode_epd(unsigned int towerIndex) override; unsigned int decode_hcal(unsigned int towerIndex) override; unsigned int decode_emcal(unsigned int towerIndex) override; + unsigned int decode_mbd(unsigned int towerIndex) override; size_t size() override { return _clones->GetEntries(); } diff --git a/offline/packages/CaloBase/TowerInfoDefs.cc b/offline/packages/CaloBase/TowerInfoDefs.cc index a5bbba15a9..d7101af09a 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.cc +++ b/offline/packages/CaloBase/TowerInfoDefs.cc @@ -7,7 +7,6 @@ #include #include - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static const int emcadc[8][8] = { @@ -30,496 +29,504 @@ static const int hcaladc[8][2] = { {12, 13}, {14, 15}}; static const int epdchnlmap[16][2] = { - {0, 0}, - {1, 2}, - {3, 4}, - {5, 6}, - {7, 8}, - {9, 10}, - {11, 12}, - {13, 14}, - {15, 16}, - {17, 18}, - {19, 20}, - {21, 22}, - {23, 24}, - {25, 26}, - {27, 28}, - {29, 30}}; - -static const int epd_phimap[31]={0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}; + {0, 0}, + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, + {9, 10}, + {11, 12}, + {13, 14}, + {15, 16}, + {17, 18}, + {19, 20}, + {21, 22}, + {23, 24}, + {25, 26}, + {27, 28}, + {29, 30}}; + +static const int epd_phimap[31] = {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; static const int epd_rmap[31] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; - unsigned int TowerInfoDefs::encode_emcal(const unsigned int towerIndex) +{ + static int phimap[64]; + static int etamap[64]; + static int etabinoffset[4]; + static int ifirst = 1; + if (ifirst == 1) { - - static int phimap[64]; - static int etamap[64]; - static int etabinoffset[4]; - static int ifirst = 1; - if (ifirst == 1) - { - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 8; k++) - { - etamap[emcadc[j][k]] = j; - phimap[emcadc[j][k]] = k; - } - } - etabinoffset[0] = 24; - etabinoffset[1] = 0; - etabinoffset[2] = 48; - etabinoffset[3] = 72; - ifirst = 0; - } - const int channels_per_sector = 64; - const int supersector = 64 * 12; - const int nchannelsperpacket = 64 * 3; - const int maxphibin = 7; - const int maxetabin = 23; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << "Attempting to access channel with invalid value in EMCal " << packet << std::endl; - exit(1); - } - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel]; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin + 8 * interfaceboard; - if (packet == 0 || packet == 1) + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < 8; k++) { - packet_etabin = maxetabin - packet_etabin; + etamap[emcadc[j][k]] = j; + phimap[emcadc[j][k]] = k; } - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); - return key; - } - -unsigned int TowerInfoDefs::encode_emcal (const unsigned int etabin, const unsigned int phibin) - { - unsigned int key = phibin + (etabin << 16U); - return key; + } + etabinoffset[0] = 24; + etabinoffset[1] = 0; + etabinoffset[2] = 48; + etabinoffset[3] = 72; + ifirst = 0; } - - -unsigned int TowerInfoDefs::decode_emcal(const unsigned int tower_key) + const int channels_per_sector = 64; + const int supersector = 64 * 12; + const int nchannelsperpacket = 64 * 3; + const int maxphibin = 7; + const int maxetabin = 23; + int supersectornumber = towerIndex / supersector; + int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| + if (packet < 0 || packet > 3) { - const int etabinoffset[4] = {24,0,48,72}; - const int etabinmap[4] = {1,0,2,3}; - const int channels_per_sector = 64; - const int supersector = 64 * 12; - const int nchannelsperpacket = 64 * 3; - const int maxphibin = 7; - const int maxetabin = 23; - - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabinmap[(int) etabin / 24]; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = 0; - if (packet == 0 || packet == 1) - { - localetabin = maxetabin - localetabin; - } - ib = localetabin / 8; - unsigned int index = 0; - if (packet == 0 || packet == 1) - { - localphibin = maxphibin - localphibin; - } - localetabin = localetabin % 8; - unsigned int localindex = emcadc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; - return index; + std::cout << "Attempting to access channel with invalid value in EMCal " << packet << std::endl; + exit(1); } - - - - - - - - -unsigned int TowerInfoDefs::encode_hcal(const unsigned int towerIndex) + int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; + int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; + int localphibin = phimap[interfaceboard_channel]; + if (packet == 0 || packet == 1) { - static int phimap[64]; - static int etamap[64]; - static int etabinoffset[4]; - static int phibinoffset[4]; - static int ifirst = 1; - if (ifirst == 1) - { - for (int j = 0; j < 8; j++) - { - for (int k = 0; k < 2; k++) - { - etamap[hcaladc[j][k]] = j; - phimap[hcaladc[j][k]] = k; - - } - } - etabinoffset[0] = 0; - etabinoffset[1] = 8; - etabinoffset[2] = 16; - etabinoffset[3] = 0; - - - phibinoffset[0] = 0; - phibinoffset[1] = 2; - phibinoffset[2] = 4; - phibinoffset[3] = 6; - ifirst = 0; - } - - const int channels_per_sector = 16; - const int supersector = 16 * 4 * 3; - const int nchannelsperpacket = channels_per_sector * 4; - // const int etabinoffset[4] = {0,8,16,0}; - // const int phibinoffset[4] = {0,2,4,6}; - int supersectornumber = towerIndex / supersector; - int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| - if (packet < 0 || packet > 3 ) - { - std::cout << "Attempting to access channel with invalid value ih HCAL " << packet << std::endl; - exit(1); - } - int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; - int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; - int localphibin = phimap[interfaceboard_channel] + phibinoffset[interfaceboard]; - int localetabin = etamap[interfaceboard_channel]; - int packet_etabin = localetabin; - unsigned int globaletabin = packet_etabin + etabinoffset[packet]; - unsigned int globalphibin = localphibin + supersectornumber * 8; - unsigned int key = globalphibin + (globaletabin << 16U); - return key; - } - - // convert from etabin-phibin to key -unsigned int TowerInfoDefs::encode_hcal (const unsigned int etabin, const unsigned int phibin) + localphibin = maxphibin - localphibin; + } + int localetabin = etamap[interfaceboard_channel]; + int packet_etabin = localetabin + 8 * interfaceboard; + if (packet == 0 || packet == 1) { - unsigned int key = phibin + (etabin << 16U); - return key; + packet_etabin = maxetabin - packet_etabin; } + unsigned int globaletabin = packet_etabin + etabinoffset[packet]; + unsigned int globalphibin = localphibin + supersectornumber * 8; + unsigned int key = globalphibin + (globaletabin << 16U); + return key; +} +unsigned int TowerInfoDefs::encode_emcal(const unsigned int etabin, const unsigned int phibin) +{ + unsigned int key = phibin + (etabin << 16U); + return key; +} - -unsigned int TowerInfoDefs::decode_hcal(const unsigned int tower_key) +unsigned int TowerInfoDefs::decode_emcal(const unsigned int tower_key) +{ + const int etabinoffset[4] = {24, 0, 48, 72}; + const int etabinmap[4] = {1, 0, 2, 3}; + const int channels_per_sector = 64; + const int supersector = 64 * 12; + const int nchannelsperpacket = 64 * 3; + const int maxphibin = 7; + const int maxetabin = 23; + + unsigned int etabin = tower_key >> 16U; + unsigned int phibin = tower_key - (etabin << 16U); + int packet = etabinmap[(int) etabin / 24]; + int localetabin = etabin - etabinoffset[packet]; + int localphibin = phibin % 8; + int supersectornumber = phibin / 8; + int ib = 0; + if (packet == 0 || packet == 1) { - int channels_per_sector = 16; - int supersector = 16 * 4 * 3; - int nchannelsperpacket = channels_per_sector * 4; - int etabinoffset[3] = {0,8,16}; - int phibinoffset[4] = {0,2,4,6}; - unsigned int etabin = tower_key >> 16U; - unsigned int phibin = tower_key - (etabin << 16U); - int packet = etabin / 8; - int localetabin = etabin - etabinoffset[packet]; - int localphibin = phibin % 8; - int supersectornumber = phibin / 8; - int ib = localphibin / 2; - unsigned int index = 0; - localphibin = localphibin - phibinoffset[ib]; - unsigned int localindex = hcaladc[localetabin][localphibin]; - index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; - return index; + localetabin = maxetabin - localetabin; } - - - // convert from calorimeter key to phi bin -unsigned int TowerInfoDefs::getCaloTowerPhiBin(const unsigned int key) + ib = localetabin / 8; + unsigned int index = 0; + if (packet == 0 || packet == 1) { - unsigned int etabin = key >> 16U; - unsigned int phibin = key - (etabin << 16U); - return phibin; + localphibin = maxphibin - localphibin; } + localetabin = localetabin % 8; + unsigned int localindex = emcadc[localetabin][localphibin]; + index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + return index; +} - // convert from calorimeter key to eta bin - unsigned int TowerInfoDefs::getCaloTowerEtaBin(const unsigned int key) +unsigned int TowerInfoDefs::encode_hcal(const unsigned int towerIndex) +{ + static int phimap[64]; + static int etamap[64]; + static int etabinoffset[4]; + static int phibinoffset[4]; + static int ifirst = 1; + if (ifirst == 1) { - unsigned int etabin = key >> 16U; - return etabin; + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < 2; k++) + { + etamap[hcaladc[j][k]] = j; + phimap[hcaladc[j][k]] = k; + } + } + etabinoffset[0] = 0; + etabinoffset[1] = 8; + etabinoffset[2] = 16; + etabinoffset[3] = 0; + + phibinoffset[0] = 0; + phibinoffset[1] = 2; + phibinoffset[2] = 4; + phibinoffset[3] = 6; + ifirst = 0; } + const int channels_per_sector = 16; + const int supersector = 16 * 4 * 3; + const int nchannelsperpacket = channels_per_sector * 4; + // const int etabinoffset[4] = {0,8,16,0}; + // const int phibinoffset[4] = {0,2,4,6}; + int supersectornumber = towerIndex / supersector; + int packet = (towerIndex % supersector) / nchannelsperpacket; // 0 = S small |eta|, 1 == S big |eta|, 2 == N small |eta|, 3 == N big |eta| + if (packet < 0 || packet > 3) + { + std::cout << "Attempting to access channel with invalid value ih HCAL " << packet << std::endl; + exit(1); + } + int interfaceboard = ((towerIndex % supersector) % nchannelsperpacket) / channels_per_sector; + int interfaceboard_channel = ((towerIndex % supersector) % nchannelsperpacket) % channels_per_sector; + int localphibin = phimap[interfaceboard_channel] + phibinoffset[interfaceboard]; + int localetabin = etamap[interfaceboard_channel]; + int packet_etabin = localetabin; + unsigned int globaletabin = packet_etabin + etabinoffset[packet]; + unsigned int globalphibin = localphibin + supersectornumber * 8; + unsigned int key = globalphibin + (globaletabin << 16U); + return key; +} + +// convert from etabin-phibin to key +unsigned int TowerInfoDefs::encode_hcal(const unsigned int etabin, const unsigned int phibin) +{ + unsigned int key = phibin + (etabin << 16U); + return key; +} +unsigned int TowerInfoDefs::decode_hcal(const unsigned int tower_key) +{ + int channels_per_sector = 16; + int supersector = 16 * 4 * 3; + int nchannelsperpacket = channels_per_sector * 4; + int etabinoffset[3] = {0, 8, 16}; + int phibinoffset[4] = {0, 2, 4, 6}; + unsigned int etabin = tower_key >> 16U; + unsigned int phibin = tower_key - (etabin << 16U); + int packet = etabin / 8; + int localetabin = etabin - etabinoffset[packet]; + int localphibin = phibin % 8; + int supersectornumber = phibin / 8; + int ib = localphibin / 2; + unsigned int index = 0; + localphibin = localphibin - phibinoffset[ib]; + unsigned int localindex = hcaladc[localetabin][localphibin]; + index = localindex + channels_per_sector * ib + packet * nchannelsperpacket + supersector * supersectornumber; + return index; +} + +// convert from calorimeter key to phi bin +unsigned int TowerInfoDefs::getCaloTowerPhiBin(const unsigned int key) +{ + unsigned int etabin = key >> 16U; + unsigned int phibin = key - (etabin << 16U); + return phibin; +} +// convert from calorimeter key to eta bin +unsigned int TowerInfoDefs::getCaloTowerEtaBin(const unsigned int key) +{ + unsigned int etabin = key >> 16U; + return etabin; +} unsigned int TowerInfoDefs::encode_epd(const unsigned int towerIndex) // convert from tower index to key - { - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int supersectornumber = towerIndex / supersector; - int sector = ((towerIndex % supersector)) / channels_per_sector; - int channel = ((towerIndex % supersector)) % channels_per_sector; - unsigned int key = channel + (sector << 5U) + (supersectornumber << 9U); - return key; - } +{ + int channels_per_sector = 31; + int supersector = channels_per_sector * 12; + unsigned int supersectornumber = towerIndex / supersector; + int sector = ((towerIndex % supersector)) / channels_per_sector; + int channel = ((towerIndex % supersector)) % channels_per_sector; + unsigned int key = channel + (sector << 5U) + (supersectornumber << 9U); + return key; +} // convert from arm-rbin-phibin to key -unsigned int TowerInfoDefs::encode_epd (const unsigned int arm, const unsigned int rbin, const unsigned int phibin) +unsigned int TowerInfoDefs::encode_epd(const unsigned int arm, const unsigned int rbin, const unsigned int phibin) { if (rbin == 0 && phibin > 11) - { - std::cout << __PRETTY_FUNCTION__ << " encode_epd invalid phibin value: " << phibin << " where max valid phibin is 11"<< std::endl; - exit(1); - } - - unsigned int sector = phibin/2; - if (rbin == 0) - { - sector = phibin; - } - - int channel = 0; - if (rbin != 0) - { - channel = epdchnlmap[rbin][phibin - 2 * sector]; - } - - unsigned int key = channel + (sector << 5U) + (arm << 9U); - return key; + { + std::cout << __PRETTY_FUNCTION__ << " encode_epd invalid phibin value: " << phibin << " where max valid phibin is 11" << std::endl; + exit(1); } - - -unsigned int TowerInfoDefs::decode_epd(const unsigned int tower_key) -{ - int channels_per_sector = 31; - int supersector = channels_per_sector * 12; - unsigned int ns_sector = tower_key >> 9U; - unsigned int sector = (tower_key - (ns_sector << 9U)) >> 5U; - unsigned int channel = tower_key - (ns_sector << 9U) - (sector << 5U); - unsigned int index = ns_sector * supersector + sector * channels_per_sector + channel; - return index; + unsigned int sector = phibin / 2; + if (rbin == 0) + { + sector = phibin; } + int channel = 0; + if (rbin != 0) + { + channel = epdchnlmap[rbin][phibin - 2 * sector]; + } + unsigned int key = channel + (sector << 5U) + (arm << 9U); + return key; +} - - - - // convert from epd key to arm bin +unsigned int TowerInfoDefs::decode_epd(const unsigned int tower_key) +{ + int channels_per_sector = 31; + int supersector = channels_per_sector * 12; + unsigned int ns_sector = tower_key >> 9U; + unsigned int sector = (tower_key - (ns_sector << 9U)) >> 5U; + unsigned int channel = tower_key - (ns_sector << 9U) - (sector << 5U); + unsigned int index = ns_sector * supersector + sector * channels_per_sector + channel; + return index; +} + +// convert from epd key to arm bin unsigned int TowerInfoDefs::get_epd_arm(unsigned int key) { unsigned int arm = key >> 9U; return arm; - } - //convert from epd key to sector number - unsigned int TowerInfoDefs::get_epd_sector(unsigned int key) - { - unsigned int arm = get_epd_arm(key); - unsigned int sector = (key - (arm << 9U) ) >> 5U; - return sector; - } - // convert from epd key to r bin - unsigned int TowerInfoDefs::get_epd_rbin(unsigned int key) - { - unsigned int arm = get_epd_arm(key); - unsigned int sector = get_epd_sector(key); - unsigned int channel = key - ( sector << 5U) - (arm << 9U); - unsigned int rbin = epd_rmap[channel]; - return rbin; - } - // convert from epd key to phi bin - unsigned int TowerInfoDefs::get_epd_phibin(unsigned int key) +} +// convert from epd key to sector number +unsigned int TowerInfoDefs::get_epd_sector(unsigned int key) +{ + unsigned int arm = get_epd_arm(key); + unsigned int sector = (key - (arm << 9U)) >> 5U; + return sector; +} +// convert from epd key to r bin +unsigned int TowerInfoDefs::get_epd_rbin(unsigned int key) +{ + unsigned int arm = get_epd_arm(key); + unsigned int sector = get_epd_sector(key); + unsigned int channel = key - (sector << 5U) - (arm << 9U); + unsigned int rbin = epd_rmap[channel]; + return rbin; +} +// convert from epd key to phi bin +unsigned int TowerInfoDefs::get_epd_phibin(unsigned int key) +{ + unsigned int arm = get_epd_arm(key); + unsigned int rbin = get_epd_rbin(key); + unsigned int sector = get_epd_sector(key); + unsigned int channel = key - (sector << 5U) - (arm << 9U); + unsigned int phibin = epd_phimap[channel] + 2 * sector; + if (rbin == 0) { - unsigned int arm = get_epd_arm(key); - unsigned int rbin = get_epd_rbin(key); - unsigned int sector = get_epd_sector(key); - unsigned int channel = key - ( sector << 5U) - (arm << 9U); - unsigned int phibin = epd_phimap[channel] + 2*sector; - if (rbin == 0) - { - phibin = sector; - } - - return phibin; + phibin = sector; } - - - - - - - - - + return phibin; +} unsigned int TowerInfoDefs::encode_zdc(const unsigned int towerIndex) +{ + if (towerIndex > 5) { - if (towerIndex > 5) - { - std::cout << "Attempting to access zdc channel with invalid number " << towerIndex << std::endl; - exit(1); - } - // 3 bits: one for pos/neg z and 2 for the 3 modules - unsigned int key; - if(towerIndex==0) key = 0; - if(towerIndex==1) key = 1; - if(towerIndex==2) key = 2; - //negative side - if(towerIndex==3) {key = 1 << 2; key += 0;} - if(towerIndex==4) {key = 1 << 2; key += 1;} - if(towerIndex==5) {key = 1 << 2; key += 2;} - return key; + std::cout << "Attempting to access zdc channel with invalid number " << towerIndex << std::endl; + exit(1); } - - - // convert from channel number to smd tower key - unsigned int TowerInfoDefs::encode_smd(const unsigned int towerIndex) + // 3 bits: one for pos/neg z and 2 for the 3 modules + unsigned int key; + if (towerIndex == 0) key = 0; + if (towerIndex == 1) key = 1; + if (towerIndex == 2) key = 2; + // negative side + if (towerIndex == 3) { - // 3 bits: one for pos/neg z and 2 for the 3 modules - if (towerIndex > 29) - { - std::cout << "Attempting to access smd channel with invalid number " << towerIndex << std::endl; - exit(1); - } - unsigned int Xpos[2] = {0,6}; - unsigned int Ypos[2] = {7,14}; - unsigned int Xneg[2] = {15,23}; - unsigned int Yneg[2] = {22,29}; - unsigned int xyBit = 0; - unsigned int fingerIndex = UINT_MAX; - unsigned int sideBit = 0; - if (towerIndex >= Xpos[0] && towerIndex <= Xpos[1] ) - { - xyBit = 0; - fingerIndex = towerIndex -Xpos[0]; - sideBit = 1; - } - if (towerIndex >= Ypos[0] && towerIndex <= Ypos[1] ) - { - xyBit = 1; - fingerIndex = towerIndex -Ypos[0]; - sideBit = 1; - } - if (towerIndex >= Xneg[0] && towerIndex <= Xneg[1] ) - { - xyBit = 0; - fingerIndex = towerIndex - Xneg[0]; - sideBit = 0; - } - if (towerIndex >= Yneg[0] && towerIndex <= Yneg[1] ) - { - xyBit = 1; - fingerIndex = towerIndex - Yneg[0]; - sideBit = 0; - } - unsigned int key = (sideBit << 4) + (xyBit << 3) + fingerIndex; -// key += (sideBit << 4) + (xyBit << 3) + fingerIndex; - return key; + key = 1 << 2; + key += 0; } - - - - -unsigned int TowerInfoDefs::decode_smd(const unsigned int key) + if (towerIndex == 4) { - unsigned int index=999; - for (unsigned int i=0; i<30; i++) - { - if (encode_smd(i) == key) {index=i; break;} - } - return index; + key = 1 << 2; + key += 1; } - - - // convert from zdc tower key to channel number -unsigned int TowerInfoDefs::decode_zdc(const unsigned int key) + if (towerIndex == 5) { - unsigned int index=999; - for (unsigned int i=0; i<6; i++) - { - if (encode_zdc(i) == key) {index=i; break;} - } - return index; + key = 1 << 2; + key += 2; } - + return key; +} - - // convert from calorimeter key to zdc side -int TowerInfoDefs::get_zdc_side(const unsigned int key) +// convert from channel number to smd tower key +unsigned int TowerInfoDefs::encode_smd(const unsigned int towerIndex) +{ + // 3 bits: one for pos/neg z and 2 for the 3 modules + if (towerIndex > 29) { - if (key&4) return 1; - if (!(key&4)) return -1; - return -999; + std::cout << "Attempting to access smd channel with invalid number " << towerIndex << std::endl; + exit(1); } - - // convert from calorimeter key to zdc module number -unsigned int TowerInfoDefs::get_zdc_module_index(const unsigned int key) + unsigned int Xpos[2] = {0, 6}; + unsigned int Ypos[2] = {7, 14}; + unsigned int Xneg[2] = {15, 23}; + unsigned int Yneg[2] = {22, 29}; + unsigned int xyBit = 0; + unsigned int fingerIndex = UINT_MAX; + unsigned int sideBit = 0; + if (towerIndex >= Xpos[0] && towerIndex <= Xpos[1]) { - return key&3; + xyBit = 0; + fingerIndex = towerIndex - Xpos[0]; + sideBit = 1; } - - // convert from calorimeter key to smd side - int TowerInfoDefs::get_smd_side(const unsigned int key) - { - if (key&(1<<4)) return 1; - if ( !(key&(1<<4)) ) return -1; - return -999; + if (towerIndex >= Ypos[0] && towerIndex <= Ypos[1]) + { + xyBit = 1; + fingerIndex = towerIndex - Ypos[0]; + sideBit = 1; } - // convert from calorimeter key to smd xy bin - int TowerInfoDefs::get_smd_xy(const unsigned int key) - { - if (key&(1<<3)) return 0; - if ( !(key&(1<<3)) ) return 1; - return -999; + if (towerIndex >= Xneg[0] && towerIndex <= Xneg[1]) + { + xyBit = 0; + fingerIndex = towerIndex - Xneg[0]; + sideBit = 0; } - // convert from calorimeter key to smd finger - int TowerInfoDefs::get_smd_finger_index(const unsigned int key) + if (towerIndex >= Yneg[0] && towerIndex <= Yneg[1]) { - return key&7; + xyBit = 1; + fingerIndex = towerIndex - Yneg[0]; + sideBit = 0; } + unsigned int key = (sideBit << 4) + (xyBit << 3) + fingerIndex; + // key += (sideBit << 4) + (xyBit << 3) + fingerIndex; + return key; +} +unsigned int TowerInfoDefs::decode_smd(const unsigned int key) +{ + unsigned int index = 999; + for (unsigned int i = 0; i < 30; i++) + { + if (encode_smd(i) == key) + { + index = i; + break; + } + } + return index; +} +// convert from zdc tower key to channel number +unsigned int TowerInfoDefs::decode_zdc(const unsigned int key) +{ + unsigned int index = 999; + for (unsigned int i = 0; i < 6; i++) + { + if (encode_zdc(i) == key) + { + index = i; + break; + } + } + return index; +} +// convert from calorimeter key to zdc side +int TowerInfoDefs::get_zdc_side(const unsigned int key) +{ + if (key & 4) return 1; + if (!(key & 4)) return -1; + return -999; +} +// convert from calorimeter key to zdc module number +unsigned int TowerInfoDefs::get_zdc_module_index(const unsigned int key) +{ + return key & 3; +} +// convert from calorimeter key to smd side +int TowerInfoDefs::get_smd_side(const unsigned int key) +{ + if (key & (1 << 4)) return 1; + if (!(key & (1 << 4))) return -1; + return -999; +} +// convert from calorimeter key to smd xy bin +int TowerInfoDefs::get_smd_xy(const unsigned int key) +{ + if (key & (1 << 3)) return 0; + if (!(key & (1 << 3))) return 1; + return -999; +} +// convert from calorimeter key to smd finger +int TowerInfoDefs::get_smd_finger_index(const unsigned int key) +{ + return key & 7; +} +// 128 channels per side, goes 8 times and 8 charges and so on +unsigned int TowerInfoDefs::encode_mbd(const unsigned int towerIndex) +{ + unsigned int side = towerIndex / 128; + unsigned int type = (towerIndex % 16) / 8; + unsigned int channel = (towerIndex % 8) + ((towerIndex / 16) * 8); + if (channel > 63) channel -= 64; + unsigned int key = (side << 7) | (type << 6) | channel; + return key; +} - // convienent for interface to geometry class - RawTowerDefs::keytype TowerInfoDefs::get_emcal_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_emcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, etabin, phibin); - return key; - } +unsigned int TowerInfoDefs::decode_mbd(const unsigned int key) +{ + unsigned int side = (key >> 7) & 1; + unsigned int type = (key >> 6) & 1; + unsigned int channel = key & 63; - // convienent for interface to geometry class - RawTowerDefs::keytype TowerInfoDefs::get_hcalin_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_hcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, etabin, phibin); - return key; - } + unsigned int index = (side * 128) + (type * 8) + (channel % 8) + (channel / 8) * 16; - // convienent for interface to geometry class - RawTowerDefs::keytype TowerInfoDefs::get_hcalout_geokey_at_channel(const unsigned int towerIndex) - { - unsigned int towerkey = encode_hcal(towerIndex); - unsigned int etabin = getCaloTowerEtaBin(towerkey); - unsigned int phibin = getCaloTowerPhiBin(towerkey); - const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, etabin, phibin); - return key; - } + return index; +} -#pragma GCC diagnostic pop +unsigned int TowerInfoDefs::get_mbd_side(const unsigned int key) +{ + return (key >> 7) & 1; +} +unsigned int TowerInfoDefs::get_mbd_type(const unsigned int key) +{ + return (key >> 6) & 1; +} + +unsigned int TowerInfoDefs::get_mbd_channel(const unsigned int key) +{ + return key & 63; +} + +// convienent for interface to geometry class +RawTowerDefs::keytype TowerInfoDefs::get_emcal_geokey_at_channel(const unsigned int towerIndex) +{ + unsigned int towerkey = encode_emcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, etabin, phibin); + return key; +} + +// convienent for interface to geometry class +RawTowerDefs::keytype TowerInfoDefs::get_hcalin_geokey_at_channel(const unsigned int towerIndex) +{ + unsigned int towerkey = encode_hcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, etabin, phibin); + return key; +} + +// convienent for interface to geometry class +RawTowerDefs::keytype TowerInfoDefs::get_hcalout_geokey_at_channel(const unsigned int towerIndex) +{ + unsigned int towerkey = encode_hcal(towerIndex); + unsigned int etabin = getCaloTowerEtaBin(towerkey); + unsigned int phibin = getCaloTowerPhiBin(towerkey); + const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, etabin, phibin); + return key; +} + +#pragma GCC diagnostic pop diff --git a/offline/packages/CaloBase/TowerInfoDefs.h b/offline/packages/CaloBase/TowerInfoDefs.h index 37dd163869..aa7298f3b4 100644 --- a/offline/packages/CaloBase/TowerInfoDefs.h +++ b/offline/packages/CaloBase/TowerInfoDefs.h @@ -35,6 +35,10 @@ namespace TowerInfoDefs int get_smd_xy(const unsigned int key); int get_smd_finger_index(const unsigned int key); + unsigned int get_mbd_side(const unsigned int key); + // 0 for time 1 for charge + unsigned int get_mbd_type(const unsigned int key); + unsigned int get_mbd_channel(const unsigned int key); unsigned int encode_zdc(const unsigned int towerIndex); @@ -42,6 +46,9 @@ namespace TowerInfoDefs unsigned int decode_smd(const unsigned int key); unsigned int decode_zdc(const unsigned int key); + unsigned int encode_mbd(const unsigned int towerIndex); + unsigned int decode_mbd(const unsigned int key); + RawTowerDefs::keytype get_emcal_geokey_at_channel(const unsigned int towerIndex); RawTowerDefs::keytype get_hcalin_geokey_at_channel(const unsigned int towerIndex) ; diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 149968fd3c..93930a8b12 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -53,7 +53,7 @@ CaloTowerBuilder::~CaloTowerBuilder() int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { WaveformProcessing->set_processing_type(_processingtype); - WaveformProcessing->set_softwarezerosuppression(_bdosoftwarezerosuppression,_nsoftwarezerosuppression); + WaveformProcessing->set_softwarezerosuppression(_bdosoftwarezerosuppression, _nsoftwarezerosuppression); if (m_dettype == CaloTowerBuilder::CEMC) { @@ -63,9 +63,9 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_cemc_template.root"); if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); - } + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::HCALIN) { @@ -75,9 +75,9 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ihcal_template.root"); if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); - } + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::HCALOUT) { @@ -87,9 +87,9 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_nchannels = 192; WaveformProcessing->set_template_file("testbeam_ohcal_template.root"); if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); - } + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); + } } else if (m_dettype == CaloTowerBuilder::EPD) { @@ -98,9 +98,20 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_packet_high = 9005; m_nchannels = 186; if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); //default the EPD to fast processing - } + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); // default the EPD to fast processing + } + } + else if (m_dettype == CaloTowerBuilder::MBD) + { + m_detector = "MBD"; + m_packet_low = 1001; + m_packet_high = 1002; + m_nchannels = 128; + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); + } } WaveformProcessing->initialize_processing(); CreateNodeTree(topNode); @@ -128,60 +139,60 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { Packet *packet = _event->getPacket(pid); if (packet) - { - int nchannels = packet->iValue(0, "CHANNELS"); - if (nchannels > m_nchannels) // packet is corrupted and reports too many channels - { - return Fun4AllReturnCodes::DISCARDEVENT; - } - for (int channel = 0; channel < nchannels; channel++) - { - std::vector waveform; - waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nsamples; samp++) - { - waveform.push_back(packet->iValue(samp, channel)); - } - waveforms.push_back(waveform); - waveform.clear(); - } - if (nchannels < m_nchannels) - { - for (int channel = 0; channel waveform; - waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { - waveform.push_back(0); - } - waveforms.push_back(waveform); - waveform.clear(); - } - } - delete packet; - } - else // if the packet is missing treat constitutent channels as zero suppressed - { - for (int channel = 0; channel waveform; - waveform.reserve(2); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { - waveform.push_back(0); - } - waveforms.push_back(waveform); - waveform.clear(); - } - } + { + int nchannels = packet->iValue(0, "CHANNELS"); + if (nchannels > m_nchannels) // packet is corrupted and reports too many channels + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + for (int channel = 0; channel < nchannels; channel++) + { + std::vector waveform; + waveform.reserve(m_nsamples); + for (int samp = 0; samp < m_nsamples; samp++) + { + waveform.push_back(packet->iValue(samp, channel)); + } + waveforms.push_back(waveform); + waveform.clear(); + } + if (nchannels < m_nchannels) + { + for (int channel = 0; channel < m_nchannels - nchannels; channel++) + { + std::vector waveform; + waveform.reserve(m_nsamples); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(0); + } + waveforms.push_back(waveform); + waveform.clear(); + } + } + delete packet; + } + else // if the packet is missing treat constitutent channels as zero suppressed + { + for (int channel = 0; channel < m_nchannels; channel++) + { + std::vector waveform; + waveform.reserve(2); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(0); + } + waveforms.push_back(waveform); + waveform.clear(); + } + } } } else // placeholder for adding simulation { return Fun4AllReturnCodes::EVENT_OK; } - + std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); for (int i = 0; i < n_channels; i++) @@ -189,7 +200,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) m_CaloInfoContainer->get_tower_at_channel(i)->set_time(processed_waveforms.at(i).at(1)); m_CaloInfoContainer->get_tower_at_channel(i)->set_energy(processed_waveforms.at(i).at(0)); } - + waveforms.clear(); return Fun4AllReturnCodes::EVENT_OK; @@ -216,6 +227,10 @@ void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) { m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::SEPD); } + else if (m_dettype == MBD) + { + m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::MBD); + } else { m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL); diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index 6947de5a76..fbf03e249e 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -28,7 +28,8 @@ class CaloTowerBuilder : public SubsysReco CEMC = 0, HCALIN = 1, HCALOUT = 2, - EPD = 3 + EPD = 3, + MBD = 4 }; void set_detector_type(CaloTowerBuilder::DetectorSystem dettype) From 5b54b80afed9007222b0c4591c48f9e639ddd20e Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 22 May 2023 09:37:36 -0400 Subject: [PATCH 426/468] Latest working version --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 0a1c97806c..8d01a02c05 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -288,8 +288,9 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( if(phi<0)phi_gain += 2*M_PI; double gain_weight = 1.0; if(m_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm + gain_weight = 1.0; nelec = nelec*gain_weight; - std::cout<<"PHG4TpcPadPlaneReadout::MapToPadPlane gain_weight = "< +#include + +#include + +#include + +#include +//#include +#include + +#include + +// cppcheck-suppress unknownMacro +R__LOAD_LIBRARY(libfun4all.so) +// cppcheck-suppress unknownMacro +R__LOAD_LIBRARY(rawtodst.so) +// cppcheck-suppress unknownMacro +R__LOAD_LIBRARY(libfun4allraw.so) + +void Fun4All_ReadTPCHits( const int nEvents = 1, const string &fname = "/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc00_pedestal-00010305-0000.prdf",const string &foutputname = "./Files/hists_G4Hits_sHijing_0-12fm_000000_001000.root" ){ + + /////////////////////////////////////////// + // Make the Server + ////////////////////////////////////////// + Fun4AllServer *se = Fun4AllServer::instance(); + tpc_hits *TPC_HITS_set = new tpc_hits(); + + se->registerSubsystem(TPC_HITS_set); + + gSystem->Load("libFROG"); + FROG *fr = new FROG(); + string inputFileName = fr->location(fname); + cout << "Next file:" << inputFileName << endl; + // this (DST) input manager just drives the event loop + Fun4AllPrdfInputManager *in = new Fun4AllPrdfInputManager("PRDF1"); + in->AddFile(inputFileName); + se->registerInputManager(in); + if (nEvents <= 0) + { + return; + } + cout << endl << "Running over " << nEvents << " Events" << endl; + se->run(nEvents); + //} + cout << endl << "Calling End in Fun4All_ReadTPCHits.C" << endl; + se->End(); + + cout << endl << "All done, calling delete Fun4AllServer" << endl; + delete se; + + cout << endl << "gSystem->Exit(0)" << endl; + gSystem->Exit(0); + + +} \ No newline at end of file diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index ec7be43442..cda11746cc 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -19,7 +19,6 @@ #include -#include //____________________________________________________________________________.. tpc_hits::tpc_hits(const std::string &name) @@ -48,8 +47,36 @@ int tpc_hits::Init(PHCompositeNode * /*topNode*/) //____________________________________________________________________________.. int tpc_hits::InitRun(PHCompositeNode *topNode) { - // std::cout << "tpc_hits::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << std::endl; + // get dst node + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "tpc_hits::InitRun - DST Node missing, doing nothing." << std::endl; + exit(1); + } + + // create hitset container if needed + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + if (!hitsetcontainer) + { + std::cout << "tpc_hits::InitRun - creating TRKR_HITSET." << std::endl; + + // find or create TRKR node + PHNodeIterator dstiter(dstNode); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!trkrnode) + { + trkrnode = new PHCompositeNode("TRKR"); + dstNode->addNode(trkrnode); + } + + // create container and add to the tree + m_hits = new TrkrHitSetContainerv1; + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + trkrnode->addNode(newNode); + } topNode->print(); // we reset the BCO for the new run @@ -57,7 +84,7 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) rollover_value = 0; current_BCOBIN = 0; - m_hits = new TrkrHitSetContainerv1(); + //m_hits = new TrkrHitSetContainerv1(); return Fun4AllReturnCodes::EVENT_OK; } @@ -78,12 +105,23 @@ int tpc_hits::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::DISCARDEVENT; } - Packet *p = _event->getPacket(4001); - if (!p) + Packet *p = _event->getPacket(4000); + // check all possible TPC packets that we need to analyze + for (int packet = 4000; packet<=4230; packet+=10) { - return Fun4AllReturnCodes::DISCARDEVENT; + std::cout << "tpc_hits:: Packet: "<< packet << " processing" << std::endl; + Packet *p_tmp = _event->getPacket(packet); + + if (!p_tmp) + { + std::cout << "tpc_hits:: Event getPacket: "<< packet << " IS NOT FOUND" << std::endl; + //return Fun4AllReturnCodes::DISCARDEVENT; + }else{ + //p = _event->getPacket(packet); + std::cout << "tpc_hits:: Event getPacket: "<< packet << " FOUND!!!" << std::endl; + + } } - int nr_of_waveforms = p->iValue(0, "NR_WF"); for (auto &l : m_hitset) @@ -109,6 +147,18 @@ int tpc_hits::process_event(PHCompositeNode *topNode) } int sampa_nr = p->iValue(wf, "SAMPAADDRESS"); int channel = p->iValue(wf, "CHANNEL"); + + int fee = p->iValue(wf, "FEE"); + int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); + int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); + int checksum = p->iValue(wf, "CHECKSUM"); + int checksumError = p->iValue(wf, "CHECKSUMERROR"); + int samples = p->iValue( wf, "SAMPLES" ); + + + + //std::cout << "tpc_hits::Process_Event SAMPAADDRESS " << sampa_nr << std::endl; + //std::cout << "tpc_hits::Process_Event Chn " << channel << std::endl; int layer; if (channel < 128) { @@ -122,15 +172,43 @@ int tpc_hits::process_event(PHCompositeNode *topNode) // mhit->setAdc( int sector = 0; int side = 0; + //std::cout << "tpc_hits::Process_Event Chn 1" << std::endl; TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); + //std::cout << "tpc_hits::Process_Event Chn 2" << std::endl; TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(hitsetkey); - for (int s = 0; s < p->iValue(wf, "SAMPLES"); s++) + + //TrkrHit *hit = hitsetit->second; + + std::cout << "tpc_hits::Process_Event Chn Chn:"<< channel + <<" layer: " << layer + << " sampa: "<< sampa_nr + << " fee: "<< fee + << " sampaAddress: "<< sampaAddress + << " sampaChannel: "<< sampaChannel + << " checksum: "<< checksum + << " checksumError: "<< checksumError + + << " hitsetkey "<< hitsetkey + + << std::endl; + for( int is = 0 ; is < samples ; is++ ) + { + p->iValue(wf,is); + } + + //std::cout << "tpc_hits::Process_Event Chn 3" << std::endl; + for (int s = 0; s < samples; s++) { int pad = 0; + // generate hit key TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(pad, s + 2 * (current_BCO - starting_BCO)); + // find existing hit, or create TrkrHit *hit = hitsetit->second->getHit(hitkey); + // create hit, assign adc and insert in hitset hit->setAdc(0); + hitsetit->second->addHitSpecificKey(hitkey, hit); } + } } // we skip the mapping to real pads at first. We just say diff --git a/offline/packages/rawtodst/tpc_hits.h b/offline/packages/rawtodst/tpc_hits.h index a82c4e8871..951c67df63 100644 --- a/offline/packages/rawtodst/tpc_hits.h +++ b/offline/packages/rawtodst/tpc_hits.h @@ -8,6 +8,7 @@ #include +#include #include class PHCompositeNode; From 1e46c72e9ac39f4207e1691773fee1bf8d786757 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Mon, 22 May 2023 16:25:22 -0400 Subject: [PATCH 428/468] latest version --- offline/packages/rawtodst/tpc_hits.cc | 45 ++++++++++++++++----------- offline/packages/rawtodst/tpc_hits.h | 3 ++ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index cda11746cc..1650bb0e43 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -2,6 +2,11 @@ #include "tpc_hits.h" #include +#include +#include +#include +#include + #include #include #include @@ -58,8 +63,8 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) } // create hitset container if needed - auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); - if (!hitsetcontainer) + m_hits = findNode::getClass(topNode, "TRKR_HITSET"); + if (!m_hits) { std::cout << "tpc_hits::InitRun - creating TRKR_HITSET." << std::endl; @@ -74,7 +79,7 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) // create container and add to the tree m_hits = new TrkrHitSetContainerv1; - auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + auto newNode = new PHIODataNode(m_hits, "TRKR_HITSET", "PHObject"); trkrnode->addNode(newNode); } topNode->print(); @@ -173,13 +178,12 @@ int tpc_hits::process_event(PHCompositeNode *topNode) int sector = 0; int side = 0; //std::cout << "tpc_hits::Process_Event Chn 1" << std::endl; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); //std::cout << "tpc_hits::Process_Event Chn 2" << std::endl; - TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(hitsetkey); + TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); - //TrkrHit *hit = hitsetit->second; - std::cout << "tpc_hits::Process_Event Chn Chn:"<< channel + std::cout << "tpc_hits::Process_Event Samples "<< samples <<"Chn:"<< channel <<" layer: " << layer << " sampa: "<< sampa_nr << " fee: "<< fee @@ -188,26 +192,31 @@ int tpc_hits::process_event(PHCompositeNode *topNode) << " checksum: "<< checksum << " checksumError: "<< checksumError - << " hitsetkey "<< hitsetkey + << " hitsetkey "<< tpcHitSetKey << std::endl; - for( int is = 0 ; is < samples ; is++ ) - { - p->iValue(wf,is); - } + //for( int is = 0 ; is < samples ; is++ ) + //{ + // p->iValue(wf,is); + //} //std::cout << "tpc_hits::Process_Event Chn 3" << std::endl; for (int s = 0; s < samples; s++) { - int pad = 0; + unsigned short pad = 0; + unsigned short t = s + 2 * (current_BCO - starting_BCO); + std::cout << "current_BCO - starting_BCO="<< current_BCO <<"-"<< starting_BCO<<"=" << s + 2 * (current_BCO - starting_BCO) << std::endl; // generate hit key - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(pad, s + 2 * (current_BCO - starting_BCO)); + //TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(pad, t);//s + 2 * (current_BCO - starting_BCO)); + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); // find existing hit, or create - TrkrHit *hit = hitsetit->second->getHit(hitkey); - // create hit, assign adc and insert in hitset - hit->setAdc(0); - hitsetit->second->addHitSpecificKey(hitkey, hit); + std::cout << "| " << hitkey << " "<< p->iValue(wf,s) ; + m_hit = hitsetit->second->getHit(hitkey); + // // create hit, assign adc and insert in hitset + m_hit->setAdc(0+s); + // hitsetit->second->addHitSpecificKey(hitkey, hit); } + std::cout << std::endl; } } diff --git a/offline/packages/rawtodst/tpc_hits.h b/offline/packages/rawtodst/tpc_hits.h index 951c67df63..95d8d445fb 100644 --- a/offline/packages/rawtodst/tpc_hits.h +++ b/offline/packages/rawtodst/tpc_hits.h @@ -6,6 +6,9 @@ #include "TPCMap.h" #include "TPC_RawHit.h" +#include +#include + #include #include From ce9afcea9b27bbeda97174d8da1c2d57bbbb3452 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 22 May 2023 20:41:27 -0400 Subject: [PATCH 429/468] add verbosity --- offline/database/sphenixnpc/CDBUtils.cc | 10 +++++++++- offline/database/sphenixnpc/CDBUtils.h | 2 +- offline/database/sphenixnpc/SphenixClient.h | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 0ee6974bf9..6bf6f31f2b 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -203,4 +203,12 @@ int CDBUtils::createPayloadType(const std::string& pl_type) } return iret; } -// nlohmann::json ret = insertPayload(pl_type, file_url, 0, iov_start); + +void CDBUtils::Verbosity(int i) +{ + if (cdbclient) + { + cdbclient->Verbosity(i); + } + m_Verbosity = i; +} diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 30046c1164..5cc6229caa 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -29,7 +29,7 @@ class CDBUtils void clearCache(); bool isGlobalTagSet(); int createPayloadType(const std::string& pl_type); - void Verbosity(int i) { m_Verbosity = i; } + void Verbosity(int i); int Verbosity() const { return m_Verbosity; } private: diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 6ffd9ff2a9..cb06408c71 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -21,12 +21,12 @@ class SphenixClient : public nopayloadclient::NoPayloadClient nlohmann::json getUrl(const std::string& pl_type, long long iov); nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start); nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end); - nlohmann::json setGlobalTag1(const std::string& name); + nlohmann::json setGlobalTag(const std::string& name); nlohmann::json clearCache(); nlohmann::json createGlobalTag1(const std::string &tagname); int createDomain(const std::string &domain); - nlohmann::json setGlobalTag(const std::string &tagname); + nlohmann::json setGlobalTag1(const std::string &tagname); int cache_set_GlobalTag(const std::string &name); bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } From 322942b7f77cee16d23ad4baea9fb4b0254f0141 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 23 May 2023 10:33:01 -0400 Subject: [PATCH 430/468] fix Fun4AllRunNodeInputManager --- .../fun4all/Fun4AllDstOutputManager.cc | 4 +++ .../fun4all/Fun4AllDstOutputManager.h | 2 ++ .../framework/fun4all/Fun4AllOutputManager.h | 1 + .../fun4all/Fun4AllRunNodeInputManager.cc | 34 ++----------------- .../fun4all/Fun4AllRunNodeInputManager.h | 1 + .../framework/fun4all/Fun4AllSyncManager.cc | 2 +- 6 files changed, 12 insertions(+), 32 deletions(-) diff --git a/offline/framework/fun4all/Fun4AllDstOutputManager.cc b/offline/framework/fun4all/Fun4AllDstOutputManager.cc index 03df89c09e..2f555f9df1 100644 --- a/offline/framework/fun4all/Fun4AllDstOutputManager.cc +++ b/offline/framework/fun4all/Fun4AllDstOutputManager.cc @@ -118,6 +118,10 @@ void Fun4AllDstOutputManager::Print(const std::string &what) const // that everything is written out), those nodes are declared transient int Fun4AllDstOutputManager::Write(PHCompositeNode *startNode) { + if (!m_SaveDstNodeFlag) + { + return 0; + } PHNodeIterator nodeiter(startNode); if (savenodes.empty()) { diff --git a/offline/framework/fun4all/Fun4AllDstOutputManager.h b/offline/framework/fun4all/Fun4AllDstOutputManager.h index 52a40758c2..e2f5166a85 100644 --- a/offline/framework/fun4all/Fun4AllDstOutputManager.h +++ b/offline/framework/fun4all/Fun4AllDstOutputManager.h @@ -25,6 +25,7 @@ class Fun4AllDstOutputManager : public Fun4AllOutputManager int StripNode(const std::string &nodename) override; int StripRunNode(const std::string &nodename) override; void SaveRunNode(const int i) override { m_SaveRunNodeFlag = i; } + void SaveDstNode(const int i) override { m_SaveDstNodeFlag = i; } int outfileopen(const std::string &fname) override; void Print(const std::string &what = "ALL") const override; @@ -35,6 +36,7 @@ class Fun4AllDstOutputManager : public Fun4AllOutputManager private: PHNodeIOManager *dstOut = nullptr; int m_SaveRunNodeFlag = 1; + int m_SaveDstNodeFlag = 1; std::set savenodes; std::set saverunnodes; std::set stripnodes; diff --git a/offline/framework/fun4all/Fun4AllOutputManager.h b/offline/framework/fun4all/Fun4AllOutputManager.h index 353ad422f0..b270fe8cb2 100644 --- a/offline/framework/fun4all/Fun4AllOutputManager.h +++ b/offline/framework/fun4all/Fun4AllOutputManager.h @@ -47,6 +47,7 @@ class Fun4AllOutputManager : public Fun4AllBase } virtual void SaveRunNode(const int) { return; } + virtual void SaveDstNode(const int) { return; } /*! \brief add an event selector to the outputmanager. diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc index 97e0dfbe3c..80ed6abca9 100644 --- a/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.cc @@ -64,45 +64,17 @@ int Fun4AllRunNodeInputManager::fileopen(const std::string &filenam) { runNode(se->getNode(RunNodeName(), TopNodeName())); IManager()->read(runNode()); - // get the current run number + // get the current run number from an existing run noder RunHeader *runheader = findNode::getClass(runNode(), "RunHeader"); if (runheader) { SetRunNumber(runheader->get_RunNumber()); } - // delete our internal copy of the runnode when opening subsequent files - if (runNodeCopy()) - { - std::cout << PHWHERE - << " The impossible happened, we have a valid copy of the run node " - << runNodeCopy()->getName() << " which should be a nullptr" - << std::endl; - gSystem->Exit(1); - } - runNodeCopy(new PHCompositeNode("RUNNODECOPY")); - if (!runNodeSum()) - { - runNodeSum(new PHCompositeNode("RUNNODESUM")); - } - PHNodeIOManager *tmpIman = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree); - tmpIman->read(runNodeCopy()); - delete tmpIman; - - PHNodeIntegrate integrate; - integrate.RunNode(runNode()); - integrate.RunSumNode(runNodeSum()); - // run recursively over internal run node copy and integrate objects - PHNodeIterator mainIter(runNodeCopy()); - mainIter.forEach(integrate); - // we do not need to keep the internal copy, keeping it would crate - // problems in case a subsequent file does not contain all the - // runwise objects from the previous file. Keeping this copy would then - // integrate the missing object again with the old copy - delete runNodeCopy(); - runNodeCopy(nullptr); } // DLW: move the delete outside the if block to cover the case where isFunctional() fails delete IManager(); + IManager(nullptr); + IsOpen(1); return 0; } diff --git a/offline/framework/fun4all/Fun4AllRunNodeInputManager.h b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h index 620129f8e5..b35c0eb85f 100644 --- a/offline/framework/fun4all/Fun4AllRunNodeInputManager.h +++ b/offline/framework/fun4all/Fun4AllRunNodeInputManager.h @@ -32,6 +32,7 @@ class Fun4AllRunNodeInputManager : public Fun4AllDstInputManager int PushBackEvents(const int /*i*/) override { return 0; } int SkipForThisManager(const int nevents) override { return PushBackEvents(nevents); } int HasSyncObject() const override { return 0; } + }; #endif // FUN4ALL_FUN4ALLRUNNODEINPUTMANAGER_H diff --git a/offline/framework/fun4all/Fun4AllSyncManager.cc b/offline/framework/fun4all/Fun4AllSyncManager.cc index 3f93a43c87..80a1871b5a 100644 --- a/offline/framework/fun4all/Fun4AllSyncManager.cc +++ b/offline/framework/fun4all/Fun4AllSyncManager.cc @@ -256,7 +256,7 @@ int Fun4AllSyncManager::run(const int nevnts) { if (m_CurrentRun != runno) { - std::cout << "Mixing run numbers (except runnumber=0 which means no valid runnumber) is not supported" << std::endl; + std::cout << PHWHERE << "Mixing run numbers (except runnumber=0 which means no valid runnumber) is not supported" << std::endl; std::cout << "Here are the list of input managers and runnumbers:" << std::endl; for (Fun4AllInputManager *inman : m_InManager) { From 031d7f4e326ebb3167d0781e22405916e5f858f7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 23 May 2023 11:08:25 -0400 Subject: [PATCH 431/468] add more spacal geometry fields to DumpPHG4CylinderGeomContainer.cc --- .../NodeDump/DumpPHG4CylinderGeomContainer.cc | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc index 392de60117..11bdf0eb36 100644 --- a/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc +++ b/offline/packages/NodeDump/DumpPHG4CylinderGeomContainer.cc @@ -57,6 +57,13 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) *fout << "xpos: " << layergeomv1->get_xpos() << std::endl; *fout << "ypos: " << layergeomv1->get_ypos() << std::endl; *fout << "zpos: " << layergeomv1->get_zpos() << std::endl; + *fout << "fiber_clading_thickness: " << layergeomv1->get_fiber_clading_thickness() << std::endl; + *fout << "fiber_core_diameter: " << layergeomv1->get_fiber_core_diameter() << std::endl; + *fout << "fiber_distance: " << layergeomv1->get_fiber_distance() << std::endl; + *fout << "absorber_mat: " << layergeomv1->get_absorber_mat() << std::endl; + *fout << "fiber_clading_mat: " << layergeomv1->get_fiber_clading_mat() << std::endl; + *fout << "fiber_core_mat: " << layergeomv1->get_fiber_core_mat() << std::endl; + *fout << "virualize_fiber: " << layergeomv1->is_virualize_fiber() << std::endl; for (auto sectormapiter : sector_map) { *fout << "sector " << sectormapiter.first << ", rotation: " << sectormapiter.second << std::endl; @@ -66,10 +73,39 @@ int DumpPHG4CylinderGeomContainer::process_Node(PHNode *myNode) if (layergeomv3) { *fout << "sidewall_outer_torr: " << layergeomv3->get_sidewall_outer_torr() << std::endl; + *fout << "sidewall_thickness: " << layergeomv3->get_sidewall_thickness() << std::endl; + *fout << "sidewall_mat: " << layergeomv3->get_sidewall_mat() << std::endl; + *fout << "max_phi_bin_in_sec: " << layergeomv3->get_max_phi_bin_in_sec() << std::endl; + *fout << "divider_mat: " << layergeomv3->get_divider_mat() << std::endl; + *fout << "divider_width: " << layergeomv3->get_divider_width() << std::endl; + const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeomv3->get_sector_tower_map(); for (const auto &towermapiter : tower_map) { - *fout << "tower " << towermapiter.first << ", rot angle: " << towermapiter.second.pRotationAngleX << std::endl; + *fout << "tower " << towermapiter.first << ", id: " << towermapiter.second.id << std::endl; + *fout << "tower " << towermapiter.first << ", pDz: " << towermapiter.second.pDz << std::endl; + *fout << "tower " << towermapiter.first << ", pDy1: " << towermapiter.second.pDy1 << std::endl; + *fout << "tower " << towermapiter.first << ", pDx1: " << towermapiter.second.pDx1 << std::endl; + *fout << "tower " << towermapiter.first << ", pDx2: " << towermapiter.second.pDx2 << std::endl; + *fout << "tower " << towermapiter.first << ", pDy2: " << towermapiter.second.pDy2 << std::endl; + *fout << "tower " << towermapiter.first << ", pDx3: " << towermapiter.second.pDx3 << std::endl; + *fout << "tower " << towermapiter.first << ", pDx4: " << towermapiter.second.pDx4 << std::endl; + *fout << "tower " << towermapiter.first << ", pTheta: " << towermapiter.second.pTheta << std::endl; + *fout << "tower " << towermapiter.first << ", pPhi: " << towermapiter.second.pPhi << std::endl; + *fout << "tower " << towermapiter.first << ", pAlp1: " << towermapiter.second.pAlp1 << std::endl; + *fout << "tower " << towermapiter.first << ", pAlp2: " << towermapiter.second.pAlp2 << std::endl; + *fout << "tower " << towermapiter.first << ", pRotationAngleX: " << towermapiter.second.pRotationAngleX << std::endl; + *fout << "tower " << towermapiter.first << ", centralX: " << towermapiter.second.centralX << std::endl; + *fout << "tower " << towermapiter.first << ", centralY: " << towermapiter.second.centralY << std::endl; + *fout << "tower " << towermapiter.first << ", centralZ: " << towermapiter.second.centralZ << std::endl; + *fout << "tower " << towermapiter.first << ", ModuleSkinThickness: " << towermapiter.second.ModuleSkinThickness << std::endl; + *fout << "tower " << towermapiter.first << ", NFiberX: " << towermapiter.second.NFiberX << std::endl; + *fout << "tower " << towermapiter.first << ", NFiberY: " << towermapiter.second.NFiberY << std::endl; + *fout << "tower " << towermapiter.first << ", NSubtowerX: " << towermapiter.second.NSubtowerX << std::endl; + *fout << "tower " << towermapiter.first << ", NSubtowerY: " << towermapiter.second.NSubtowerY << std::endl; + *fout << "tower " << towermapiter.first << ", LightguideHeight: " << towermapiter.second.LightguideHeight << std::endl; + *fout << "tower " << towermapiter.first << ", LightguideTaperRatio: " << towermapiter.second.LightguideTaperRatio << std::endl; + *fout << "tower " << towermapiter.first << ", LightguideMaterial: " << towermapiter.second.LightguideMaterial << std::endl; } } } From 36f4b7c2461da43fce7bc89b55f1c465ec6d0929 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 23 May 2023 14:40:41 -0400 Subject: [PATCH 432/468] Changed TPC distortion corrections to be stored on the runNode rather than the dstNode --- .../tpc/TpcLoadDistortionCorrection.cc | 18 ++----- .../tpccalib/PHTpcCentralMembraneMatcher.cc | 53 ++++++++----------- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index 99447abbe9..70a6f16b2c 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -53,22 +53,14 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) // look for distortion calibration object PHNodeIterator iter(topNode); - /// Get the DST node and check - auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) + /// Get the RUN node and check + auto runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) { - std::cout << "TpcLoadDistortionCorrection::InitRun - DST Node missing, quitting" << std::endl; + std::cout << "TpcLoadDistortionCorrection::InitRun - RUN Node missing, quitting" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - // Get the tracking subnode and create if not found - auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); - if (!svtxNode) - { - svtxNode = new PHCompositeNode("SVTX"); - dstNode->addNode(svtxNode); - } - //create and populate the nodes for each distortion, if present: for (int i=0;i<3;i++){ @@ -81,7 +73,7 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) std::cout << "TpcLoadDistortionCorrection::InitRun - creating TpcDistortionCorrectionContainer in node " << m_node_name[i] << std::endl; distortion_correction_object = new TpcDistortionCorrectionContainer; auto node = new PHDataNode(distortion_correction_object, m_node_name[i]); - svtxNode->addNode(node); + runNode->addNode(node); } std::cout << "TpcLoadDistortionCorrection::InitRun - reading corrections from " << m_correction_filename[i] << std::endl; diff --git a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc index 59c6e9fa61..4000e4a1de 100644 --- a/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc +++ b/offline/packages/tpccalib/PHTpcCentralMembraneMatcher.cc @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -184,8 +183,8 @@ double PHTpcCentralMembraneMatcher::getPhiRotation_smoothed(TH1D *hitHist, TH1D clustHist->Fit("f1","IQ"); - clustHist->Draw(); - f1->Draw("same"); + // clustHist->Draw(); + //f1->Draw("same"); return f1->GetParameter(1); } @@ -383,8 +382,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) // reset output distortion correction container histograms for( const auto& harray:{m_dcc_out->m_hDRint, m_dcc_out->m_hDPint, m_dcc_out->m_hDZint, m_dcc_out->m_hentries} ) - { for( const auto& h:harray ) { h->Reset(); } } - + { + clust_r_phi_pos->Reset(); clust_r_phi_neg->Reset(); @@ -392,6 +391,8 @@ int PHTpcCentralMembraneMatcher::process_event(PHCompositeNode * /*topNode*/) m_event_index++; return Fun4AllReturnCodes::EVENT_OK; } + + for( const auto& h:harray ) { h->Reset(); } } // read the reconstructed CM clusters auto clusrange = m_corrected_CMcluster_map->getClusters(); @@ -887,36 +888,28 @@ int PHTpcCentralMembraneMatcher::GetNodes(PHCompositeNode* topNode) //// output tpc fluctuation distortion container //// this one is filled on the fly on a per-CM-event basis, and applied in the tracking chain - //const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; - //m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); - //if( !m_dcc_out ) - //{ + const std::string dcc_out_node_name = "TpcDistortionCorrectionContainerFluctuation"; + m_dcc_out = findNode::getClass(topNode,dcc_out_node_name); + if( !m_dcc_out ) + { - // /// Get the DST node and check - // auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - // if (!dstNode) - // { - // std::cout << "PHTpcCentralMembraneMatcher::InitRun - DST Node missing, quitting" << std::endl; - // return Fun4AllReturnCodes::ABORTRUN; - // } + /// Get the RUN node and check + auto runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << "PHTpcCentralMembraneMatcher::InitRun - RUN Node missing, quitting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - // // Get the tracking subnode and create if not found - // auto svtxNode = dynamic_cast(iter.findFirst("PHCompositeNode", "SVTX")); - // if (!svtxNode) - // { - // svtxNode = new PHCompositeNode("SVTX"); - // dstNode->addNode(svtxNode); - // } - - // std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; - // m_dcc_out = new TpcDistortionCorrectionContainer; - // auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); - // svtxNode->addNode(node); - // } + std::cout << "PHTpcCentralMembraneMatcher::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; + m_dcc_out = new TpcDistortionCorrectionContainer; + auto node = new PHDataNode(m_dcc_out, dcc_out_node_name); + runNode->addNode(node); + } // create per event distortions. Do not put on the node tree - m_dcc_out = new TpcDistortionCorrectionContainer; + //m_dcc_out = new TpcDistortionCorrectionContainer; // also prepare the local distortion container, used to aggregate multple events m_dcc_out_aggregated.reset( new TpcDistortionCorrectionContainer ); From 2854bd29f87bc18af3e3f24961b7a21fdc8df34e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 May 2023 15:07:50 -0400 Subject: [PATCH 433/468] allow layer misalignment in acts kf --- offline/packages/trackbase/AlignmentTransformation.cc | 4 ++-- offline/packages/trackbase/AlignmentTransformation.h | 2 +- offline/packages/trackbase/Calibrator.h | 4 ++-- .../trackbase/alignmentTransformationContainer.cc | 10 +++++----- .../trackbase/alignmentTransformationContainer.h | 6 +++--- offline/packages/trackreco/MakeActsGeometry.cc | 4 ++-- offline/packages/trackreco/MakeActsGeometry.h | 8 ++++---- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index ef9a887d4b..326778e695 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -310,9 +310,9 @@ int AlignmentTransformation::getNodes(PHCompositeNode* topNode) return 0; } -void AlignmentTransformation::misalignmentFactor(TrkrDefs::TrkrId id, const double factor) +void AlignmentTransformation::misalignmentFactor(uint8_t layer, const double factor) { - transformMap->setMisalignmentFactor(id, factor); + transformMap->setMisalignmentFactor(layer, factor); } void AlignmentTransformation::createAlignmentTransformContainer(PHCompositeNode* topNode) { diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index bb61bee929..652b25841d 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -103,7 +103,7 @@ void setTPCParams(double tpcDevs[6]) } } - void misalignmentFactor(TrkrDefs::TrkrId id, const double factor); + void misalignmentFactor(uint8_t layer, const double factor); private: diff --git a/offline/packages/trackbase/Calibrator.h b/offline/packages/trackbase/Calibrator.h index 2ffaf83960..b03076a38c 100644 --- a/offline/packages/trackbase/Calibrator.h +++ b/offline/packages/trackbase/Calibrator.h @@ -61,8 +61,8 @@ class Calibrator auto cov = uncalibmeas.covariance(); const auto& cluskey = sourceLink.cluskey(); - const auto trkrid = TrkrDefs::getTrkrId(cluskey); - const double misalignmentFactor = gctx.get()->getMisalignmentFactor(trkrid); + const auto layer = TrkrDefs::getLayer(cluskey); + const double misalignmentFactor = gctx.get()->getMisalignmentFactor(layer); Acts::ActsSymMatrix<2> expandedCov = Acts::ActsSymMatrix<2>::Zero(); diff --git a/offline/packages/trackbase/alignmentTransformationContainer.cc b/offline/packages/trackbase/alignmentTransformationContainer.cc index aef2683729..09e7aee510 100644 --- a/offline/packages/trackbase/alignmentTransformationContainer.cc +++ b/offline/packages/trackbase/alignmentTransformationContainer.cc @@ -17,20 +17,20 @@ bool alignmentTransformationContainer::use_alignment = false; alignmentTransformationContainer::alignmentTransformationContainer() { - for ( const auto id : { TrkrDefs::mvtxId, TrkrDefs::inttId, TrkrDefs::tpcId, TrkrDefs::micromegasId }) + for ( uint8_t layer = 0; layer < 57; layer++) { - m_misalignmentFactor.insert(std::make_pair(id, 1.)); + m_misalignmentFactor.insert(std::make_pair(layer, 1.)); } } -void alignmentTransformationContainer::setMisalignmentFactor(uint8_t id, double factor) +void alignmentTransformationContainer::setMisalignmentFactor(uint8_t layer, double factor) { - auto it = m_misalignmentFactor.find(id); + auto it = m_misalignmentFactor.find(layer); if(it != m_misalignmentFactor.end()) { it->second = factor; return; } - std::cout << "You provided a nonexistent TrkrDefs::TrkrId in alignmentTransformationContainer::setMisalignmentFactor..." + std::cout << "You provided a nonexistent layer in alignmentTransformationContainer::setMisalignmentFactor..." << std::endl; } void alignmentTransformationContainer::Reset() diff --git a/offline/packages/trackbase/alignmentTransformationContainer.h b/offline/packages/trackbase/alignmentTransformationContainer.h index c9dac5e171..e885aa4483 100644 --- a/offline/packages/trackbase/alignmentTransformationContainer.h +++ b/offline/packages/trackbase/alignmentTransformationContainer.h @@ -41,8 +41,8 @@ class alignmentTransformationContainer : public Acts::GeometryContext void addTransform(Acts::GeometryIdentifier, Acts::Transform3); Acts::Transform3& getTransform(Acts::GeometryIdentifier id); const std::vector>& getMap() const; - void setMisalignmentFactor(uint8_t id, double factor); - const double& getMisalignmentFactor(uint8_t id) const { return m_misalignmentFactor.find(id)->second; } + void setMisalignmentFactor(uint8_t layer, double factor); + const double& getMisalignmentFactor(uint8_t layer) const { return m_misalignmentFactor.find(layer)->second; } static bool use_alignment; private: @@ -53,7 +53,7 @@ class alignmentTransformationContainer : public Acts::GeometryContext std::vector< std::vector> transformVec; - /// Map of TrkrDefs::TrkrId to misalignment factor + /// Map of TrkrDefs::Layer to misalignment factor std::map m_misalignmentFactor; ClassDef(alignmentTransformationContainer,1); diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 08138d8062..c3405a7bec 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -174,9 +174,9 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_actsGeometry->set_drift_velocity(m_drift_velocity); alignment_transformation.createMap(topNode); - for(auto& [id, factor] : m_misalignmentFactor) + for(auto& [layer, factor] : m_misalignmentFactor) { - alignment_transformation.misalignmentFactor(id, factor); + alignment_transformation.misalignmentFactor(layer, factor); } // print diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 234bb2fa19..8a98d0cd8d 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -119,16 +119,16 @@ class MakeActsGeometry : public SubsysReco } - void misalignmentFactor(TrkrDefs::TrkrId id, const double misalignment) + void misalignmentFactor(uint8_t layer, const double misalignment) { - auto it = m_misalignmentFactor.find(id); + auto it = m_misalignmentFactor.find(layer); if(it != m_misalignmentFactor.end()) { it->second = misalignment; return; } - std::cout << "Passed an unknown trkr id, misalignment factor will not be set for " << id << std::endl; + std::cout << "Passed an unknown trkr layer, misalignment factor will not be set for " << layer << std::endl; } double getSurfStepPhi() {return m_surfStepPhi;} @@ -209,7 +209,7 @@ class MakeActsGeometry : public SubsysReco TGeoManager* m_geoManager = nullptr; bool m_useField = true; - std::map m_misalignmentFactor; + std::map m_misalignmentFactor; /// Several maps that connect Acts world to sPHENIX G4 world std::map m_clusterNodeMap; From d86d5bca4c94ff1bb5709ca37dcf48026baf9b08 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Tue, 23 May 2023 16:29:53 -0400 Subject: [PATCH 434/468] Adding Writing TRKR_HITSET to DST --- offline/packages/rawtodst/TPCMap.cc | 16 ++ offline/packages/rawtodst/TPCMap.h | 1 + .../rawtodst/macros/Fun4All_ReadTPCHits.C | 27 ++- offline/packages/rawtodst/tpc_hits.cc | 228 ++++++++++-------- offline/packages/rawtodst/tpc_hits.h | 10 + 5 files changed, 184 insertions(+), 98 deletions(-) diff --git a/offline/packages/rawtodst/TPCMap.cc b/offline/packages/rawtodst/TPCMap.cc index 81797ac828..20985104bf 100644 --- a/offline/packages/rawtodst/TPCMap.cc +++ b/offline/packages/rawtodst/TPCMap.cc @@ -174,6 +174,22 @@ unsigned int TPCMap::getLayer(const unsigned int FEE, const unsigned int FEEChan return itr->second.layer; } +unsigned int TPCMap::getPad(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const +{ + if (FEE >= 26 || FEEChannel > 255) + { + return 0.; + } + unsigned int key = 256 * FEE + FEEChannel; + + std::map::const_iterator itr = tmap.find(key); + if (itr == tmap.end()) + { + return -100; + } + return itr->second.padnr; +} + double TPCMap::getR(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const { if (FEE >= 26 || FEEChannel > 255) diff --git a/offline/packages/rawtodst/TPCMap.h b/offline/packages/rawtodst/TPCMap.h index ebd0c54a11..9dc230aec1 100644 --- a/offline/packages/rawtodst/TPCMap.h +++ b/offline/packages/rawtodst/TPCMap.h @@ -12,6 +12,7 @@ class TPCMap virtual ~TPCMap() = default; virtual unsigned int getLayer(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; + virtual unsigned int getPad(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; virtual double getR(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; virtual double getPhi(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; virtual void setMapNames(const std::string &r1, const std::string &r2, const std::string &r3); diff --git a/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C b/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C index f3923c3482..aee4433e7f 100644 --- a/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C +++ b/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C @@ -1,9 +1,16 @@ #pragma once + +#include + #include #include #include +#include +#include + + #include #include @@ -19,7 +26,12 @@ R__LOAD_LIBRARY(rawtodst.so) // cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libfun4allraw.so) -void Fun4All_ReadTPCHits( const int nEvents = 1, const string &fname = "/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc00_pedestal-00010305-0000.prdf",const string &foutputname = "./Files/hists_G4Hits_sHijing_0-12fm_000000_001000.root" ){ +void Fun4All_ReadTPCHits( + const int nEvents = 1, + const string &fname = "/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc01_pedestal-00010305-0000.prdf", + const string &outputFile = "./DSTFile.root", + const string &outdir = "." ) + { /////////////////////////////////////////// // Make the Server @@ -36,7 +48,20 @@ void Fun4All_ReadTPCHits( const int nEvents = 1, const string &fname = "/spheni // this (DST) input manager just drives the event loop Fun4AllPrdfInputManager *in = new Fun4AllPrdfInputManager("PRDF1"); in->AddFile(inputFileName); + //in->AddFile("/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc01_pedestal-00010305-0000.prdf"); se->registerInputManager(in); + + + Enable::DSTOUT = true; + Enable::DSTOUT_COMPRESS = false; + DstOut::OutputDir = outdir; + DstOut::OutputFile = outputFile; + + if (Enable::DSTOUT) + { + string FullOutFile = DstOut::OutputDir + "/" + DstOut::OutputFile; + Fun4AllDstOutputManager *out = new Fun4AllDstOutputManager("DSTOUT", FullOutFile); + } if (nEvents <= 0) { return; diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index 1650bb0e43..1b5b6f5b48 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -24,21 +25,26 @@ #include +#include +#include //____________________________________________________________________________.. tpc_hits::tpc_hits(const std::string &name) : SubsysReco(name) -{ + , hm(nullptr) + , _filename("./outputfile.root") + { std::cout << "tpc_hits::tpc_hits(const std::string &name)" << std::endl; starting_BCO = -1; rollover_value = 0; current_BCOBIN = 0; - M.setMapNames("AutoPad-R1-RevA.sch.ChannelMapping.csv", "AutoPad-R3-RevA.sch.ChannelMapping.csv", "AutoPad-R2-RevA-Pads.sch.ChannelMapping.csv"); + M.setMapNames("AutoPad-R1-RevA.sch.ChannelMapping.csv", "AutoPad-R2-RevA-Pads.sch.ChannelMapping.csv", "AutoPad-R3-RevA.sch.ChannelMapping.csv"); } //____________________________________________________________________________.. tpc_hits::~tpc_hits() { + delete hm; std::cout << "tpc_hits::~tpc_hits() Calling dtor" << std::endl; } @@ -46,6 +52,12 @@ tpc_hits::~tpc_hits() int tpc_hits::Init(PHCompositeNode * /*topNode*/) { std::cout << "tpc_hits::Init(PHCompositeNode *topNode) Initializing" << std::endl; + hm = new Fun4AllHistoManager("HITHIST"); + + _h_hit_XY = new TH2F("_h_hit_XY" ,"_h_hit_XY;X, [m];Y, [m]", 400, -800, 800, 400, -800, 800); + + hm->registerHisto(_h_hit_XY ); + return Fun4AllReturnCodes::EVENT_OK; } @@ -110,116 +122,136 @@ int tpc_hits::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::DISCARDEVENT; } - Packet *p = _event->getPacket(4000); // check all possible TPC packets that we need to analyze + int sector = -1; + for (int packet = 4000; packet<=4230; packet+=10) { std::cout << "tpc_hits:: Packet: "<< packet << " processing" << std::endl; - Packet *p_tmp = _event->getPacket(packet); - - if (!p_tmp) + Packet *p = _event->getPacket(packet); + + sector++; + + int side = 0; + if(sector>11) side=1; + if (p) { - std::cout << "tpc_hits:: Event getPacket: "<< packet << " IS NOT FOUND" << std::endl; - //return Fun4AllReturnCodes::DISCARDEVENT; - }else{ - //p = _event->getPacket(packet); std::cout << "tpc_hits:: Event getPacket: "<< packet << " FOUND!!!" << std::endl; - + }else{ + continue; } - } - int nr_of_waveforms = p->iValue(0, "NR_WF"); - for (auto &l : m_hitset) - { - l = new TrkrHitSetv1(); + + //if(current_packet==0){ + // std::cout << "tpc_hits:: Event getPacket DID NOT FOUND PACKET!!!" << std::endl; + // return Fun4AllReturnCodes::DISCARDEVENT; + //} + + //Packet *p = _event->getPacket(current_packet); - int wf; - for (wf = 0; wf < nr_of_waveforms; wf++) + int nr_of_waveforms = p->iValue(0, "NR_WF"); + + for (auto &l : m_hitset) { - int current_BCO = p->iValue(wf, "BCO") + rollover_value; + l = new TrkrHitSetv1(); - if (starting_BCO < 0) + int wf; + for (wf = 0; wf < nr_of_waveforms; wf++) { - starting_BCO = current_BCO; - } + int current_BCO = p->iValue(wf, "BCO") + rollover_value; + + if (starting_BCO < 0) + { + starting_BCO = current_BCO; + } + + if (current_BCO < starting_BCO) // we have a rollover + { + rollover_value += 0x100000; + current_BCO = p->iValue(wf, "BCO") + rollover_value; + starting_BCO = current_BCO; + current_BCOBIN++; + } + int sampa_nr = p->iValue(wf, "SAMPAADDRESS"); + int channel = p->iValue(wf, "CHANNEL"); + + int fee = p->iValue(wf, "FEE"); + //int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); + //int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); + //int checksum = p->iValue(wf, "CHECKSUM"); + //int checksumError = p->iValue(wf, "CHECKSUMERROR"); + int samples = p->iValue( wf, "SAMPLES" ); + int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; + int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; + + //std::cout << "tpc_hits::Process_Event SAMPAADDRESS " << sampa_nr << std::endl; + //std::cout << "tpc_hits::Process_Event Chn " << channel << std::endl; + int layer; + if (channel < 128) + { + layer = sampa_nr * 2; + } + else + { + layer = sampa_nr * 2 + 1; + } + m_hit = new TrkrHitv2(); + + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); + TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); + + // setting the mapp of the FEE + int feeM = FEE_map[fee]-1; + if(FEE_R[fee]==2) feeM += 6; + if(FEE_R[fee]==3) feeM += 14; + + double R = M.getR(feeM, channel); + double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; + + //std::cout << "tpc_hits::Process_Event Samples "<< samples + //<<" Chn:"<< channel + //<<" layer: " << layer + //<< " sampa: "<< sampa_nr + //<< " fee: "<< fee + //<< " Mapped fee: "<< feeM + //<< " sampaAddress: "<< sampaAddress + //<< " sampaChannel: "<< sampaChannel + //<< " checksum: "<< checksum + //<< " checksumError: "<< checksumError + + //<< " hitsetkey "<< tpcHitSetKey + //<< " R = " << R + //<< " phi = " << phi + //<< std::endl; + for (int s = 0; s < samples; s++) + { + int pad = 0; + int t = s + 2 * (current_BCO - starting_BCO); + int adc = p->iValue(wf,s); + // generate hit key + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); + // find existing hit, or create + //std::cout << "| " << hitkey << " "<< adc; //<< std::endl; + m_hit = hitsetit->second->getHit(hitkey); + + if (!m_hit) + { + // create a new one + m_hit = new TrkrHitv2(); + hitsetit->second->addHitSpecificKey(hitkey, m_hit); + } + // // create hit, assign adc and insert in hitset + m_hit->setAdc(adc); + _h_hit_XY->Fill(R*cos(phi),R*sin(phi),adc); + // hitsetit->second->addHitSpecificKey(hitkey, hit); + } + //std::cout << std::endl; - if (current_BCO < starting_BCO) // we have a rollover - { - rollover_value += 0x100000; - current_BCO = p->iValue(wf, "BCO") + rollover_value; - starting_BCO = current_BCO; - current_BCOBIN++; - } - int sampa_nr = p->iValue(wf, "SAMPAADDRESS"); - int channel = p->iValue(wf, "CHANNEL"); - - int fee = p->iValue(wf, "FEE"); - int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); - int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); - int checksum = p->iValue(wf, "CHECKSUM"); - int checksumError = p->iValue(wf, "CHECKSUMERROR"); - int samples = p->iValue( wf, "SAMPLES" ); - - - - //std::cout << "tpc_hits::Process_Event SAMPAADDRESS " << sampa_nr << std::endl; - //std::cout << "tpc_hits::Process_Event Chn " << channel << std::endl; - int layer; - if (channel < 128) - { - layer = sampa_nr * 2; - } - else - { - layer = sampa_nr * 2 + 1; } - m_hit = new TrkrHitv2(); - // mhit->setAdc( - int sector = 0; - int side = 0; - //std::cout << "tpc_hits::Process_Event Chn 1" << std::endl; - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); - //std::cout << "tpc_hits::Process_Event Chn 2" << std::endl; - TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); - - - std::cout << "tpc_hits::Process_Event Samples "<< samples <<"Chn:"<< channel - <<" layer: " << layer - << " sampa: "<< sampa_nr - << " fee: "<< fee - << " sampaAddress: "<< sampaAddress - << " sampaChannel: "<< sampaChannel - << " checksum: "<< checksum - << " checksumError: "<< checksumError - - << " hitsetkey "<< tpcHitSetKey - - << std::endl; - //for( int is = 0 ; is < samples ; is++ ) - //{ - // p->iValue(wf,is); - //} - - //std::cout << "tpc_hits::Process_Event Chn 3" << std::endl; - for (int s = 0; s < samples; s++) - { - unsigned short pad = 0; - unsigned short t = s + 2 * (current_BCO - starting_BCO); - std::cout << "current_BCO - starting_BCO="<< current_BCO <<"-"<< starting_BCO<<"=" << s + 2 * (current_BCO - starting_BCO) << std::endl; - // generate hit key - //TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(pad, t);//s + 2 * (current_BCO - starting_BCO)); - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); - // find existing hit, or create - std::cout << "| " << hitkey << " "<< p->iValue(wf,s) ; - m_hit = hitsetit->second->getHit(hitkey); - // // create hit, assign adc and insert in hitset - m_hit->setAdc(0+s); - // hitsetit->second->addHitSpecificKey(hitkey, hit); - } - std::cout << std::endl; - } - } + + }// End of run over packets + // we skip the mapping to real pads at first. We just say // that we get 16 rows (segment R2) with 128 pads // so each FEE fills 2 rows. Not right, but one step at a time. @@ -245,6 +277,8 @@ int tpc_hits::EndRun(const int runnumber) int tpc_hits::End(PHCompositeNode * /*topNode*/) { std::cout << "tpc_hits::End(PHCompositeNode *topNode) This is the End..." << std::endl; + hm->dumpHistos(_filename, "RECREATE"); + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/rawtodst/tpc_hits.h b/offline/packages/rawtodst/tpc_hits.h index 95d8d445fb..7bdcacaa0b 100644 --- a/offline/packages/rawtodst/tpc_hits.h +++ b/offline/packages/rawtodst/tpc_hits.h @@ -15,9 +15,11 @@ #include class PHCompositeNode; +class Fun4AllHistoManager; class TrkrHitSetContainer; class TrkrHitSet; class TrkrHit; +class TH2; class tpc_hits : public SubsysReco { @@ -55,6 +57,9 @@ class tpc_hits : public SubsysReco void Print(const std::string &what = "ALL") const override; protected: + Fun4AllHistoManager *hm = nullptr; + std::string _filename; + static const int layercount = 16; static const int layeroffset = 7 + 16; @@ -69,6 +74,11 @@ class tpc_hits : public SubsysReco int starting_BCO; int rollover_value; int current_BCOBIN; + + private: + + TH2* _h_hit_XY = nullptr; + }; #endif // TPC_HITS_H From acc12b639ea4529e70e3d153b0278e24d84d670e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 May 2023 22:13:30 -0400 Subject: [PATCH 435/468] updated for new Micromegas packets --- offline/packages/micromegas/MicromegasDefs.h | 7 +- .../packages/micromegas/MicromegasMapping.cc | 4 +- .../MicromegasRawDataCalibration.cc | 91 +++++----- .../micromegas/MicromegasRawDataDecoder.cc | 163 +++++++++--------- .../micromegas/MicromegasRawDataEvaluation.cc | 106 ++++++------ 5 files changed, 187 insertions(+), 184 deletions(-) diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index 6440c7222a..45611aa7f5 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -11,6 +11,8 @@ #include +#include + namespace MicromegasDefs { @@ -91,8 +93,9 @@ namespace MicromegasDefs s*/ uint8_t getTileId(TrkrDefs::cluskey); - //! TPOT packet id - static constexpr unsigned int m_packet_id = 5001; + //! TPOT packet ids + static constexpr int m_npackets = 2; + static constexpr std::array m_packet_ids = {5000, 5001}; //! number of channels per fee board static constexpr int m_nchannels_fee = 256; diff --git a/offline/packages/micromegas/MicromegasMapping.cc b/offline/packages/micromegas/MicromegasMapping.cc index 437e15afba..e79c2a509b 100644 --- a/offline/packages/micromegas/MicromegasMapping.cc +++ b/offline/packages/micromegas/MicromegasMapping.cc @@ -89,7 +89,9 @@ m_detectors( { {6, MicromegasDefs::genHitSetKey(55, MicromegasDefs::SegmentationType::SEGMENTATION_PHI, 0 ), "sec21.0", "R3.3", "M5P", "SCOP" }, {8, MicromegasDefs::genHitSetKey(56, MicromegasDefs::SegmentationType::SEGMENTATION_Z, 0 ), "sec21.1", "R3.4", "M5Z", "SCOZ" }, {9, MicromegasDefs::genHitSetKey(55, MicromegasDefs::SegmentationType::SEGMENTATION_PHI, 1 ), "sec21.2", "R3.5", "M8P", "SCIP" }, - {10, MicromegasDefs::genHitSetKey(56, MicromegasDefs::SegmentationType::SEGMENTATION_Z, 1 ), "sec21.3", "R3.6", "M8Z", "SCIZ" }, + /* {10, MicromegasDefs::genHitSetKey(56, MicromegasDefs::SegmentationType::SEGMENTATION_Z, 1 ), "sec21.3", "R3.6", "M8Z", "SCIZ" }, */ + // updated after fiber swapping on May 23, to fix flaky initialization of the FEE + {23, MicromegasDefs::genHitSetKey(56, MicromegasDefs::SegmentationType::SEGMENTATION_Z, 1 ), "sec21.3", "R3.9", "M8Z", "SCIZ" }, {24, MicromegasDefs::genHitSetKey(55, MicromegasDefs::SegmentationType::SEGMENTATION_PHI, 6 ), "sec22.0", "R3.8", "M6P", "SWIP" }, {25, MicromegasDefs::genHitSetKey(56, MicromegasDefs::SegmentationType::SEGMENTATION_Z, 6 ), "sec22.1", "R3.8", "M6Z", "SWIZ" }, diff --git a/offline/packages/micromegas/MicromegasRawDataCalibration.cc b/offline/packages/micromegas/MicromegasRawDataCalibration.cc index 6e82703180..abe3854bb2 100644 --- a/offline/packages/micromegas/MicromegasRawDataCalibration.cc +++ b/offline/packages/micromegas/MicromegasRawDataCalibration.cc @@ -53,58 +53,55 @@ int MicromegasRawDataCalibration::process_event(PHCompositeNode *topNode) { return Fun4AllReturnCodes::DISCARDEVENT; } - // get TPOT packet number - /* - * for now it is the same packet number as the TPC: 4001. - * To be fixed at a later stage. - * check with Martin Purschke - */ - std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); - if( !packet ) + // loop over TPOT packets + for( const auto& packet_id:MicromegasDefs::m_packet_ids ) { - // no data - std::cout << "MicromegasRawDataCalibration::process_event - event contains no TPOT data" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - // get number of datasets (also call waveforms) - const auto n_waveforms = packet->iValue(0, "NR_WF" ); - if( Verbosity() ) - { std::cout << "MicromegasRawDataCalibration::process_event - n_waveforms: " << n_waveforms << std::endl; } - - for( int i=0; iiValue( i, "CHANNEL" ); - int fee = packet->iValue(i, "FEE" ); - int samples = packet->iValue( i, "SAMPLES" ); - if( Verbosity() ) + std::unique_ptr packet( event->getPacket(packet_id) ); + if( !packet ) { - std::cout - << "MicromegasRawDataCalibration::process_event -" - << " waveform: " << i - << " fee: " << fee - << " channel: " << channel - << " samples: " << samples - << std::endl; + // no data + std::cout << "MicromegasRawDataCalibration::process_event - event contains no TPOT data" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; } - - // find relevant profile histogram - TProfile* profile = nullptr; - auto piter = m_profile_map.lower_bound( fee ); - if( piter == m_profile_map.end() || fee < piter->first ) - { - // create and insert - profile = new TProfile( Form( "h_adc_channel_%i", fee ), "ADC vs channel;channel;adc", MicromegasDefs::m_nchannels_fee, 0, MicromegasDefs::m_nchannels_fee ); - profile->SetErrorOption( "s" ); - m_profile_map.insert( piter, std::make_pair( fee, profile ) ); - } else profile = piter->second; - - // fill - for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) - { profile->Fill( channel, packet->iValue(i,is) ); } + // get number of datasets (also call waveforms) + const auto n_waveforms = packet->iValue(0, "NR_WF" ); + if( Verbosity() ) + { std::cout << "MicromegasRawDataCalibration::process_event - n_waveforms: " << n_waveforms << std::endl; } + + for( int i=0; iiValue( i, "CHANNEL" ); + int fee = packet->iValue(i, "FEE" ); + int samples = packet->iValue( i, "SAMPLES" ); + if( Verbosity() ) + { + std::cout + << "MicromegasRawDataCalibration::process_event -" + << " waveform: " << i + << " fee: " << fee + << " channel: " << channel + << " samples: " << samples + << std::endl; + } + + // find relevant profile histogram + TProfile* profile = nullptr; + auto piter = m_profile_map.lower_bound( fee ); + if( piter == m_profile_map.end() || fee < piter->first ) + { + // create and insert + profile = new TProfile( Form( "h_adc_channel_%i", fee ), "ADC vs channel;channel;adc", MicromegasDefs::m_nchannels_fee, 0, MicromegasDefs::m_nchannels_fee ); + profile->SetErrorOption( "s" ); + m_profile_map.insert( piter, std::make_pair( fee, profile ) ); + } else profile = piter->second; + + // fill + for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) + { profile->Fill( channel, packet->iValue(i,is) ); } + + } } - return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/micromegas/MicromegasRawDataDecoder.cc b/offline/packages/micromegas/MicromegasRawDataDecoder.cc index d83c33a1b6..c13eaec506 100644 --- a/offline/packages/micromegas/MicromegasRawDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasRawDataDecoder.cc @@ -92,101 +92,98 @@ int MicromegasRawDataDecoder::process_event(PHCompositeNode *topNode) if(event->getEvtType() >= 8) { return Fun4AllReturnCodes::DISCARDEVENT; } - // get TPOT packet number - /* - * for now it is the same packet number as the TPC: 4001. - * To be fixed at a later stage. - * check with Martin Purschke - */ - std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); - if( !packet ) + // loop over TPOT packets + for( const auto& packet_id:MicromegasDefs::m_packet_ids ) { - // no data - std::cout << "MicromegasRawDataDecoder::process_event - event contains no TPOT data" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - // get number of datasets (also call waveforms) - const auto n_waveforms = packet->iValue(0, "NR_WF" ); - if( Verbosity() ) - { std::cout << "MicromegasRawDataDecoder::process_event - n_waveforms: " << n_waveforms << std::endl; } - for( int i=0; iiValue( i, "CHANNEL" ); - int fee = packet->iValue(i, "FEE" ); - int samples = packet->iValue( i, "SAMPLES" ); - if( Verbosity() ) + std::unique_ptr packet( event->getPacket(packet_id) ); + if( !packet ) { - std::cout - << "MicromegasRawDataDecoder::process_event -" - << " waveform: " << i - << " fee: " << fee - << " channel: " << channel - << " samples: " << samples - << std::endl; + // no data + std::cout << "MicromegasRawDataDecoder::process_event - event contains no TPOT data" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; } - - // get channel rms and pedestal from calibration data - const double pedestal = m_calibration_data.get_pedestal( fee, channel ); - const double rms = m_calibration_data.get_rms( fee, channel ); - - // a rms of zero means the calibration has failed. the data is unusable - if( rms <= 0 ) continue; - - // loop over samples find maximum - std::vector adc; - for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) - { adc.push_back( packet->iValue( i, is ) ); } - - if( adc.empty() ) continue; - - // get max adc value in range - /* TODO: use more advanced signal processing */ - auto max_adc = *std::max_element( adc.begin(), adc.end() ); - - // subtract pedestal - max_adc -= pedestal; - // compare to threshold - if( max_adc > m_n_sigma * rms ) + // get number of datasets (also call waveforms) + const auto n_waveforms = packet->iValue(0, "NR_WF" ); + if( Verbosity() ) + { std::cout << "MicromegasRawDataDecoder::process_event - n_waveforms: " << n_waveforms << std::endl; } + for( int i=0; ifindOrAddHitSet(hitsetkey); - - // generate hit key - const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip); - - // find existing hit, or create - auto hit = hitset_it->second->getHit(hitkey); - if( hit ) + auto channel = packet->iValue( i, "CHANNEL" ); + int fee = packet->iValue(i, "FEE" ); + int samples = packet->iValue( i, "SAMPLES" ); + if( Verbosity() ) { - std::cout << "MicromegasRawDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; - continue; + std::cout + << "MicromegasRawDataDecoder::process_event -" + << " waveform: " << i + << " fee: " << fee + << " channel: " << channel + << " samples: " << samples + << std::endl; } - - // create hit, assign adc and insert in hitset - hit = new TrkrHitv2; - hit->setAdc( max_adc ); - hitset_it->second->addHitSpecificKey(hitkey, hit); - // increment counter - ++m_hitcounts[hitsetkey]; + // get channel rms and pedestal from calibration data + const double pedestal = m_calibration_data.get_pedestal( fee, channel ); + const double rms = m_calibration_data.get_rms( fee, channel ); + + // a rms of zero means the calibration has failed. the data is unusable + if( rms <= 0 ) continue; + + // loop over samples find maximum + std::vector adc; + for( int is = std::max( m_sample_min,0 ); is < std::min( m_sample_max,samples ); ++ is ) + { adc.push_back( packet->iValue( i, is ) ); } + + if( adc.empty() ) continue; + + // get max adc value in range + /* TODO: use more advanced signal processing */ + auto max_adc = *std::max_element( adc.begin(), adc.end() ); + + // subtract pedestal + max_adc -= pedestal; + + // compare to threshold + if( max_adc > m_n_sigma * rms ) + { + + // map fee and channel to physical hitsetid and physical strip + // get hitset key matching this fee + const TrkrDefs::hitsetkey hitsetkey = m_mapping.get_hitsetkey( fee ); + if( !hitsetkey ) continue; + + // get matching physical strip + int strip = m_mapping.get_physical_strip( fee, channel ); + if( strip < 0 ) continue; + + // get matching hitset + const auto hitset_it = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); + + // generate hit key + const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip); + + // find existing hit, or create + auto hit = hitset_it->second->getHit(hitkey); + if( hit ) + { + std::cout << "MicromegasRawDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; + continue; + } + + // create hit, assign adc and insert in hitset + hit = new TrkrHitv2; + hit->setAdc( max_adc ); + hitset_it->second->addHitSpecificKey(hitkey, hit); + + // increment counter + ++m_hitcounts[hitsetkey]; + + } } - } - return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluation.cc b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc index d9eb66ea33..22336dd351 100644 --- a/offline/packages/micromegas/MicromegasRawDataEvaluation.cc +++ b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc @@ -62,7 +62,12 @@ int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) {6, 2}, // SCOP {8, 3}, // SCOZ {9, 4}, // SCIP - {10, 5}, // SCIZ + + // old mapping until May 23 + /* it is ok to keep it here, to be able to process older files */ + {10, 5}, // SCIZ + // updated after May 23 + {23, 5}, // SCIZ {24, 6}, // SWIP {25, 7}, // SWIZ @@ -85,61 +90,60 @@ int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) if(event->getEvtType() >= 8) { return Fun4AllReturnCodes::DISCARDEVENT; } - // get TPOT packet number - /* - * for now it is the same packet number as the TPC: 4001. - * To be fixed at a later stage. - * check with Martin Purschke - */ - std::unique_ptr packet( event->getPacket(MicromegasDefs::m_packet_id) ); - if( !packet ) - { - // no data - std::cout << "MicromegasRawDataEvaluation::process_event - event contains no TPOT data" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - m_container->Reset(); - - // get number of datasets (also call waveforms) - const auto n_waveforms = packet->iValue(0, "NR_WF" ); - m_container->n_waveforms = n_waveforms; - if( Verbosity() ) - { std::cout << "MicromegasRawDataEvaluation::process_event - n_waveforms: " << n_waveforms << std::endl; } - - for( int i=0; iiValue( i, "CHANNEL" ); - const unsigned short fee = packet->iValue(i, "FEE" ); - - // get hitsetkey, layer and tile - const auto hitsetkey = m_mapping.get_hitsetkey(fee); - const unsigned short layer = TrkrDefs::getLayer( hitsetkey ); - const unsigned short tile = MicromegasDefs::getTileId( hitsetkey ); - - // get detector index and absolute channel number - const unsigned short det_index = fee_map[fee]; - const unsigned short absolute_channel = channel + det_index*MicromegasDefs::m_nchannels_fee; - - // get number of samples and loop - const unsigned short samples = packet->iValue( i, "SAMPLES" ); - for( unsigned short is = 0; is < samples; ++is ) + std::unique_ptr packet( event->getPacket(packet_id) ); + if( !packet ) { - unsigned short adc = packet->iValue(i,is); - m_container->samples.push_back( - Sample{ - .fee_id = fee, - .layer = layer, - .tile = tile, - .channel = channel, - .absolute_channel = absolute_channel, - .sample = is, - .adc = adc - }); + // no data + std::cout << "MicromegasRawDataEvaluation::process_event - event contains no TPOT data" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; } + m_container->Reset(); + + // get number of datasets (also call waveforms) + const auto n_waveforms = packet->iValue(0, "NR_WF" ); + m_container->n_waveforms = n_waveforms; + if( Verbosity() ) + { std::cout << "MicromegasRawDataEvaluation::process_event - n_waveforms: " << n_waveforms << std::endl; } + + for( int i=0; iiValue( i, "CHANNEL" ); + const unsigned short fee = packet->iValue(i, "FEE" ); + + // get hitsetkey, layer and tile + const auto hitsetkey = m_mapping.get_hitsetkey(fee); + const unsigned short layer = TrkrDefs::getLayer( hitsetkey ); + const unsigned short tile = MicromegasDefs::getTileId( hitsetkey ); + + // get detector index and absolute channel number + const unsigned short det_index = fee_map[fee]; + const unsigned short absolute_channel = channel + det_index*MicromegasDefs::m_nchannels_fee; + + // get number of samples and loop + const unsigned short samples = packet->iValue( i, "SAMPLES" ); + for( unsigned short is = 0; is < samples; ++is ) + { + unsigned short adc = packet->iValue(i,is); + m_container->samples.push_back( + Sample + { + .fee_id = fee, + .layer = layer, + .tile = tile, + .channel = channel, + .absolute_channel = absolute_channel, + .sample = is, + .adc = adc + }); + } + + } } - + m_evaluation_tree->Fill(); return Fun4AllReturnCodes::EVENT_OK; From 523c9d4a299eeffa87976e642f7b02c8c0322b73 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 May 2023 22:35:50 -0400 Subject: [PATCH 436/468] - added packet_id to evaluation - do not reset container between packets --- .../micromegas/MicromegasRawDataEvaluation.cc | 13 +++++++------ .../micromegas/MicromegasRawDataEvaluation.h | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluation.cc b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc index 22336dd351..89fdd647dd 100644 --- a/offline/packages/micromegas/MicromegasRawDataEvaluation.cc +++ b/offline/packages/micromegas/MicromegasRawDataEvaluation.cc @@ -90,6 +90,8 @@ int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) if(event->getEvtType() >= 8) { return Fun4AllReturnCodes::DISCARDEVENT; } + m_container->Reset(); + // loop over TPOT packets for( const auto& packet_id:MicromegasDefs::m_packet_ids ) { @@ -97,22 +99,20 @@ int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) if( !packet ) { // no data - std::cout << "MicromegasRawDataEvaluation::process_event - event contains no TPOT data" << std::endl; + std::cout << "MicromegasRawDataEvaluation::process_event - packet " << packet_id << " not found." << std::endl; return Fun4AllReturnCodes::EVENT_OK; } - - m_container->Reset(); - + // get number of datasets (also call waveforms) const auto n_waveforms = packet->iValue(0, "NR_WF" ); m_container->n_waveforms = n_waveforms; if( Verbosity() ) - { std::cout << "MicromegasRawDataEvaluation::process_event - n_waveforms: " << n_waveforms << std::endl; } + { std::cout << "MicromegasRawDataEvaluation::process_event - packet: " << packet_id << " n_waveforms: " << n_waveforms << std::endl; } for( int i=0; iiValue( i, "CHANNEL" ); const unsigned short fee = packet->iValue(i, "FEE" ); + const unsigned short channel = packet->iValue( i, "CHANNEL" ); // get hitsetkey, layer and tile const auto hitsetkey = m_mapping.get_hitsetkey(fee); @@ -131,6 +131,7 @@ int MicromegasRawDataEvaluation::process_event(PHCompositeNode *topNode) m_container->samples.push_back( Sample { + .packet_id = packet_id, .fee_id = fee, .layer = layer, .tile = tile, diff --git a/offline/packages/micromegas/MicromegasRawDataEvaluation.h b/offline/packages/micromegas/MicromegasRawDataEvaluation.h index d52e276e91..bcc5cab00f 100644 --- a/offline/packages/micromegas/MicromegasRawDataEvaluation.h +++ b/offline/packages/micromegas/MicromegasRawDataEvaluation.h @@ -49,6 +49,7 @@ class MicromegasRawDataEvaluation : public SubsysReco class Sample { public: + unsigned int packet_id = 0; unsigned short fee_id = 0; unsigned short layer = 0; unsigned short tile = 0; From 3ca163d9c8047a233f786d64c823183f891592ff Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 24 May 2023 10:08:29 -0400 Subject: [PATCH 437/468] Latest version --- offline/packages/rawtodst/tpc_hits.cc | 43 +++++++++++++++++++-------- offline/packages/rawtodst/tpc_hits.h | 4 +-- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index 1b5b6f5b48..6a47c73436 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -75,8 +75,8 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) } // create hitset container if needed - m_hits = findNode::getClass(topNode, "TRKR_HITSET"); - if (!m_hits) + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + if (!hitsetcontainer) { std::cout << "tpc_hits::InitRun - creating TRKR_HITSET." << std::endl; @@ -90,8 +90,8 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) } // create container and add to the tree - m_hits = new TrkrHitSetContainerv1; - auto newNode = new PHIODataNode(m_hits, "TRKR_HITSET", "PHObject"); + hitsetcontainer = new TrkrHitSetContainerv1; + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); trkrnode->addNode(newNode); } topNode->print(); @@ -110,8 +110,14 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) int tpc_hits::process_event(PHCompositeNode *topNode) { std::cout << "tpc_hits::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + // load relevant nodes + // Get the TrkrHitSetContainer node + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + assert(trkrhitsetcontainer); Event *_event = findNode::getClass(topNode, "PRDF"); + assert( _event ); + if (_event == nullptr) { std::cout << "tpc_hits::Process_Event - Event not found" << std::endl; @@ -132,8 +138,10 @@ int tpc_hits::process_event(PHCompositeNode *topNode) sector++; + // Figure out which side int side = 0; if(sector>11) side=1; + if (p) { std::cout << "tpc_hits:: Event getPacket: "<< packet << " FOUND!!!" << std::endl; @@ -181,9 +189,10 @@ int tpc_hits::process_event(PHCompositeNode *topNode) //int checksum = p->iValue(wf, "CHECKSUM"); //int checksumError = p->iValue(wf, "CHECKSUMERROR"); int samples = p->iValue( wf, "SAMPLES" ); - int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; + //int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; - + // From Takao + int FEE_map[26]={3, 2, 5, 3, 4, 0, 2, 1, 3, 4, 5, 7, 6, 2, 0, 1, 0, 1, 4, 5, 11, 9, 10, 8, 6, 7}; //std::cout << "tpc_hits::Process_Event SAMPAADDRESS " << sampa_nr << std::endl; //std::cout << "tpc_hits::Process_Event Chn " << channel << std::endl; int layer; @@ -195,10 +204,10 @@ int tpc_hits::process_event(PHCompositeNode *topNode) { layer = sampa_nr * 2 + 1; } - m_hit = new TrkrHitv2(); TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); - TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); + //TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); + TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); // setting the mapp of the FEE int feeM = FEE_map[fee]-1; @@ -232,16 +241,24 @@ int tpc_hits::process_event(PHCompositeNode *topNode) TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); // find existing hit, or create //std::cout << "| " << hitkey << " "<< adc; //<< std::endl; - m_hit = hitsetit->second->getHit(hitkey); + //m_hit = hitsetit->second->getHit(hitkey); + auto hit = hitsetit->second->getHit(hitkey); - if (!m_hit) + //if (!m_hit) + //{ + if (!hit) { // create a new one - m_hit = new TrkrHitv2(); - hitsetit->second->addHitSpecificKey(hitkey, m_hit); + std::cout << "creating hitkey "<< hitkey <second->addHitSpecificKey(hitkey, m_hit); + hit = new TrkrHitv2(); + hit->setAdc(adc); + hitsetit->second->addHitSpecificKey(hitkey, hit); } // // create hit, assign adc and insert in hitset - m_hit->setAdc(adc); + //m_hit->setAdc(adc); + //hit->setAdc(adc); _h_hit_XY->Fill(R*cos(phi),R*sin(phi),adc); // hitsetit->second->addHitSpecificKey(hitkey, hit); } diff --git a/offline/packages/rawtodst/tpc_hits.h b/offline/packages/rawtodst/tpc_hits.h index 7bdcacaa0b..daa6a0aac2 100644 --- a/offline/packages/rawtodst/tpc_hits.h +++ b/offline/packages/rawtodst/tpc_hits.h @@ -63,9 +63,9 @@ class tpc_hits : public SubsysReco static const int layercount = 16; static const int layeroffset = 7 + 16; - TrkrHitSetContainer *m_hits = nullptr; + //TrkrHitSetContainer *m_hits = nullptr; TrkrHitSet *m_hitset[layercount] = {}; - TrkrHit *m_hit = nullptr; + //TrkrHit *m_hit = nullptr; // RawHitSetContainer *m_rawhits __attribute__ ((unused)) = nullptr; From fab8d0da400793b3dc32e727f55830ddb35a9a9e Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 24 May 2023 13:01:48 -0400 Subject: [PATCH 438/468] Remove macros directory --- .../rawtodst/macros/Fun4All_ReadTPCHits.C | 82 -------------- offline/packages/rawtodst/tpc_hits.cc | 106 ++++++++---------- offline/packages/rawtodst/tpc_hits.h | 14 +-- 3 files changed, 55 insertions(+), 147 deletions(-) delete mode 100644 offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C diff --git a/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C b/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C deleted file mode 100644 index aee4433e7f..0000000000 --- a/offline/packages/rawtodst/macros/Fun4All_ReadTPCHits.C +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include - -#include -#include - - -#include - -#include -//#include -#include - -#include - -// cppcheck-suppress unknownMacro -R__LOAD_LIBRARY(libfun4all.so) -// cppcheck-suppress unknownMacro -R__LOAD_LIBRARY(rawtodst.so) -// cppcheck-suppress unknownMacro -R__LOAD_LIBRARY(libfun4allraw.so) - -void Fun4All_ReadTPCHits( - const int nEvents = 1, - const string &fname = "/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc01_pedestal-00010305-0000.prdf", - const string &outputFile = "./DSTFile.root", - const string &outdir = "." ) - { - - /////////////////////////////////////////// - // Make the Server - ////////////////////////////////////////// - Fun4AllServer *se = Fun4AllServer::instance(); - tpc_hits *TPC_HITS_set = new tpc_hits(); - - se->registerSubsystem(TPC_HITS_set); - - gSystem->Load("libFROG"); - FROG *fr = new FROG(); - string inputFileName = fr->location(fname); - cout << "Next file:" << inputFileName << endl; - // this (DST) input manager just drives the event loop - Fun4AllPrdfInputManager *in = new Fun4AllPrdfInputManager("PRDF1"); - in->AddFile(inputFileName); - //in->AddFile("/sphenix/lustre01/sphnxpro/rawdata/commissioning/tpc/pedestal/TPC_ebdc01_pedestal-00010305-0000.prdf"); - se->registerInputManager(in); - - - Enable::DSTOUT = true; - Enable::DSTOUT_COMPRESS = false; - DstOut::OutputDir = outdir; - DstOut::OutputFile = outputFile; - - if (Enable::DSTOUT) - { - string FullOutFile = DstOut::OutputDir + "/" + DstOut::OutputFile; - Fun4AllDstOutputManager *out = new Fun4AllDstOutputManager("DSTOUT", FullOutFile); - } - if (nEvents <= 0) - { - return; - } - cout << endl << "Running over " << nEvents << " Events" << endl; - se->run(nEvents); - //} - cout << endl << "Calling End in Fun4All_ReadTPCHits.C" << endl; - se->End(); - - cout << endl << "All done, calling delete Fun4AllServer" << endl; - delete se; - - cout << endl << "gSystem->Exit(0)" << endl; - gSystem->Exit(0); - - -} \ No newline at end of file diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index 6a47c73436..47a1a5458d 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -149,12 +149,6 @@ int tpc_hits::process_event(PHCompositeNode *topNode) continue; } - - //if(current_packet==0){ - // std::cout << "tpc_hits:: Event getPacket DID NOT FOUND PACKET!!!" << std::endl; - // return Fun4AllReturnCodes::DISCARDEVENT; - //} - //Packet *p = _event->getPacket(current_packet); int nr_of_waveforms = p->iValue(0, "NR_WF"); @@ -184,17 +178,12 @@ int tpc_hits::process_event(PHCompositeNode *topNode) int channel = p->iValue(wf, "CHANNEL"); int fee = p->iValue(wf, "FEE"); - //int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); - //int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); - //int checksum = p->iValue(wf, "CHECKSUM"); - //int checksumError = p->iValue(wf, "CHECKSUMERROR"); int samples = p->iValue( wf, "SAMPLES" ); //int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; // From Takao int FEE_map[26]={3, 2, 5, 3, 4, 0, 2, 1, 3, 4, 5, 7, 6, 2, 0, 1, 0, 1, 4, 5, 11, 9, 10, 8, 6, 7}; - //std::cout << "tpc_hits::Process_Event SAMPAADDRESS " << sampa_nr << std::endl; - //std::cout << "tpc_hits::Process_Event Chn " << channel << std::endl; + int layer; if (channel < 128) { @@ -217,21 +206,27 @@ int tpc_hits::process_event(PHCompositeNode *topNode) double R = M.getR(feeM, channel); double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; - //std::cout << "tpc_hits::Process_Event Samples "<< samples - //<<" Chn:"<< channel - //<<" layer: " << layer - //<< " sampa: "<< sampa_nr - //<< " fee: "<< fee - //<< " Mapped fee: "<< feeM - //<< " sampaAddress: "<< sampaAddress - //<< " sampaChannel: "<< sampaChannel - //<< " checksum: "<< checksum - //<< " checksumError: "<< checksumError - - //<< " hitsetkey "<< tpcHitSetKey - //<< " R = " << R - //<< " phi = " << phi - //<< std::endl; + if( Verbosity() ) + { + int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); + int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); + int checksum = p->iValue(wf, "CHECKSUM"); + int checksumError = p->iValue(wf, "CHECKSUMERROR"); + std::cout << "tpc_hits::Process_Event Samples "<< samples + <<" Chn:"<< channel + <<" layer: " << layer + << " sampa: "<< sampa_nr + << " fee: "<< fee + << " Mapped fee: "<< feeM + << " sampaAddress: "<< sampaAddress + << " sampaChannel: "<< sampaChannel + << " checksum: "<< checksum + << " checksumError: "<< checksumError + << " hitsetkey "<< tpcHitSetKey + << " R = " << R + << " phi = " << phi + << std::endl; + } for (int s = 0; s < samples; s++) { int pad = 0; @@ -240,29 +235,24 @@ int tpc_hits::process_event(PHCompositeNode *topNode) // generate hit key TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); // find existing hit, or create - //std::cout << "| " << hitkey << " "<< adc; //<< std::endl; - //m_hit = hitsetit->second->getHit(hitkey); auto hit = hitsetit->second->getHit(hitkey); - //if (!m_hit) - //{ + // create hit, assign adc and insert in hitset if (!hit) { // create a new one - std::cout << "creating hitkey "<< hitkey <second->addHitSpecificKey(hitkey, m_hit); hit = new TrkrHitv2(); hit->setAdc(adc); hitsetit->second->addHitSpecificKey(hitkey, hit); } - // // create hit, assign adc and insert in hitset - //m_hit->setAdc(adc); - //hit->setAdc(adc); - _h_hit_XY->Fill(R*cos(phi),R*sin(phi),adc); + //else{ + // hit->setAdc(adc); // hitsetit->second->addHitSpecificKey(hitkey, hit); + //} + + _h_hit_XY->Fill(R*cos(phi),R*sin(phi),adc); + } - //std::cout << std::endl; } } @@ -277,18 +267,18 @@ int tpc_hits::process_event(PHCompositeNode *topNode) } //____________________________________________________________________________.. -int tpc_hits::ResetEvent(PHCompositeNode * /*topNode*/) -{ - std::cout << "tpc_hits::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} +//int tpc_hits::ResetEvent(PHCompositeNode * /*topNode*/) +//{ +// std::cout << "tpc_hits::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} //____________________________________________________________________________.. -int tpc_hits::EndRun(const int runnumber) -{ - std::cout << "tpc_hits::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} +//int tpc_hits::EndRun(const int runnumber) +//{ +// std::cout << "tpc_hits::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} //____________________________________________________________________________.. int tpc_hits::End(PHCompositeNode * /*topNode*/) @@ -300,14 +290,14 @@ int tpc_hits::End(PHCompositeNode * /*topNode*/) } //____________________________________________________________________________.. -int tpc_hits::Reset(PHCompositeNode * /*topNode*/) -{ - std::cout << "tpc_hits::Reset(PHCompositeNode *topNode) being Reset" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} +//int tpc_hits::Reset(PHCompositeNode * /*topNode*/) +//{ +// std::cout << "tpc_hits::Reset(PHCompositeNode *topNode) being Reset" << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} //____________________________________________________________________________.. -void tpc_hits::Print(const std::string &what) const -{ - std::cout << "tpc_hits::Print(const std::string &what) const Printing info for " << what << std::endl; -} +//void tpc_hits::Print(const std::string &what) const +//{ +// std::cout << "tpc_hits::Print(const std::string &what) const Printing info for " << what << std::endl; +//} diff --git a/offline/packages/rawtodst/tpc_hits.h b/offline/packages/rawtodst/tpc_hits.h index daa6a0aac2..07b1a18302 100644 --- a/offline/packages/rawtodst/tpc_hits.h +++ b/offline/packages/rawtodst/tpc_hits.h @@ -16,9 +16,9 @@ class PHCompositeNode; class Fun4AllHistoManager; -class TrkrHitSetContainer; -class TrkrHitSet; -class TrkrHit; +//class TrkrHitSetContainer; +//class TrkrHitSet; +//class TrkrHit; class TH2; class tpc_hits : public SubsysReco @@ -43,18 +43,18 @@ class tpc_hits : public SubsysReco int process_event(PHCompositeNode *topNode) override; /// Clean up internals after each event. - int ResetEvent(PHCompositeNode *topNode) override; + //int ResetEvent(PHCompositeNode *topNode) override; /// Called at the end of each run. - int EndRun(const int runnumber) override; + //int EndRun(const int runnumber) override; /// Called at the end of all processing. int End(PHCompositeNode *topNode) override; /// Reset - int Reset(PHCompositeNode * /*topNode*/) override; + //int Reset(PHCompositeNode * /*topNode*/) override; - void Print(const std::string &what = "ALL") const override; + //void Print(const std::string &what = "ALL") const override; protected: Fun4AllHistoManager *hm = nullptr; From 210674a51879f52add48bc87de57a26cad072876 Mon Sep 17 00:00:00 2001 From: Veronica Verkest Date: Wed, 24 May 2023 14:11:14 -0400 Subject: [PATCH 439/468] allow user to set the value of the event number --- simulation/g4simulation/g4eval/CaloEvaluator.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/simulation/g4simulation/g4eval/CaloEvaluator.h b/simulation/g4simulation/g4eval/CaloEvaluator.h index 9425681e44..a239a71a26 100644 --- a/simulation/g4simulation/g4eval/CaloEvaluator.h +++ b/simulation/g4simulation/g4eval/CaloEvaluator.h @@ -38,6 +38,13 @@ class CaloEvaluator : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; + // allow user to set the value of the event number + // useful for condor simulation submissions + // must be called after Init() + void set_event(int ievent) { + _ievent = ievent; + } + void set_strict(bool b) { _strict = b; } // funtions to limit the tracing to only part of the event --------- // and speed up the evaluation From 2b1085d498cb4e2062ff131bcd36a858d9848091 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 24 May 2023 14:54:43 -0400 Subject: [PATCH 440/468] Latest changes --- offline/packages/rawtodst/tpc_hits.cc | 35 ++++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index 47a1a5458d..bf465185e8 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -109,7 +109,7 @@ int tpc_hits::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int tpc_hits::process_event(PHCompositeNode *topNode) { - std::cout << "tpc_hits::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + //std::cout << "tpc_hits::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; // load relevant nodes // Get the TrkrHitSetContainer node auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); @@ -133,7 +133,6 @@ int tpc_hits::process_event(PHCompositeNode *topNode) for (int packet = 4000; packet<=4230; packet+=10) { - std::cout << "tpc_hits:: Packet: "<< packet << " processing" << std::endl; Packet *p = _event->getPacket(packet); sector++; @@ -144,7 +143,7 @@ int tpc_hits::process_event(PHCompositeNode *topNode) if (p) { - std::cout << "tpc_hits:: Event getPacket: "<< packet << " FOUND!!!" << std::endl; + std::cout << "tpc_hits:: Event getPacket: "<< packet << " Sector"<< sector << std::endl; }else{ continue; } @@ -183,29 +182,31 @@ int tpc_hits::process_event(PHCompositeNode *topNode) int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; // From Takao int FEE_map[26]={3, 2, 5, 3, 4, 0, 2, 1, 3, 4, 5, 7, 6, 2, 0, 1, 0, 1, 4, 5, 11, 9, 10, 8, 6, 7}; + int pads_per_sector[3] = {96, 128, 192}; - int layer; - if (channel < 128) - { - layer = sampa_nr * 2; - } - else - { - layer = sampa_nr * 2 + 1; - } + //if (channel < 128) + //{ + // layer = sampa_nr * 2; + //} + //else + //{ + // layer = sampa_nr * 2 + 1; + //} - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); - //TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); - TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); // setting the mapp of the FEE int feeM = FEE_map[fee]-1; if(FEE_R[fee]==2) feeM += 6; if(FEE_R[fee]==3) feeM += 14; + int layer = M.getLayer(feeM, channel); double R = M.getR(feeM, channel); double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); + //TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); + TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); + if( Verbosity() ) { int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); @@ -229,11 +230,11 @@ int tpc_hits::process_event(PHCompositeNode *topNode) } for (int s = 0; s < samples; s++) { - int pad = 0; + int pad = M.getPad(feeM, channel); int t = s + 2 * (current_BCO - starting_BCO); int adc = p->iValue(wf,s); // generate hit key - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad, (unsigned int) t); + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad + sector*pads_per_sector[FEE_R[sector]-1], (unsigned int) t); // find existing hit, or create auto hit = hitsetit->second->getHit(hitkey); From f9b24ae0a50ad5481903818f3a1ab6c7e722cd86 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 24 May 2023 15:16:38 -0400 Subject: [PATCH 441/468] Update TpcRawDataTree.cc --- offline/packages/tpc/TpcRawDataTree.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index d84fd6a1b6..ba2e30bfef 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -33,6 +33,7 @@ TpcRawDataTree::TpcRawDataTree(const std::string &name) for (int packet = 4001; packet <= 4231; packet += 10) { m_packets.push_back(packet); + m_packets.push_back(packet+1); } } From d5509e45338a9376270dc501300c0f986961267b Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 24 May 2023 15:27:13 -0400 Subject: [PATCH 442/468] Added draft of InttRawDataDecoder.h/cc following Hugo's (well written) codes for the micromegas --- offline/packages/intt/InttRawDataDecoder.cc | 102 ++++++++++++++++++++ offline/packages/intt/InttRawDataDecoder.h | 34 +++++++ offline/packages/intt/Makefile.am | 4 +- 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 offline/packages/intt/InttRawDataDecoder.cc create mode 100644 offline/packages/intt/InttRawDataDecoder.h diff --git a/offline/packages/intt/InttRawDataDecoder.cc b/offline/packages/intt/InttRawDataDecoder.cc new file mode 100644 index 0000000000..e0eb2d8403 --- /dev/null +++ b/offline/packages/intt/InttRawDataDecoder.cc @@ -0,0 +1,102 @@ +#include "InttRawDataDecoder.h" + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +InttRawDataDecoder::InttRawDataDecoder(std::string const& name): + SubsysReco(name) +{ + //Do nothing +} + +//Init +int InttRawDataDecoder::Init(PHCompositeNode* /*topNode*/) +{ + //Do nothing (yet) + return Fun4AllReturnCodes::EVENT_OK; +} + +//InitRun +int InttRawDataDecoder::InitRun(PHCompositeNode* /*topNode*/) +{ + //Do nothing (yet) + return Fun4AllReturnCodes::EVENT_OK; +} + +//process_event +int InttRawDataDecoder::process_event(PHCompositeNode* topNode) +{ + TrkrHitSetContainer trkr_hit_set_container = findNode::getClass(topNode, "TRKR_HITSET"); + if(!trkr_hit_set_container)return Fun4AllReturnCodes::DISCARDEVENT; + + Event evt = findNode::getClass(topNode, "PRDF"); + if(!evt)return Fun4AllReturnCodes::DISCARDEVENT; + + for(int pid = 3001; pid < 3009; ++pid) + { + Packet* p = evt->getPacket(pid); + if(!p)continue; + + int N = p->iValue(0, "NR_HITS"); + if(!N)continue; + + bco_full = p->lValue(0, "BCO"); + + int adc = 0; + int amp = 0; + int chp = 0; + int chn = 0; + int fee = 0; + int bco = 0; + + TrkrDefs::hitsetkey hit_set_key = 0; + TrkrDefs::hitkey hit_key = 0; + TrkrHitSetContainer::Iterator hit_set_container_itr; + TrkrHit* hit = nullptr; + + for(int n = 0; n < N; ++n) + { + adc = p->iValue(i, "ADC"); + amp = p->iValue(i, "AMPLITUE"); + chp = p->iValue(i, "CHIP_ID"); + chn = p->iValue(i, "CHANNEL_ID"); + fee = p->iValue(i, "FEE"); + bco = p->iValue(i, "FPHX_BCO"); + + //make hit_set_key + //... + + hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); + + //make hit_key + //... + + hit = hit_set_container_itr->second->getHit(hit_key); + if(hit)continue; //Not a typo; this is to avoid duplicate hits + + hit = new TrkrHit; + //hit->setAdc(...) + //... + hit_setcontainer_itr->second->addHitSpecificKey(hit_key, hit); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//End +int InttRawDataDecoder::End(PHCompositeNode* /*topNode*/) +{ + //Do nothing (yet) + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/offline/packages/intt/InttRawDataDecoder.h b/offline/packages/intt/InttRawDataDecoder.h new file mode 100644 index 0000000000..69ec8283d0 --- /dev/null +++ b/offline/packages/intt/InttRawDataDecoder.h @@ -0,0 +1,34 @@ +#ifndef INTT_RAW_DATA_DECODER_H +#define INTT_RAW_DATA_DECODER_H + +////////////////////////////////////////////////////////////////////////////// +// Shamelessly imitaged from the micromegas version: +// +// coresoftware/offline/packages/micromegas/MicromegasRawDataDecoder.h +// +// Thank you Hugo + +#include "InttFelixMap.h" + +#include + +#include +#include +#include + +class PHCompositeNode; + +class InttRawDataDecoder : public SubsysReco +{ +public: + InttRawDataDecoder(std::string const& name = "InttRawDataDecoder"); + + int Init(PHCompositeNode*) override; + int process_event(PHCompositeNode*) override; + int End(PHCompositeNode*) override; + +private: + int64_t full_bco = 0; +}; + +#endif//INTT_RAW_DATA_DECODER_H diff --git a/offline/packages/intt/Makefile.am b/offline/packages/intt/Makefile.am index cdd2f87dfa..d64cc00644 100644 --- a/offline/packages/intt/Makefile.am +++ b/offline/packages/intt/Makefile.am @@ -21,6 +21,7 @@ pkginclude_HEADERS = \ InttClusterizer.h \ InttDeadMapHelper.h \ InttFelixMap.h \ + InttRawDataDecoder.h \ CylinderGeomIntt.h ROOTDICTS = \ @@ -34,7 +35,8 @@ nobase_dist_pcm_DATA = \ libintt_la_SOURCES = \ InttClusterizer.cc \ InttDeadMapHelper.cc \ - InttFelixMap.cc + InttFelixMap.cc \ + InttRawDataDecoder.h libintt_la_LIBADD = \ libintt_io.la \ From 56c65c7dc8a6498bb77336b47504f6acc35f04c8 Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 24 May 2023 15:37:45 -0400 Subject: [PATCH 443/468] Still only a draft, but not it's a draft that compiles --- offline/packages/intt/InttRawDataDecoder.cc | 26 +++++++++++++-------- offline/packages/intt/InttRawDataDecoder.h | 1 + offline/packages/intt/Makefile.am | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/offline/packages/intt/InttRawDataDecoder.cc b/offline/packages/intt/InttRawDataDecoder.cc index e0eb2d8403..298a46746e 100644 --- a/offline/packages/intt/InttRawDataDecoder.cc +++ b/offline/packages/intt/InttRawDataDecoder.cc @@ -10,7 +10,9 @@ #include #include +#include #include +#include InttRawDataDecoder::InttRawDataDecoder(std::string const& name): SubsysReco(name) @@ -35,10 +37,10 @@ int InttRawDataDecoder::InitRun(PHCompositeNode* /*topNode*/) //process_event int InttRawDataDecoder::process_event(PHCompositeNode* topNode) { - TrkrHitSetContainer trkr_hit_set_container = findNode::getClass(topNode, "TRKR_HITSET"); + TrkrHitSetContainer* trkr_hit_set_container = findNode::getClass(topNode, "TRKR_HITSET"); if(!trkr_hit_set_container)return Fun4AllReturnCodes::DISCARDEVENT; - Event evt = findNode::getClass(topNode, "PRDF"); + Event* evt = findNode::getClass(topNode, "PRDF"); if(!evt)return Fun4AllReturnCodes::DISCARDEVENT; for(int pid = 3001; pid < 3009; ++pid) @@ -49,8 +51,9 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) int N = p->iValue(0, "NR_HITS"); if(!N)continue; - bco_full = p->lValue(0, "BCO"); + full_bco = p->lValue(0, "BCO"); + //Could potentially wrap these into a struct int adc = 0; int amp = 0; int chp = 0; @@ -65,14 +68,17 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) for(int n = 0; n < N; ++n) { - adc = p->iValue(i, "ADC"); - amp = p->iValue(i, "AMPLITUE"); - chp = p->iValue(i, "CHIP_ID"); - chn = p->iValue(i, "CHANNEL_ID"); - fee = p->iValue(i, "FEE"); - bco = p->iValue(i, "FPHX_BCO"); + adc = p->iValue(n, "ADC"); + amp = p->iValue(n, "AMPLITUE"); + chp = p->iValue(n, "CHIP_ID"); + chn = p->iValue(n, "CHANNEL_ID"); + fee = p->iValue(n, "FEE"); + bco = p->iValue(n, "FPHX_BCO"); //make hit_set_key + //dummy expression so it compiles + //should add a helper method somewhere, either in trackbase or here + hit_set_key = adc + amp + chp + chn + fee + bco; //... hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); @@ -86,7 +92,7 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) hit = new TrkrHit; //hit->setAdc(...) //... - hit_setcontainer_itr->second->addHitSpecificKey(hit_key, hit); + hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } } diff --git a/offline/packages/intt/InttRawDataDecoder.h b/offline/packages/intt/InttRawDataDecoder.h index 69ec8283d0..f1c5bccf9c 100644 --- a/offline/packages/intt/InttRawDataDecoder.h +++ b/offline/packages/intt/InttRawDataDecoder.h @@ -24,6 +24,7 @@ class InttRawDataDecoder : public SubsysReco InttRawDataDecoder(std::string const& name = "InttRawDataDecoder"); int Init(PHCompositeNode*) override; + int InitRun(PHCompositeNode*) override; int process_event(PHCompositeNode*) override; int End(PHCompositeNode*) override; diff --git a/offline/packages/intt/Makefile.am b/offline/packages/intt/Makefile.am index d64cc00644..e555e46bca 100644 --- a/offline/packages/intt/Makefile.am +++ b/offline/packages/intt/Makefile.am @@ -36,7 +36,7 @@ libintt_la_SOURCES = \ InttClusterizer.cc \ InttDeadMapHelper.cc \ InttFelixMap.cc \ - InttRawDataDecoder.h + InttRawDataDecoder.cc libintt_la_LIBADD = \ libintt_io.la \ From a5364b7fae6a51dc49d81a517f0c93e6aab05e12 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Wed, 24 May 2023 17:07:49 -0400 Subject: [PATCH 444/468] Setting gain weights to 1 --- offline/packages/rawtodst/tpc_hits.cc | 32 ++++++------------- offline/packages/tpc/Makefile.am | 4 +++ .../g4tpc/PHG4TpcPadPlaneReadout.cc | 1 - .../g4tpc/PHG4TpcPadPlaneReadout.h | 2 +- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/offline/packages/rawtodst/tpc_hits.cc b/offline/packages/rawtodst/tpc_hits.cc index bf465185e8..f69d040bb1 100644 --- a/offline/packages/rawtodst/tpc_hits.cc +++ b/offline/packages/rawtodst/tpc_hits.cc @@ -129,27 +129,25 @@ int tpc_hits::process_event(PHCompositeNode *topNode) } // check all possible TPC packets that we need to analyze - int sector = -1; + for(int ep=0;ep<2;ep++){ + for (int sector = 0; sector<=23; sector++) + { + const int packet = 4000 + sector*10 + ep; - for (int packet = 4000; packet<=4230; packet+=10) - { + // Reading packet Packet *p = _event->getPacket(packet); - sector++; - // Figure out which side int side = 0; if(sector>11) side=1; if (p) { - std::cout << "tpc_hits:: Event getPacket: "<< packet << " Sector"<< sector << std::endl; + std::cout << "tpc_hits:: Event getPacket: "<< packet << "| Sector"<< sector << "| EndPoint "<< ep << std::endl; }else{ continue; } - //Packet *p = _event->getPacket(current_packet); - int nr_of_waveforms = p->iValue(0, "NR_WF"); for (auto &l : m_hitset) @@ -178,22 +176,13 @@ int tpc_hits::process_event(PHCompositeNode *topNode) int fee = p->iValue(wf, "FEE"); int samples = p->iValue( wf, "SAMPLES" ); + // clockwise FEE mapping //int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; - // From Takao + // conter clockwise FEE mapping (From Takao) int FEE_map[26]={3, 2, 5, 3, 4, 0, 2, 1, 3, 4, 5, 7, 6, 2, 0, 1, 0, 1, 4, 5, 11, 9, 10, 8, 6, 7}; int pads_per_sector[3] = {96, 128, 192}; - //if (channel < 128) - //{ - // layer = sampa_nr * 2; - //} - //else - //{ - // layer = sampa_nr * 2 + 1; - //} - - // setting the mapp of the FEE int feeM = FEE_map[fee]-1; if(FEE_R[fee]==2) feeM += 6; @@ -204,7 +193,6 @@ int tpc_hits::process_event(PHCompositeNode *topNode) double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); - //TrkrHitSetContainer::Iterator hitsetit = m_hits->findOrAddHitSet(tpcHitSetKey); TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); if( Verbosity() ) @@ -258,8 +246,8 @@ int tpc_hits::process_event(PHCompositeNode *topNode) } } - }// End of run over packets - + }// End of run over packets + }//End of ep loop // we skip the mapping to real pads at first. We just say // that we get 16 rows (segment R2) with 128 pads // so each FEE fills 2 rows. Not right, but one step at a time. diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index f575bea662..9e523aaa25 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -27,6 +27,8 @@ pkginclude_HEADERS = \ TpcDistortionCorrection.h \ TpcDistortionCorrectionContainer.h \ TpcLoadDistortionCorrection.h \ + TpcMap.h \ + TpcRawDataDecoder.h \ TpcRawWriter.h \ TpcSimpleClusterizer.h @@ -38,6 +40,8 @@ libtpc_la_SOURCES = \ TpcClusterCleaner.cc \ TpcClusterizer.cc \ TpcLoadDistortionCorrection.cc \ + TpcMap.cc \ + TpcRawDataDecoder.cc \ TpcRawWriter.cc \ TpcSimpleClusterizer.cc diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 8d01a02c05..7798d7078c 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -288,7 +288,6 @@ void PHG4TpcPadPlaneReadout::MapToPadPlane( if(phi<0)phi_gain += 2*M_PI; double gain_weight = 1.0; if(m_flagToUseGain==1) gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem*10,phi_gain));//rad_gem in cm -> *10 to get mm - gain_weight = 1.0; nelec = nelec*gain_weight; //std::cout<<"PHG4TpcPadPlaneReadout::MapToPadPlane gain_weight = "< SectorPhi; int m_NHits = 0; // Using Gain maps is turned off by default - int m_flagToUseGain = 1; + int m_flagToUseGain = 0; // gaussian sampling static constexpr double _nsigmas = 5; From 7efdb89a4aeb9fcb2a897bfac11e77499af305b9 Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 24 May 2023 17:58:22 -0400 Subject: [PATCH 445/468] Implemented proper computations of hitkey and hitsetkey --- offline/packages/intt/InttRawDataDecoder.cc | 60 ++++++++++++--------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/offline/packages/intt/InttRawDataDecoder.cc b/offline/packages/intt/InttRawDataDecoder.cc index 298a46746e..cad589b151 100644 --- a/offline/packages/intt/InttRawDataDecoder.cc +++ b/offline/packages/intt/InttRawDataDecoder.cc @@ -10,7 +10,9 @@ #include #include +#include #include +#include #include #include @@ -43,6 +45,25 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) Event* evt = findNode::getClass(topNode, "PRDF"); if(!evt)return Fun4AllReturnCodes::DISCARDEVENT; + int adc = 0; + //int amp = 0; + int chp = 0; + int chn = 0; + int fee = 0; + int bco = 0; + + struct INTT_Felix::Ladder_s ldr_struct; + int layer = 0; + int ladder_z = 0; + int ladder_phi = 0; + int strip_x = 0; + int strip_y = 0; + + TrkrDefs::hitsetkey hit_set_key = 0; + TrkrDefs::hitkey hit_key = 0; + TrkrHitSetContainer::Iterator hit_set_container_itr; + TrkrHit* hit = nullptr; + for(int pid = 3001; pid < 3009; ++pid) { Packet* p = evt->getPacket(pid); @@ -53,45 +74,32 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) full_bco = p->lValue(0, "BCO"); - //Could potentially wrap these into a struct - int adc = 0; - int amp = 0; - int chp = 0; - int chn = 0; - int fee = 0; - int bco = 0; - - TrkrDefs::hitsetkey hit_set_key = 0; - TrkrDefs::hitkey hit_key = 0; - TrkrHitSetContainer::Iterator hit_set_container_itr; - TrkrHit* hit = nullptr; - for(int n = 0; n < N; ++n) { adc = p->iValue(n, "ADC"); - amp = p->iValue(n, "AMPLITUE"); + //amp = p->iValue(n, "AMPLITUE"); chp = p->iValue(n, "CHIP_ID"); chn = p->iValue(n, "CHANNEL_ID"); fee = p->iValue(n, "FEE"); bco = p->iValue(n, "FPHX_BCO"); - //make hit_set_key - //dummy expression so it compiles - //should add a helper method somewhere, either in trackbase or here - hit_set_key = adc + amp + chp + chn + fee + bco; - //... + INTT_Felix::FelixMap(pid - 3001, fee, ldr_struct); + layer = 2 * ldr_struct.barrel + ldr_struct.ladder; + ladder_phi = ldr_struct.ladder; // B A A B + ladder_z = arm * 2 + (chp % 13 < 5); //South<- 1, 0, 2, 3 ->North - hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); + strip_x = 25 * arm - (2 * arm - 1) * chp % 13; + strip_y = 128 * ((arm + chp / 13) % 2) + chn; //need to check this is the convention - //make hit_key - //... + hit_key = InttDefs::genHitKey(strip_x, strip_y); + hit_set_key = InttDefs::genHitSetKey(layer, ladder_z, ladder_phi, bco); + hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); hit = hit_set_container_itr->second->getHit(hit_key); - if(hit)continue; //Not a typo; this is to avoid duplicate hits + if(hit)continue; - hit = new TrkrHit; - //hit->setAdc(...) - //... + hit = new TrkrHitv2; + hit->setAdc(adc) hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } } From d8daba50fd62ede4d4a91e249d7e010bdc19cdab Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 24 May 2023 18:03:06 -0400 Subject: [PATCH 446/468] fixed typo --- offline/packages/intt/InttRawDataDecoder.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/offline/packages/intt/InttRawDataDecoder.cc b/offline/packages/intt/InttRawDataDecoder.cc index cad589b151..0010ea04f0 100644 --- a/offline/packages/intt/InttRawDataDecoder.cc +++ b/offline/packages/intt/InttRawDataDecoder.cc @@ -46,16 +46,17 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) if(!evt)return Fun4AllReturnCodes::DISCARDEVENT; int adc = 0; - //int amp = 0; + int amp = 0; + int bco = 0; int chp = 0; int chn = 0; int fee = 0; - int bco = 0; struct INTT_Felix::Ladder_s ldr_struct; int layer = 0; int ladder_z = 0; int ladder_phi = 0; + int arm = 0; int strip_x = 0; int strip_y = 0; @@ -78,16 +79,16 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) { adc = p->iValue(n, "ADC"); //amp = p->iValue(n, "AMPLITUE"); + bco = p->iValue(n, "FPHX_BCO"); chp = p->iValue(n, "CHIP_ID"); chn = p->iValue(n, "CHANNEL_ID"); fee = p->iValue(n, "FEE"); - bco = p->iValue(n, "FPHX_BCO"); INTT_Felix::FelixMap(pid - 3001, fee, ldr_struct); layer = 2 * ldr_struct.barrel + ldr_struct.ladder; ladder_phi = ldr_struct.ladder; // B A A B ladder_z = arm * 2 + (chp % 13 < 5); //South<- 1, 0, 2, 3 ->North - + arm = (pid - 3001) / 4; strip_x = 25 * arm - (2 * arm - 1) * chp % 13; strip_y = 128 * ((arm + chp / 13) % 2) + chn; //need to check this is the convention @@ -99,7 +100,7 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) if(hit)continue; hit = new TrkrHitv2; - hit->setAdc(adc) + hit->setAdc(adc); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } } From 25504c091497017fec888419cca0e6a3c1fd90fa Mon Sep 17 00:00:00 2001 From: josephbertaux Date: Wed, 24 May 2023 18:04:07 -0400 Subject: [PATCH 447/468] fixed typo --- offline/packages/intt/InttRawDataDecoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/intt/InttRawDataDecoder.cc b/offline/packages/intt/InttRawDataDecoder.cc index 0010ea04f0..ca2bba139a 100644 --- a/offline/packages/intt/InttRawDataDecoder.cc +++ b/offline/packages/intt/InttRawDataDecoder.cc @@ -46,7 +46,7 @@ int InttRawDataDecoder::process_event(PHCompositeNode* topNode) if(!evt)return Fun4AllReturnCodes::DISCARDEVENT; int adc = 0; - int amp = 0; + //int amp = 0; int bco = 0; int chp = 0; int chn = 0; From f05c59cc24fd1baaa8847fc3a1ae80ee17937287 Mon Sep 17 00:00:00 2001 From: E Shulga Date: Thu, 25 May 2023 09:44:22 -0400 Subject: [PATCH 448/468] Adding files TpcMap.cc/.h and TpcRawDataDecoder.cc/.h --- offline/packages/tpc/TpcMap.cc | 223 +++++++++++++++++ offline/packages/tpc/TpcMap.h | 37 +++ offline/packages/tpc/TpcRawDataDecoder.cc | 292 ++++++++++++++++++++++ offline/packages/tpc/TpcRawDataDecoder.h | 83 ++++++ 4 files changed, 635 insertions(+) create mode 100644 offline/packages/tpc/TpcMap.cc create mode 100644 offline/packages/tpc/TpcMap.h create mode 100644 offline/packages/tpc/TpcRawDataDecoder.cc create mode 100644 offline/packages/tpc/TpcRawDataDecoder.h diff --git a/offline/packages/tpc/TpcMap.cc b/offline/packages/tpc/TpcMap.cc new file mode 100644 index 0000000000..37054e2706 --- /dev/null +++ b/offline/packages/tpc/TpcMap.cc @@ -0,0 +1,223 @@ +#include "TpcMap.h" + +#include +#include +#include +#include +#include +#include + +void TpcMap::setMapNames(const std::string &r1, const std::string &r2, const std::string &r3) +{ + const char *calibrationroot = getenv("CALIBRATIONROOT"); + std::string full_path; + if (calibrationroot) + { + full_path = std::string(calibrationroot) + "/TPC/Mapping/PadPlane/"; + } + else + { + full_path = "./"; + } + std::string full_path_r1 = full_path + r1; + std::string full_path_r2 = full_path + r2; + std::string full_path_r3 = full_path + r3; + int status; + status = digest_map(full_path_r1, 0); + if (status) + { + std::cout << "reading " << full_path_r1 << " failed" << std::endl; + } + status = digest_map(full_path_r2, 1); + if (status) + { + std::cout << "reading " << full_path_r2 << " failed" << std::endl; + } + status = digest_map(full_path_r3, 2); + if (status) + { + std::cout << "reading " << full_path_r3 << " failed" << std::endl; + } +} + +int TpcMap::digest_map(const std::string &fileName, const unsigned int section_offset) +{ + std::ifstream infile(fileName, std::ios::in); + + if (!infile.is_open()) + { + std::cout << "Could not open file: "<< fileName << std::endl; + _broken = 1; + return -1; + } + + std::string line; + getline(infile, line); // throwaway - we skip the first line + // cout << __FILE__<< " " << __LINE__ << ": " << line << endl; + + int abs_pad = INT_MAX; + int Radius = INT_MAX; + // int Pad; + // int U; + // int G; + // string Pin; + // int PinColID; + // int PinRowID; + // string PadName; + int FEE = INT_MAX; + // int FEE_Connector; + int FEE_Chan = INT_MAX; + // double phi; + // double x; + // double y; + // double PadX; + // double PadY; + double PadR = NAN; + double PadPhi = NAN; + + while (getline(infile, line)) + { + // cout << line<< endl; + std::stringstream ss(line); + std::string next; + + // 0 26 26 + // 1 0 0 + // 2 0 0 + // 3 1 1 + // 4 1 1 + // 5 0 C5 + // 6 2 2 + // 7 5 5 + // 8 0 ZZ.00.000 + // 9 5 5.0 + // 10 0 J2 + // 11 147 147 + // 12 0 0.005570199740407434 + // 13 69 69.99891405342764 + // 14 0 0.38991196551332985 + // 15 77 77.86043476908294 + // 16 305 305.14820499531316 + // 17 314 314.9248709046211 + // 18 0 0.24982557215053805 + + int index = 0; + while (ss.good()) + { + getline(ss, next, ','); + if (index == 0) + { + abs_pad = std::stoul(next); + } + else if (index == 1) + { + Radius = stoul(next); + } + else if (index == 9) + { + FEE = stoul(next); + } + else if (index == 11) + { + FEE_Chan = stoul(next); + } + else if (index == 17) + { + PadR = stod(next); + } + else if (index == 18) + { + PadPhi = stod(next); + } + index++; + } + + if (section_offset == 1) + { + FEE += 6; + } + if (section_offset == 2) + { + FEE += 14; + } + + struct tpc_map x + { + }; + x.padnr = abs_pad; + x.layer = Radius + section_offset * 16 + 7; + x.FEE = FEE; + x.FEEChannel = FEE_Chan; + x.PadR = PadR; + x.PadPhi = PadPhi; + + unsigned int key = 256 * (FEE) + FEE_Chan; + tmap[key] = x; + // cout << setw(5) << key << setw(5) << FEE << setw(5) << FEE_Chan << " " << PadR << " " << PadPhi << endl; + } + return 0; +} + +unsigned int TpcMap::getLayer(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const +{ + if (FEE >= 26 || FEEChannel > 255) + { + return 0.; + } + unsigned int key = 256 * FEE + FEEChannel; + + std::map::const_iterator itr = tmap.find(key); + if (itr == tmap.end()) + { + return 0; + } + return itr->second.layer; +} + +unsigned int TpcMap::getPad(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const +{ + if (FEE >= 26 || FEEChannel > 255) + { + return 0.; + } + unsigned int key = 256 * FEE + FEEChannel; + + std::map::const_iterator itr = tmap.find(key); + if (itr == tmap.end()) + { + return -100; + } + return itr->second.padnr; +} + +double TpcMap::getR(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const +{ + if (FEE >= 26 || FEEChannel > 255) + { + return 0.; + } + unsigned int key = 256 * FEE + FEEChannel; + + std::map::const_iterator itr = tmap.find(key); + if (itr == tmap.end()) + { + return -100; + } + return itr->second.PadR; +} + +double TpcMap::getPhi(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int /* packetid */) const +{ + if (FEE > 25 || FEEChannel > 255) + { + return 0.; + } + unsigned int key = 256 * FEE + FEEChannel; + + std::map::const_iterator itr = tmap.find(key); + if (itr == tmap.end()) + { + return -100; + } + return itr->second.PadPhi; +} diff --git a/offline/packages/tpc/TpcMap.h b/offline/packages/tpc/TpcMap.h new file mode 100644 index 0000000000..c48d98cc63 --- /dev/null +++ b/offline/packages/tpc/TpcMap.h @@ -0,0 +1,37 @@ +#ifndef __TpcMap_H__ +#define __TpcMap_H__ + +#include +#include + +class TpcMap +{ + public: + // constructors and destructors + TpcMap() = default; + virtual ~TpcMap() = default; + + virtual unsigned int getLayer(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; + virtual unsigned int getPad(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; + virtual double getR(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; + virtual double getPhi(const unsigned int FEE, const unsigned int FEEChannel, const unsigned int packetid = 0) const; + virtual void setMapNames(const std::string &r1, const std::string &r2, const std::string &r3); + + private: + int digest_map(const std::string &fileName, const unsigned int section_offset); + + int _broken = 0; + struct tpc_map + { + unsigned int padnr; + unsigned int layer; + unsigned int FEE; + unsigned int FEEChannel; + double PadR; + double PadPhi; + }; + + std::map tmap; +}; + +#endif diff --git a/offline/packages/tpc/TpcRawDataDecoder.cc b/offline/packages/tpc/TpcRawDataDecoder.cc new file mode 100644 index 0000000000..c6eb894aa0 --- /dev/null +++ b/offline/packages/tpc/TpcRawDataDecoder.cc @@ -0,0 +1,292 @@ + +#include "TpcRawDataDecoder.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include // for PHIODataNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include + +#include +#include +#include + +#include + +#include +#include + +//____________________________________________________________________________.. +TpcRawDataDecoder::TpcRawDataDecoder(const std::string &name) + : SubsysReco(name) + , hm(nullptr) + , _filename("./outputfile.root") + { + std::cout << "TpcRawDataDecoder::TpcRawDataDecoder(const std::string &name)" << std::endl; + starting_BCO = -1; + rollover_value = 0; + current_BCOBIN = 0; + M.setMapNames("AutoPad-R1-RevA.sch.ChannelMapping.csv", "AutoPad-R2-RevA-Pads.sch.ChannelMapping.csv", "AutoPad-R3-RevA.sch.ChannelMapping.csv"); +} + +//____________________________________________________________________________.. +TpcRawDataDecoder::~TpcRawDataDecoder() +{ + delete hm; + std::cout << "TpcRawDataDecoder::~TpcRawDataDecoder() Calling dtor" << std::endl; +} + +//____________________________________________________________________________.. +int TpcRawDataDecoder::Init(PHCompositeNode * /*topNode*/) +{ + std::cout << "TpcRawDataDecoder::Init(PHCompositeNode *topNode) Initializing" << std::endl; + hm = new Fun4AllHistoManager("HITHIST"); + + _h_hit_XY = new TH2F("_h_hit_XY" ,"_h_hit_XY;X, [m];Y, [m]", 400, -800, 800, 400, -800, 800); + + hm->registerHisto(_h_hit_XY ); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TpcRawDataDecoder::InitRun(PHCompositeNode *topNode) +{ + + // get dst node + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "TpcRawDataDecoder::InitRun - DST Node missing, doing nothing." << std::endl; + exit(1); + } + + // create hitset container if needed + auto hitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + if (!hitsetcontainer) + { + std::cout << "TpcRawDataDecoder::InitRun - creating TRKR_HITSET." << std::endl; + + // find or create TRKR node + PHNodeIterator dstiter(dstNode); + auto trkrnode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + if (!trkrnode) + { + trkrnode = new PHCompositeNode("TRKR"); + dstNode->addNode(trkrnode); + } + + // create container and add to the tree + hitsetcontainer = new TrkrHitSetContainerv1; + auto newNode = new PHIODataNode(hitsetcontainer, "TRKR_HITSET", "PHObject"); + trkrnode->addNode(newNode); + } + topNode->print(); + + // we reset the BCO for the new run + starting_BCO = -1; + rollover_value = 0; + current_BCOBIN = 0; + + //m_hits = new TrkrHitSetContainerv1(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int TpcRawDataDecoder::process_event(PHCompositeNode *topNode) +{ + //std::cout << "TpcRawDataDecoder::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + // load relevant nodes + // Get the TrkrHitSetContainer node + auto trkrhitsetcontainer = findNode::getClass(topNode, "TRKR_HITSET"); + assert(trkrhitsetcontainer); + + Event *_event = findNode::getClass(topNode, "PRDF"); + assert( _event ); + + if (_event == nullptr) + { + std::cout << "TpcRawDataDecoder::Process_Event - Event not found" << std::endl; + return -1; + } + if (_event->getEvtType() >= 8) /// special events + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + + // check all possible TPC packets that we need to analyze + for(int ep=0;ep<2;ep++){ + for (int sector = 0; sector<=23; sector++) + { + const int packet = 4000 + sector*10 + ep; + + // Reading packet + Packet *p = _event->getPacket(packet); + + // Figure out which side + int side = 0; + if(sector>11) side=1; + + if (p) + { + std::cout << "TpcRawDataDecoder:: Event getPacket: "<< packet << "| Sector"<< sector << "| EndPoint "<< ep << std::endl; + }else{ + continue; + } + + int nr_of_waveforms = p->iValue(0, "NR_WF"); + + for (auto &l : m_hitset) + { + l = new TrkrHitSetv1(); + + int wf; + for (wf = 0; wf < nr_of_waveforms; wf++) + { + int current_BCO = p->iValue(wf, "BCO") + rollover_value; + + if (starting_BCO < 0) + { + starting_BCO = current_BCO; + } + + if (current_BCO < starting_BCO) // we have a rollover + { + rollover_value += 0x100000; + current_BCO = p->iValue(wf, "BCO") + rollover_value; + starting_BCO = current_BCO; + current_BCOBIN++; + } + int sampa_nr = p->iValue(wf, "SAMPAADDRESS"); + int channel = p->iValue(wf, "CHANNEL"); + + int fee = p->iValue(wf, "FEE"); + int samples = p->iValue( wf, "SAMPLES" ); + // clockwise FEE mapping + //int FEE_map[26]={5, 6, 1, 3, 2, 12, 10, 11, 9, 8, 7, 1, 2, 4, 8, 7, 6, 5, 4, 3, 1, 3, 2, 4, 6, 5}; + int FEE_R[26]={2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; + // conter clockwise FEE mapping (From Takao) + int FEE_map[26]={3, 2, 5, 3, 4, 0, 2, 1, 3, 4, 5, 7, 6, 2, 0, 1, 0, 1, 4, 5, 11, 9, 10, 8, 6, 7}; + int pads_per_sector[3] = {96, 128, 192}; + + // setting the mapp of the FEE + int feeM = FEE_map[fee]-1; + if(FEE_R[fee]==2) feeM += 6; + if(FEE_R[fee]==3) feeM += 14; + int layer = M.getLayer(feeM, channel); + + double R = M.getR(feeM, channel); + double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; + + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); + TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); + + if( Verbosity() ) + { + int sampaAddress = p->iValue(wf, "SAMPAADDRESS"); + int sampaChannel = p->iValue(wf, "SAMPACHANNEL"); + int checksum = p->iValue(wf, "CHECKSUM"); + int checksumError = p->iValue(wf, "CHECKSUMERROR"); + std::cout << "TpcRawDataDecoder::Process_Event Samples "<< samples + <<" Chn:"<< channel + <<" layer: " << layer + << " sampa: "<< sampa_nr + << " fee: "<< fee + << " Mapped fee: "<< feeM + << " sampaAddress: "<< sampaAddress + << " sampaChannel: "<< sampaChannel + << " checksum: "<< checksum + << " checksumError: "<< checksumError + << " hitsetkey "<< tpcHitSetKey + << " R = " << R + << " phi = " << phi + << std::endl; + } + for (int s = 0; s < samples; s++) + { + int pad = M.getPad(feeM, channel); + int t = s + 2 * (current_BCO - starting_BCO); + int adc = p->iValue(wf,s); + // generate hit key + TrkrDefs::hitkey hitkey = TpcDefs::genHitKey((unsigned int) pad + sector*pads_per_sector[FEE_R[sector]-1], (unsigned int) t); + // find existing hit, or create + auto hit = hitsetit->second->getHit(hitkey); + + // create hit, assign adc and insert in hitset + if (!hit) + { + // create a new one + hit = new TrkrHitv2(); + hit->setAdc(adc); + hitsetit->second->addHitSpecificKey(hitkey, hit); + } + //else{ + // hit->setAdc(adc); + // hitsetit->second->addHitSpecificKey(hitkey, hit); + //} + + _h_hit_XY->Fill(R*cos(phi),R*sin(phi),adc); + + } + + } + } + + }// End of run over packets + }//End of ep loop + // we skip the mapping to real pads at first. We just say + // that we get 16 rows (segment R2) with 128 pads + // so each FEE fills 2 rows. Not right, but one step at a time. + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +//int TpcRawDataDecoder::ResetEvent(PHCompositeNode * /*topNode*/) +//{ +// std::cout << "TpcRawDataDecoder::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//____________________________________________________________________________.. +//int TpcRawDataDecoder::EndRun(const int runnumber) +//{ +// std::cout << "TpcRawDataDecoder::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//____________________________________________________________________________.. +int TpcRawDataDecoder::End(PHCompositeNode * /*topNode*/) +{ + std::cout << "TpcRawDataDecoder::End(PHCompositeNode *topNode) This is the End..." << std::endl; + hm->dumpHistos(_filename, "RECREATE"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +//int TpcRawDataDecoder::Reset(PHCompositeNode * /*topNode*/) +//{ +// std::cout << "TpcRawDataDecoder::Reset(PHCompositeNode *topNode) being Reset" << std::endl; +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//____________________________________________________________________________.. +//void TpcRawDataDecoder::Print(const std::string &what) const +//{ +// std::cout << "TpcRawDataDecoder::Print(const std::string &what) const Printing info for " << what << std::endl; +//} diff --git a/offline/packages/tpc/TpcRawDataDecoder.h b/offline/packages/tpc/TpcRawDataDecoder.h new file mode 100644 index 0000000000..51c56b4136 --- /dev/null +++ b/offline/packages/tpc/TpcRawDataDecoder.h @@ -0,0 +1,83 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TPCRAWDATADECODER_H +#define TPCRAWDATADECODER_H + +#include "TpcMap.h" + +#include +#include + +#include + +#include +#include + +class PHCompositeNode; +class Fun4AllHistoManager; +//class TrkrHitSetContainer; +//class TrkrHitSet; +//class TrkrHit; +class TH2; + +class TpcRawDataDecoder : public SubsysReco +{ + public: + TpcRawDataDecoder(const std::string &name = "TpcRawDataDecoder"); + + ~TpcRawDataDecoder() override; + + int Init(PHCompositeNode *topNode) override; + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. A place + to book histograms which have to know the run number. + */ + int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Clean up internals after each event. + //int ResetEvent(PHCompositeNode *topNode) override; + + /// Called at the end of each run. + //int EndRun(const int runnumber) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + /// Reset + //int Reset(PHCompositeNode * /*topNode*/) override; + + //void Print(const std::string &what = "ALL") const override; + + protected: + Fun4AllHistoManager *hm = nullptr; + std::string _filename; + + static const int layercount = 16; + static const int layeroffset = 7 + 16; + + //TrkrHitSetContainer *m_hits = nullptr; + TrkrHitSet *m_hitset[layercount] = {}; + //TrkrHit *m_hit = nullptr; + + // RawHitSetContainer *m_rawhits __attribute__ ((unused)) = nullptr; + + TpcMap M; + + int starting_BCO; + int rollover_value; + int current_BCOBIN; + + private: + + TH2* _h_hit_XY = nullptr; + +}; + +#endif // TPC_RAWDATADECODER_H From b01953f854b4eab3e61d03e84df4efa19263c77d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 25 May 2023 10:44:09 -0400 Subject: [PATCH 449/468] suppress verbosity --- offline/packages/trackreco/MakeActsGeometry.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index c3405a7bec..dd07de6a77 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -115,9 +115,9 @@ namespace MakeActsGeometry::MakeActsGeometry(const std::string &name) : SubsysReco(name) { - for ( const auto id : { TrkrDefs::mvtxId, TrkrDefs::inttId, TrkrDefs::tpcId, TrkrDefs::micromegasId }) + for ( int layer = 0; layer < 57; layer++) { - m_misalignmentFactor.insert(std::make_pair(id, 1.)); + m_misalignmentFactor.insert(std::make_pair(layer, 1.)); } } From f29a31af3ac51fa82dbd5f2193dc2bc294cfc5ee Mon Sep 17 00:00:00 2001 From: E Shulga Date: Thu, 25 May 2023 16:08:50 -0400 Subject: [PATCH 450/468] Set histos to nullptr --- offline/packages/tpc/TpcRawDataDecoder.cc | 60 ++++++++++++++++++- offline/packages/tpc/TpcRawDataDecoder.h | 15 +++++ .../g4tpc/PHG4TpcPadPlaneReadout.cc | 2 + 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpc/TpcRawDataDecoder.cc b/offline/packages/tpc/TpcRawDataDecoder.cc index c6eb894aa0..faef235725 100644 --- a/offline/packages/tpc/TpcRawDataDecoder.cc +++ b/offline/packages/tpc/TpcRawDataDecoder.cc @@ -27,6 +27,7 @@ #include #include +#include //____________________________________________________________________________.. TpcRawDataDecoder::TpcRawDataDecoder(const std::string &name) @@ -39,6 +40,52 @@ TpcRawDataDecoder::TpcRawDataDecoder(const std::string &name) rollover_value = 0; current_BCOBIN = 0; M.setMapNames("AutoPad-R1-RevA.sch.ChannelMapping.csv", "AutoPad-R2-RevA-Pads.sch.ChannelMapping.csv", "AutoPad-R3-RevA.sch.ChannelMapping.csv"); + + + + + // Open a file, save the ntuple and close the file + TFile in_file("/sphenix/user/shulga/Work/Files/pedestal-10616-outfile.root"); + in_file.GetObject("h_Alive",h_Alive); + float chan_id,fee_id,module_id,pedMean,pedStdi, sec_id; float* row_content; + + if( Verbosity() )std::cout << "chan_id\t fee_id\t module_id\t pedMean\t pedStdi\t sec_id\n"; + for (int irow=0;irowGetEntries();++irow) + { + h_Alive->GetEntry(irow); + row_content = h_Alive->GetArgs(); + chan_id = row_content[0]; + fee_id = row_content[1]; + module_id = row_content[2]; + pedMean = row_content[3]; + pedStdi = row_content[4]; + sec_id = row_content[5]; + if( Verbosity() ) + { + std::cout + << chan_id << "\t" + << fee_id << "\t" + << module_id << "\t" + << pedMean << "\t" + << pedStdi << "\t" + << sec_id << "\t" + << std::endl; + } + + struct tpc_map x + { + }; + + x.CHN_ID = chan_id ; + x.FEE_ID = fee_id ; + x.MOD_ID = module_id; + x.PedMean = pedMean ; + x.PedStdi = pedStdi ; + x.SEC_ID = sec_id ; + + unsigned int key = 256 * (fee_id) + chan_id; + tmap[key] = x; + } } //____________________________________________________________________________.. @@ -191,7 +238,8 @@ int TpcRawDataDecoder::process_event(PHCompositeNode *topNode) double R = M.getR(feeM, channel); double phi = M.getPhi(feeM, channel) + sector * M_PI / 6 ; - + unsigned int key = 256 * (feeM) + channel; + int pedestal = round(tmap[key].PedMean); TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(layer, sector, side); TrkrHitSetContainer::Iterator hitsetit = trkrhitsetcontainer->findOrAddHitSet(tpcHitSetKey); @@ -231,7 +279,8 @@ int TpcRawDataDecoder::process_event(PHCompositeNode *topNode) { // create a new one hit = new TrkrHitv2(); - hit->setAdc(adc); + hit->setAdc(adc-pedestal); + //std::cout<< "ADC = " << adc << " Pedestal = "<< pedestal << "delta = "<< adc-pedestal << std::endl; hitsetit->second->addHitSpecificKey(hitkey, hit); } //else{ @@ -290,3 +339,10 @@ int TpcRawDataDecoder::End(PHCompositeNode * /*topNode*/) //{ // std::cout << "TpcRawDataDecoder::Print(const std::string &what) const Printing info for " << what << std::endl; //} + +//____________________________________________________________________________.. +void TpcRawDataDecoder::setHistoFileName(const std::string &what) +{ + _filename = what; + std::cout << "TpcRawDataDecoder::setHistoFileName(const std::string &what) Histogram File Name is " << what << std::endl; +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcRawDataDecoder.h b/offline/packages/tpc/TpcRawDataDecoder.h index 51c56b4136..f368a20cbd 100644 --- a/offline/packages/tpc/TpcRawDataDecoder.h +++ b/offline/packages/tpc/TpcRawDataDecoder.h @@ -19,6 +19,7 @@ class Fun4AllHistoManager; //class TrkrHitSet; //class TrkrHit; class TH2; +class TNtuple; class TpcRawDataDecoder : public SubsysReco { @@ -54,6 +55,7 @@ class TpcRawDataDecoder : public SubsysReco //int Reset(PHCompositeNode * /*topNode*/) override; //void Print(const std::string &what = "ALL") const override; + void setHistoFileName(const std::string &what = "./outputfile.root"); protected: Fun4AllHistoManager *hm = nullptr; @@ -69,6 +71,19 @@ class TpcRawDataDecoder : public SubsysReco // RawHitSetContainer *m_rawhits __attribute__ ((unused)) = nullptr; TpcMap M; + TNtuple *h_Alive = nullptr; + + struct tpc_map + { + unsigned int CHN_ID; + unsigned int FEE_ID; + unsigned int MOD_ID; + double PedMean; + double PedStdi; + unsigned int SEC_ID; + }; + + std::map tmap; int starting_BCO; int rollover_value; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 7798d7078c..da3a2a42db 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -66,6 +66,8 @@ PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name) ReadGain(); RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937); gsl_rng_set(RandomGenerator, PHRandomSeed()); // fixed seed is handled in this funtcion + h_gain[0] = nullptr; + h_gain[1] = nullptr; return; } From 06c022f5944e11e9f44d327617a6880c626fc7c0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 25 May 2023 20:53:05 -0400 Subject: [PATCH 451/468] remove verbosity --- offline/packages/trackreco/MakeActsGeometry.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 8a98d0cd8d..4abf59703c 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -127,8 +127,6 @@ class MakeActsGeometry : public SubsysReco it->second = misalignment; return; } - - std::cout << "Passed an unknown trkr layer, misalignment factor will not be set for " << layer << std::endl; } double getSurfStepPhi() {return m_surfStepPhi;} From c9da4605238ec5027943bf09786d759c52f7fe94 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 16:37:58 -0400 Subject: [PATCH 452/468] all working --- offline/database/sphenixnpc/CDBUtils.cc | 66 +++++++++----------- offline/database/sphenixnpc/CDBUtils.h | 11 ++-- offline/database/sphenixnpc/SphenixClient.cc | 31 ++++++++- 3 files changed, 63 insertions(+), 45 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 6bf6f31f2b..134e17c63c 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -17,45 +17,40 @@ CDBUtils::CDBUtils(const std::string &globaltag) } -void CDBUtils::createGlobalTag(const std::string &tagname) +int CDBUtils::createGlobalTag(const std::string &tagname) { - cdbclient->createGlobalTag(tagname); + nlohmann::json resp = cdbclient->createGlobalTag(tagname); + int iret = resp["code"]; + nlohmann::json msgcont = resp["msg"]; + std::cout << msgcont << std::endl; + return iret; } int CDBUtils::deleteGlobalTag(const std::string &tagname) { nlohmann::json resp = cdbclient->deleteGlobalTag(tagname); int iret = resp["code"]; - if (iret != 0) - { - nlohmann::json msgcont = resp["msg"]; - std::cout << "message: " << msgcont << std::endl; - } + nlohmann::json msgcont = resp["msg"]; + std::cout << msgcont << std::endl; return iret; } -void CDBUtils::lockGlobalTag(const std::string &tagname) +int CDBUtils::lockGlobalTag(const std::string &tagname) { nlohmann::json resp = cdbclient->lockGlobalTag(tagname); int iret = resp["code"]; - if (iret != 0) - { - nlohmann::json msgcont = resp["msg"]; - std::cout << "message: " << msgcont << std::endl; - } - return; + nlohmann::json msgcont = resp["msg"]; + std::cout << msgcont << std::endl; + return iret; } -void CDBUtils::unlockGlobalTag(const std::string &tagname) +int CDBUtils::unlockGlobalTag(const std::string &tagname) { nlohmann::json resp = cdbclient->unlockGlobalTag(tagname); int iret = resp["code"]; - if (iret != 0) - { - nlohmann::json msgcont = resp["msg"]; - std::cout << "message: " << msgcont << std::endl; - } - return; + nlohmann::json msgcont = resp["msg"]; + std::cout << "message: " << msgcont << std::endl; + return iret; } void CDBUtils::clearCache() @@ -65,35 +60,36 @@ void CDBUtils::clearCache() std::string CDBUtils::getUrl(const std::string &type, uint64_t iov) { - return cdbclient->getUrl(type, iov); + nlohmann::json resp = cdbclient->getUrl(type, iov); + return resp["msg"]; } -int CDBUtils::createDomain(const std::string &domain) +int CDBUtils::createPayloadType(const std::string &pt) { - cdbclient->createDomain(domain); int iret = -1; nlohmann::json resp; - if (m_DomainCache.empty()) + if (m_PayloadTypeCache.empty()) { resp = cdbclient->getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; for (auto &it : msgcont.items()) { - std::string existent_domain = it.value().at("name"); - m_DomainCache.insert(existent_domain); + std::string existent_pt = it.value().at("name"); + m_PayloadTypeCache.insert(existent_pt); } } - if (m_DomainCache.find(domain) == m_DomainCache.end()) + if (m_PayloadTypeCache.find(pt) == m_PayloadTypeCache.end()) { - resp = cdbclient->createPayloadType(domain); + resp = cdbclient->createPayloadType(pt); iret = resp["code"]; if (iret == 0) { - m_DomainCache.insert(domain); + m_PayloadTypeCache.insert(pt); } } else { + std::cout << "PayloadTypeCache " << pt << " exists already" << std::endl; iret = 0; } return iret; @@ -138,7 +134,7 @@ int CDBUtils::insertPayload(const std::string &pl_type, const std::string &file_ } else { - std::cout << resp << std::endl; + std::cout << resp["msg"] << std::endl; } return iret; } @@ -158,7 +154,7 @@ int CDBUtils::insertPayload(const std::string &pl_type, const std::string &file_ } else { - std::cout << resp << std::endl; + std::cout << resp["msg"] << std::endl; } return iret; } @@ -167,10 +163,6 @@ int CDBUtils::setGlobalTag(const std::string &tagname) { nlohmann::json resp = cdbclient->setGlobalTag(tagname); int iret = resp["code"]; - if (iret != 0) - { - std::cout << "Error setting global tag, msg: " << resp["msg"] << std::endl; - } std::cout << "message: " << resp["msg"] << std::endl; return iret; } @@ -180,6 +172,7 @@ bool CDBUtils::isGlobalTagSet() return cdbclient->isGlobalTagSet(); } +/* int CDBUtils::createPayloadType(const std::string& pl_type) { if (! isGlobalTagSet()) @@ -203,6 +196,7 @@ int CDBUtils::createPayloadType(const std::string& pl_type) } return iret; } +*/ void CDBUtils::Verbosity(int i) { diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 5cc6229caa..908bf98912 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -15,11 +15,11 @@ class CDBUtils CDBUtils(); CDBUtils(const std::string &globaltag); virtual ~CDBUtils() = default; - void createGlobalTag(const std::string &tagname); + int createGlobalTag(const std::string &tagname); int setGlobalTag(const std::string &tagname); - void lockGlobalTag(const std::string &tagname); - void unlockGlobalTag(const std::string &tagname); - int createDomain(const std::string &domain); + int lockGlobalTag(const std::string &tagname); + int unlockGlobalTag(const std::string &tagname); + int createPayloadType(const std::string &domain); std::string getUrl(const std::string &type, uint64_t iov); int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); @@ -28,7 +28,6 @@ class CDBUtils void listPayloadTypes(); void clearCache(); bool isGlobalTagSet(); - int createPayloadType(const std::string& pl_type); void Verbosity(int i); int Verbosity() const { return m_Verbosity; } @@ -36,7 +35,7 @@ class CDBUtils int m_Verbosity = 0; SphenixClient *cdbclient = nullptr; std::string m_CachedGlobalTag; - std::set m_DomainCache; + std::set m_PayloadTypeCache; }; #endif // SPHENIXNPC_CDBUTILS_H diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 5a1907581a..7aa9a8c928 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -11,7 +11,7 @@ SphenixClient::SphenixClient() SphenixClient::SphenixClient(const std::string >_name): nopayloadclient::NoPayloadClient(gt_name) { -//cache_set_GlobalTag(globaltag); + m_CachedGlobalTag = gt_name; } nlohmann::json SphenixClient::getPayloadIOVs(long long iov) { @@ -40,8 +40,33 @@ nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const st return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); } -nlohmann::json SphenixClient::setGlobalTag(const std::string& name) { - return nopayloadclient::NoPayloadClient::setGlobalTag(name); +nlohmann::json SphenixClient::setGlobalTag(const std::string& gt_name) { + if (m_CachedGlobalTag == gt_name) + { + std::string message = "global tag already set to " + gt_name; + return {{"code", 0}, {"msg", message}}; + } +// check if the global tag exists before switching + bool found_gt = false; + nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); + nlohmann::json msgcont = resp["msg"]; + for (auto &it : msgcont.items()) + { + std::string exist_gt = it.value().at("name"); + if (exist_gt == gt_name) + { + found_gt = true; + break; + } + } + if (found_gt) + { + m_CachedGlobalTag = gt_name; + return nopayloadclient::NoPayloadClient::setGlobalTag(gt_name); + } + + std::string message = "global tag " + gt_name + " does not exist"; + return {{"code", -1}, {"msg", message}}; } nlohmann::json SphenixClient::clearCache() { From 87be8139a6b4b45f6c4c6c60d5cf5611dc84968f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 16:46:37 -0400 Subject: [PATCH 453/468] adjust for new cdb client --- offline/framework/ffamodules/CDBInterface.cc | 8 +++----- offline/framework/ffamodules/CDBInterface.h | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 68242a79a3..209b2b88e2 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -1,6 +1,6 @@ #include "CDBInterface.h" -#include +#include #include #include @@ -17,8 +17,6 @@ #include #include -//#include - #include #include // for uint64_t @@ -131,10 +129,10 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f } if (cdbclient == nullptr) { - cdbclient = new sphenixnpc(rc->get_StringFlag("CDB_GLOBALTAG")); + cdbclient = new SphenixClient(rc->get_StringFlag("CDB_GLOBALTAG")); } uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); - std::string return_url = cdbclient->getCalibrationFile(domain,timestamp); + std::string return_url = cdbclient->getUrl(domain,timestamp); if (return_url.empty()) { return_url = filename; diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index c86002cd18..41dd293586 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -11,7 +11,7 @@ #include // for tuple class PHCompositeNode; -class sphenixnpc; +class SphenixClient; class CDBInterface : public SubsysReco { @@ -31,7 +31,7 @@ class CDBInterface : public SubsysReco CDBInterface(const std::string &name = "CDBInterface"); static CDBInterface *__instance; - sphenixnpc *cdbclient = nullptr; + SphenixClient *cdbclient = nullptr; std::set> m_UrlVector; }; From 7b2b139118b3b00c8991fc8046c5071051721f8d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 19:19:03 -0400 Subject: [PATCH 454/468] return string for getCalibration --- offline/database/sphenixnpc/SphenixClient.cc | 8 ++++++++ offline/database/sphenixnpc/SphenixClient.h | 1 + offline/framework/ffamodules/CDBInterface.cc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 7aa9a8c928..c35a2688b7 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -17,6 +17,7 @@ SphenixClient::SphenixClient(const std::string >_name): nopayloadclient::NoPay nlohmann::json SphenixClient::getPayloadIOVs(long long iov) { return nopayloadclient::NoPayloadClient::getPayloadIOVs(0, iov); } + nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) { nlohmann::json resp = getPayloadIOVs(iov); if (resp["code"] != 0) return resp; @@ -30,6 +31,13 @@ nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) } return makeResp(payload_iov["payload_url"]); } + +std::string SphenixClient::getCalibration(const std::string& pl_type, long long iov) +{ + nlohmann::json resp = getUrl(pl_type, iov); + return resp["msg"]; +} + nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start) { return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start); diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index cb06408c71..17695a58ff 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -23,6 +23,7 @@ class SphenixClient : public nopayloadclient::NoPayloadClient nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end); nlohmann::json setGlobalTag(const std::string& name); nlohmann::json clearCache(); + std::string getCalibration(const std::string& pl_type, long long iov); nlohmann::json createGlobalTag1(const std::string &tagname); int createDomain(const std::string &domain); diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 209b2b88e2..b9773a82e9 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -132,7 +132,7 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f cdbclient = new SphenixClient(rc->get_StringFlag("CDB_GLOBALTAG")); } uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); - std::string return_url = cdbclient->getUrl(domain,timestamp); + std::string return_url = cdbclient->getCalibration(domain,timestamp); if (return_url.empty()) { return_url = filename; From ddf6080ef974c5c51ab64412ae13fa3b99bec3cf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 19:33:07 -0400 Subject: [PATCH 455/468] clang-tidy, clang-format --- offline/database/sphenixnpc/CDBUtils.cc | 12 +- offline/database/sphenixnpc/CDBUtils.h | 1 - offline/database/sphenixnpc/SphenixClient.cc | 148 ++++++------------- offline/database/sphenixnpc/SphenixClient.h | 17 +-- 4 files changed, 56 insertions(+), 122 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 134e17c63c..2528c90f4c 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -9,14 +9,14 @@ CDBUtils::CDBUtils() : cdbclient(new SphenixClient()) -{} +{ +} CDBUtils::CDBUtils(const std::string &globaltag) : cdbclient(new SphenixClient(globaltag)) { } - int CDBUtils::createGlobalTag(const std::string &tagname) { nlohmann::json resp = cdbclient->createGlobalTag(tagname); @@ -102,7 +102,7 @@ void CDBUtils::listGlobalTags() for (auto &it : msgcont.items()) { std::string exist_gt = it.value().at("name"); - std::cout << "global tag: " << exist_gt << std::endl; + std::cout << "global tag: " << exist_gt << std::endl; } return; } @@ -114,7 +114,7 @@ void CDBUtils::listPayloadTypes() for (auto &it : msgcont.items()) { std::string exist_pl = it.value().at("name"); - std::cout << "payload type: " << exist_pl << std::endl; + std::cout << "payload type: " << exist_pl << std::endl; } return; } @@ -126,7 +126,7 @@ int CDBUtils::insertPayload(const std::string &pl_type, const std::string &file_ std::cout << "No Global Tag set" << std::endl; return -1; } - nlohmann::json resp = cdbclient->insertPayload(pl_type,file_url,iov_start); + nlohmann::json resp = cdbclient->insertPayload(pl_type, file_url, iov_start); int iret = resp["code"]; if (iret != 0) { @@ -204,5 +204,5 @@ void CDBUtils::Verbosity(int i) { cdbclient->Verbosity(i); } - m_Verbosity = i; + m_Verbosity = i; } diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 908bf98912..002b4b858b 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -11,7 +11,6 @@ class SphenixClient; class CDBUtils { public: - CDBUtils(); CDBUtils(const std::string &globaltag); virtual ~CDBUtils() = default; diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index c35a2688b7..85439c433c 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -2,34 +2,39 @@ #include -#include #include +#include #include -SphenixClient::SphenixClient() -{} - -SphenixClient::SphenixClient(const std::string >_name): nopayloadclient::NoPayloadClient(gt_name) +SphenixClient::SphenixClient(const std::string& gt_name) + : nopayloadclient::NoPayloadClient(gt_name) { m_CachedGlobalTag = gt_name; } -nlohmann::json SphenixClient::getPayloadIOVs(long long iov) { - return nopayloadclient::NoPayloadClient::getPayloadIOVs(0, iov); +nlohmann::json SphenixClient::getPayloadIOVs(long long iov) +{ + return nopayloadclient::NoPayloadClient::getPayloadIOVs(0, iov); } -nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) { - nlohmann::json resp = getPayloadIOVs(iov); - if (resp["code"] != 0) return resp; - nlohmann::json payload_iovs = resp["msg"]; - if (!payload_iovs.contains(pl_type)) { - return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); - } - nlohmann::json payload_iov = payload_iovs[pl_type]; - if (payload_iov["minor_iov_end"] < iov) { - return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); - } - return makeResp(payload_iov["payload_url"]); +nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) +{ + nlohmann::json resp = getPayloadIOVs(iov); + if (resp["code"] != 0) + { + return resp; + } + nlohmann::json payload_iovs = resp["msg"]; + if (!payload_iovs.contains(pl_type)) + { + return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); + } + nlohmann::json payload_iov = payload_iovs[pl_type]; + if (payload_iov["minor_iov_end"] < iov) + { + return nopayloadclient::DataBaseException("No valid payload with type " + pl_type).jsonify(); + } + return makeResp(payload_iov["payload_url"]); } std::string SphenixClient::getCalibration(const std::string& pl_type, long long iov) @@ -39,26 +44,29 @@ std::string SphenixClient::getCalibration(const std::string& pl_type, long long } nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const std::string& file_url, - long long iov_start) { - return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start); + long long iov_start) +{ + return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start); } nlohmann::json SphenixClient::insertPayload(const std::string& pl_type, const std::string& file_url, - long long iov_start, long long iov_end) { - return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); + long long iov_start, long long iov_end) +{ + return nopayloadclient::NoPayloadClient::insertPayload(pl_type, file_url, 0, iov_start, 0, iov_end); } -nlohmann::json SphenixClient::setGlobalTag(const std::string& gt_name) { +nlohmann::json SphenixClient::setGlobalTag(const std::string& gt_name) +{ if (m_CachedGlobalTag == gt_name) { std::string message = "global tag already set to " + gt_name; return {{"code", 0}, {"msg", message}}; } -// check if the global tag exists before switching + // check if the global tag exists before switching bool found_gt = false; nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto &it : msgcont.items()) + for (auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); if (exist_gt == gt_name) @@ -77,86 +85,15 @@ nlohmann::json SphenixClient::setGlobalTag(const std::string& gt_name) { return {{"code", -1}, {"msg", message}}; } -nlohmann::json SphenixClient::clearCache() { - return nopayloadclient::NoPayloadClient::clearCache(); -} - -nlohmann::json SphenixClient::createGlobalTag1(const std::string &tagname) +nlohmann::json SphenixClient::clearCache() { - if (tagname == m_CachedGlobalTag) // global tag already set - { - std::string message = "global tag already set to " + tagname; - return {{"code", 0}, {"msg", message}}; - } -// check if the global tag exists already - bool found_gt = false; - nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); - nlohmann::json msgcont = resp["msg"]; - for (auto &it : msgcont.items()) - { - std::string exist_gt = it.value().at("name"); - std::cout << "global tag: " << exist_gt << std::endl; - if (exist_gt == tagname) - { - found_gt = true; - break; - } - } - if (found_gt) - { - std::string message = "global tag " + tagname + " already exists"; - return {{"code", 0}, {"msg", message}}; - } - resp = nopayloadclient::NoPayloadClient::createGlobalTag(tagname); - int iret = resp["code"]; - if (iret != 0) - { - std::cout << "Error creating global tag, msg: " << resp["msg"] << std::endl; - } - else - { - nopayloadclient::NoPayloadClient::setGlobalTag(tagname); - m_CachedGlobalTag = tagname; - clearCache(); - std::cout << "SphenixClient: Created new global tag " << tagname << std::endl; - } - return resp; + return nopayloadclient::NoPayloadClient::clearCache(); } -nlohmann::json SphenixClient::setGlobalTag1(const std::string &tagname) -{ - if (tagname == m_CachedGlobalTag) // global tag already set - { - std::string message = "global tag already set to " + tagname; - return {{"code", 0}, {"msg", message}}; - } - bool found_gt = false; - nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); - nlohmann::json msgcont = resp["msg"]; - for (auto &it : msgcont.items()) - { - std::string exist_gt = it.value().at("name"); - std::cout << "global tag: " << exist_gt << std::endl; - if (exist_gt == tagname) - { - found_gt = true; - break; - } - } - if (found_gt) - { - m_CachedGlobalTag = tagname; - resp = nopayloadclient::NoPayloadClient::setGlobalTag(tagname); - return resp; - } -std::string message = "global tag " + tagname + " does not exist"; - return {{"code", -1}, {"msg", message}}; -} - -int SphenixClient::cache_set_GlobalTag(const std::string &tagname) +int SphenixClient::cache_set_GlobalTag(const std::string& tagname) { int iret = 0; - if (tagname == m_CachedGlobalTag) // global tag already set + if (tagname == m_CachedGlobalTag) // global tag already set { return iret; } @@ -165,10 +102,10 @@ int SphenixClient::cache_set_GlobalTag(const std::string &tagname) bool found_gt = false; nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto &it : msgcont.items()) + for (auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); - std::cout << "global tag: " << exist_gt << std::endl; + std::cout << "global tag: " << exist_gt << std::endl; if (exist_gt == tagname) { found_gt = true; @@ -191,7 +128,7 @@ int SphenixClient::cache_set_GlobalTag(const std::string &tagname) return iret; } -int SphenixClient::createDomain(const std::string &domain) +int SphenixClient::createDomain(const std::string& domain) { int iret = -1; nlohmann::json resp; @@ -199,7 +136,7 @@ int SphenixClient::createDomain(const std::string &domain) { resp = nopayloadclient::NoPayloadClient::getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; - for (auto &it : msgcont.items()) + for (auto& it : msgcont.items()) { std::string existent_domain = it.value().at("name"); m_DomainCache.insert(existent_domain); @@ -229,4 +166,3 @@ bool SphenixClient::isGlobalTagSet() } return true; } - diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 17695a58ff..9e686c1118 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -5,7 +5,6 @@ #include - #include #include #include @@ -14,28 +13,28 @@ class SphenixClient : public nopayloadclient::NoPayloadClient { public: - SphenixClient(); - SphenixClient(const std::string &globaltag); + SphenixClient() = default; + SphenixClient(const std::string& globaltag); virtual ~SphenixClient() = default; + // make clang happy, since we use our own without overriding the base class methods + using nopayloadclient::NoPayloadClient::getPayloadIOVs; + nlohmann::json getPayloadIOVs(long long iov); - nlohmann::json getUrl(const std::string& pl_type, long long iov); + nlohmann::json getUrl(const std::string& pl_type, long long iov); nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start); nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end); nlohmann::json setGlobalTag(const std::string& name); nlohmann::json clearCache(); std::string getCalibration(const std::string& pl_type, long long iov); - nlohmann::json createGlobalTag1(const std::string &tagname); - int createDomain(const std::string &domain); - nlohmann::json setGlobalTag1(const std::string &tagname); - int cache_set_GlobalTag(const std::string &name); + int createDomain(const std::string& domain); + int cache_set_GlobalTag(const std::string& name); bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } private: int m_Verbosity = 0; - uint64_t m_CachedIOV = 0; std::string m_CachedGlobalTag; std::set m_DomainCache; }; From 7e22b6c52c2c0edae847efc2e69ff0c13f41a377 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 19:56:19 -0400 Subject: [PATCH 456/468] fix cppcheck warnings --- offline/database/sphenixnpc/CDBUtils.h | 7 ++++++- offline/database/sphenixnpc/SphenixClient.cc | 5 ++--- offline/database/sphenixnpc/SphenixClient.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 002b4b858b..1fe25d02f0 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -12,7 +12,12 @@ class CDBUtils { public: CDBUtils(); - CDBUtils(const std::string &globaltag); + explicit CDBUtils(const std::string &globaltag); + + // delete copy ctor and assignment operator (cppcheck) + explicit CDBUtils(const CDBUtils&) = delete; + CDBUtils& operator=(const CDBUtils&) = delete; + virtual ~CDBUtils() = default; int createGlobalTag(const std::string &tagname); int setGlobalTag(const std::string &tagname); diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 85439c433c..32af0f31ad 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -8,9 +8,8 @@ SphenixClient::SphenixClient(const std::string& gt_name) : nopayloadclient::NoPayloadClient(gt_name) -{ - m_CachedGlobalTag = gt_name; -} + , m_CachedGlobalTag(gt_name) +{} nlohmann::json SphenixClient::getPayloadIOVs(long long iov) { diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 9e686c1118..15c491f2cd 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -14,7 +14,7 @@ class SphenixClient : public nopayloadclient::NoPayloadClient { public: SphenixClient() = default; - SphenixClient(const std::string& globaltag); + explicit SphenixClient(const std::string& globaltag); virtual ~SphenixClient() = default; // make clang happy, since we use our own without overriding the base class methods using nopayloadclient::NoPayloadClient::getPayloadIOVs; From 91f63bbbe126ab95e9cdf693e8f3ff7991e1a574 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 20:54:14 -0400 Subject: [PATCH 457/468] fix cppcheck warning --- offline/packages/NodeDump/macro/run_dump.C | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/NodeDump/macro/run_dump.C b/offline/packages/NodeDump/macro/run_dump.C index db735d5331..f596812d53 100644 --- a/offline/packages/NodeDump/macro/run_dump.C +++ b/offline/packages/NodeDump/macro/run_dump.C @@ -6,10 +6,12 @@ #include #include +// cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libfun4all.so) +// cppcheck-suppress unknownMacro R__LOAD_LIBRARY(libphnodedump.so) -void run_dump(const char *infile, const int evts=100) +void run_dump(const std::string &infile, const int evts=100) { gSystem->Load("libg4dst.so"); Fun4AllServer* se = Fun4AllServer::instance(); From fcd2d9a9c9b85ae86840b368ea35801136a7c4fe Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 20:55:09 -0400 Subject: [PATCH 458/468] fix cppcheck warning --- offline/packages/TrackingDiagnostics/TrackResiduals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 6ea73562df..d3e50bae38 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -32,7 +32,7 @@ class TrackResiduals : public SubsysReco int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void outfileName(std::string name) { m_outfileName = name; } + void outfileName(std::string &name) { m_outfileName = name; } void alignment(bool align) { m_doAlignment = align; } private: From d237989b0e93daff699903ef732168ecdc833b42 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 May 2023 22:29:14 -0400 Subject: [PATCH 459/468] suppress clang warning (needs fix in nopayloadclient) --- offline/database/sphenixnpc/configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/offline/database/sphenixnpc/configure.ac b/offline/database/sphenixnpc/configure.ac index 75794b946c..13a1c84f06 100644 --- a/offline/database/sphenixnpc/configure.ac +++ b/offline/database/sphenixnpc/configure.ac @@ -9,5 +9,11 @@ if test $ac_cv_prog_gxx = yes; then CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" fi +case $CXX in + clang++) + CXXFLAGS="$CXXFLAGS -Wno-overloaded-virtual" + ;; +esac + AC_CONFIG_FILES([Makefile]) AC_OUTPUT From eb63da04194c6e3c35489cc2c424c3b7c3b7bb7f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 27 May 2023 00:13:40 -0400 Subject: [PATCH 460/468] iwyu to trigger jenkins --- .../g4simulation/g4histos/G4RawTowerTTree.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/simulation/g4simulation/g4histos/G4RawTowerTTree.cc b/simulation/g4simulation/g4histos/G4RawTowerTTree.cc index fef84a923b..f2aa714cb4 100644 --- a/simulation/g4simulation/g4histos/G4RawTowerTTree.cc +++ b/simulation/g4simulation/g4histos/G4RawTowerTTree.cc @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -21,10 +21,6 @@ #include #include // for operator<<, endl, basic_... -#include // for _Rb_tree_const_iterator -#include // for pair - -using namespace std; G4RawTowerTTree::G4RawTowerTTree(const std::string &name) : SubsysReco(name) @@ -39,9 +35,9 @@ int G4RawTowerTTree::Init(PHCompositeNode *topNode) { if (_detector.empty()) { - cout << "Detector not set via Detector() method" << endl; - cout << "(it is the name appended to the G4TOWER_ nodename)" << endl; - cout << "you do not want to run like this, exiting now" << endl; + std::cout << "Detector not set via Detector() method" << std::endl; + std::cout << "(it is the name appended to the G4TOWER_ nodename)" << std::endl; + std::cout << "you do not want to run like this, exiting now" << std::endl; gSystem->Exit(1); } hm = new Fun4AllHistoManager("TOWERHIST"); @@ -63,10 +59,10 @@ int G4RawTowerTTree::process_event(PHCompositeNode *topNode) RawTowerGeomContainer *rawtowergeom = findNode::getClass(topNode, _towergeomnodename); // RawTowerContainer *g4towers = findNode::getClass(topNode, _towernodename); - TowerInfoContainer *g4towers = findNode::getClass(topNode, _towernodename); + TowerInfoContainer *g4towers = findNode::getClass(topNode, _towernodename); if (!g4towers) { - cout << "could not find " << _towernodename << endl; + std::cout << "could not find " << _towernodename << std::endl; gSystem->Exit(1); } From acc4af8ad2009a7c4734e72b7752e1d340bbb95c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 27 May 2023 09:47:49 -0400 Subject: [PATCH 461/468] use pragma to suppress warning coming from nopayloadclient --- offline/database/sphenixnpc/SphenixClient.h | 3 +++ offline/database/sphenixnpc/configure.ac | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 15c491f2cd..f0d55e5141 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -21,7 +21,10 @@ class SphenixClient : public nopayloadclient::NoPayloadClient nlohmann::json getPayloadIOVs(long long iov); nlohmann::json getUrl(const std::string& pl_type, long long iov); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverloaded-virtual" nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start); +#pragma GCC diagnostic pop nlohmann::json insertPayload(const std::string& pl_type, const std::string& file_url, long long iov_start, long long iov_end); nlohmann::json setGlobalTag(const std::string& name); nlohmann::json clearCache(); diff --git a/offline/database/sphenixnpc/configure.ac b/offline/database/sphenixnpc/configure.ac index 13a1c84f06..75794b946c 100644 --- a/offline/database/sphenixnpc/configure.ac +++ b/offline/database/sphenixnpc/configure.ac @@ -9,11 +9,5 @@ if test $ac_cv_prog_gxx = yes; then CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" fi -case $CXX in - clang++) - CXXFLAGS="$CXXFLAGS -Wno-overloaded-virtual" - ;; -esac - AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 1e5cd1306d51d5e2b9cb1d07693620d422fc3543 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 27 May 2023 19:54:31 -0400 Subject: [PATCH 462/468] use separate name for template payload type --- .../packages/CaloReco/CaloWaveformProcessing.cc | 2 +- .../packages/CaloReco/CaloWaveformProcessing.h | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index ef120fb246..aa7d0e005d 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -18,7 +18,7 @@ void CaloWaveformProcessing::initialize_processing() if (m_processingtype == CaloWaveformProcessing::TEMPLATE) { std::string calibrations_repo_template = std::string(calibrationsroot) + "/WaveformProcessing/templates/" + m_template_input_file; - url_template = CDBInterface::instance()->getUrl(m_template_input_file, calibrations_repo_template); + url_template = CDBInterface::instance()->getUrl(m_template_name, calibrations_repo_template); m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); m_Fitter->set_nthreads(get_nthreads()); diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index 86a518ad53..c79dd99d1c 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -20,10 +20,7 @@ class CaloWaveformProcessing : public SubsysReco FAST = 3, }; - CaloWaveformProcessing() - : m_processingtype(CaloWaveformProcessing::TEMPLATE) - , m_template_input_file("CEMC_TEMPLATE") - , m_model_name("CEMC_ONNX"){}; + CaloWaveformProcessing() {} ~CaloWaveformProcessing() override {} void set_processing_type(CaloWaveformProcessing::process modelno) @@ -42,6 +39,12 @@ class CaloWaveformProcessing : public SubsysReco m_template_input_file = template_input_file; return; } + + void set_template_name(const std::string &template_name) + { + m_template_name = template_name; + return; + } void set_model_file(const std::string &model_name) { m_model_name = model_name; @@ -67,15 +70,16 @@ class CaloWaveformProcessing : public SubsysReco private: CaloWaveformFitting *m_Fitter = nullptr; - CaloWaveformProcessing::process m_processingtype = CaloWaveformProcessing::NONE; + CaloWaveformProcessing::process m_processingtype = CaloWaveformProcessing::TEMPLATE; int _nthreads = 1; int _nsoftwarezerosuppression = 40; bool _bdosoftwarezerosuppression = false; std::string m_template_input_file; std::string url_template; + std::string m_template_name = "NONE"; std::string url_onnx; - std::string m_model_name; + std::string m_model_name = "CEMC_ONNX"; }; #endif From a9674feab36cc44e254b3b1ad3e4227799acc9b4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 27 May 2023 19:55:09 -0400 Subject: [PATCH 463/468] restore old behavior, return empty string if no payload found --- offline/database/sphenixnpc/SphenixClient.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 32af0f31ad..31646df659 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -39,6 +39,14 @@ nlohmann::json SphenixClient::getUrl(const std::string& pl_type, long long iov) std::string SphenixClient::getCalibration(const std::string& pl_type, long long iov) { nlohmann::json resp = getUrl(pl_type, iov); + if (resp["code"] != 0) + { + if (m_Verbosity> 0) + { + std::cout << resp["msg"] << std::endl; + } + return ""; + } return resp["msg"]; } From 3d03b9b07f49b0257cc9b20d595e819b57cdee3d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 29 May 2023 11:45:14 -0400 Subject: [PATCH 464/468] Remove verbosity Fix seg fault --- .../g4tpc/PHG4TpcElectronDrift.cc | 4 +- .../g4simulation/g4tpc/TpcClusterBuilder.cc | 53 +++++++++++-------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 2604b651a9..29ef025a89 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -422,7 +422,9 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) if ( std::abs(prior_g4hit->get_x(0)-hiter->second->get_x(0)) > max_g4hitstep || std::abs(prior_g4hit->get_y(0)-hiter->second->get_y(0)) > max_g4hitstep ) { - truth_clusterer.cluster_hits(truth_track); + if(truth_track) { + truth_clusterer.cluster_hits(truth_track); + } } } prior_g4hit = hiter->second; diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index 9fd95f11b1..d68e5d0635 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -1,6 +1,5 @@ #include "TpcClusterBuilder.h" -/* #include */ -#include +#include #include #include #include @@ -39,7 +38,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { //----------------------------------------------------- // from TpcClusterizer.cc ~line: 837 //----------------------------------------------------- - + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr) @@ -51,7 +50,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { int side = TpcDefs::getSide(hitsetitr->first); unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); PHG4TpcCylinderGeom *layergeom = geom_container->GetLayerCellGeom(layer); - + //get the maximum and minimum phi and time unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); unsigned short NPhiBinsSector = NPhiBins/12; @@ -67,7 +66,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { unsigned short phioffset = PhiOffset; unsigned short tbins = NTBinsSide; unsigned short toffset = TOffset ; - + // loop over the hits in this cluster double t_sum = 0.0; double adc_sum = 0.0; @@ -78,7 +77,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { // double phi2_sum = 0.0; double radius = layergeom->get_radius(); // returns center of layer - + int phibinhi = -1; int phibinlo = INT_MAX; int tbinhi = -1; @@ -87,11 +86,15 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { auto ihit_list = hitset->getHits(); double sum_energy { 0. }; // energy = 4 * adc at this point + for(auto ihit = ihit_list.first; ihit != ihit_list.second; ++ihit){ int e = ihit->second->getEnergy(); int adc = ihit->second->getAdc(); if (adc*4 != e) { - cout << " FIXME: energy: " << ihit->second->getEnergy() << " vs adc " << ihit->second->getAdc() << endl; + if(verbosity > 1) + { + cout << " FIXME: energy: " << ihit->second->getEnergy() << " vs adc " << ihit->second->getAdc() << endl; + } } sum_energy += ihit->second->getEnergy(); } @@ -100,6 +103,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { // FIXME -- see why the hits are so scattered std::set v_iphi, v_it; // FIXME std::map m_iphi, m_it; // FIXME + for(auto iter = ihit_list.first; iter != ihit_list.second; ++iter){ unsigned int adc = iter->second->getAdc(); if (adc <= 0) continue; @@ -124,12 +128,17 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { if(iphi<0 || iphi>=phibins){ //FIXME - std::cout << "WARNING phibin out of range: " << iphi << " | " << phibins << std::endl; + if(verbosity > 1) + { + std::cout << "WARNING phibin out of range: " << iphi << " | " << phibins << std::endl; + } continue; } if(it<0 || it>=tbins){ //FIXME - std::cout << "WARNING z bin out of range: " << it << " | " << tbins << std::endl; + if(verbosity > 1) { + std::cout << "WARNING z bin out of range: " << it << " | " << tbins << std::endl; + } continue; } @@ -154,18 +163,17 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { adc_sum += adc; } - - if (true) { // FIXME + + if (false) { // FIXME int _phi_sum = 0; for (auto _ : m_iphi) _phi_sum += _.second; - if (_phi_sum != adc_sum) cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << endl; + if (_phi_sum != adc_sum && verbosity > 1) std::cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << std::endl; int _t_sum = 0; for (auto _ : m_it) _t_sum += _.second; - if (_t_sum != adc_sum) cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << endl; + if (_t_sum != adc_sum && verbosity > 1) std::cout << " FIXME z1 " << adc_sum << " delta phi: " << (adc_sum - _phi_sum) << std::endl; } - // This is the global position double clusiphi = iphi_sum / adc_sum; double clusphi = layergeom->get_phi(clusiphi); @@ -181,7 +189,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; - if (tsize < 0) cout << " FIXME z4 tsize: " << ((int)tsize) << " " << tbinlo << " to " << tbinhi << endl; + if (tsize < 0 && verbosity > 1) std::cout << " FIXME z4 tsize: " << ((int)tsize) << " " << tbinlo << " to " << tbinhi << std::endl; // ------------------------------------------------- // ------------------------------------------------- @@ -249,15 +257,15 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { } cout << endl; } - } // end debug printing - + } + // get the global vector3 to then get the surface local phi and z Acts::Vector3 global(clusx, clusy, clusz); TrkrDefs::subsurfkey subsurfkey = 0; Surface surface = m_tGeometry->get_tpc_surface_from_coords( hitsetkey, global, subsurfkey); - + if (!surface) { if (verbosity) std::cout << "Can't find the surface! with hitsetkey " << ((int)hitsetkey) << std::endl; continue; @@ -267,11 +275,11 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { clust = clust + m_sampa_tbias; global *= Acts::UnitConstants::cm; - + Acts::Vector3 local=surface->transform(m_tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; - - auto cluster = new TrkrClusterv4; // + + auto cluster = new TrkrClusterv5; // cluster->setAdc(adc_sum); /* cluster->setOverlap(ntouch); */ /* cluster->setEdge(nedge); */ @@ -280,13 +288,12 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) { cluster->setSubSurfKey(subsurfkey); cluster->setLocalX(local(0)); cluster->setLocalY(clust); - + // add the clusterkey auto empl = hitsetkey_cnt.try_emplace(hitsetkey,0); if (!empl.second) empl.first->second += 1; TrkrDefs::cluskey cluskey = TrkrDefs::genClusKey(hitsetkey, hitsetkey_cnt[hitsetkey]); m_clusterlist->addClusterSpecifyKey(cluskey, cluster); - track->addCluster(cluskey); } m_hits->Reset(); From bbc9327405225e854dbfb6f5630567dd1cb4b724 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 30 May 2023 00:02:04 -0400 Subject: [PATCH 465/468] sync with master --- simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 4fa0983e98..414fc6fff6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -765,6 +765,7 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) truthtracks->identify(); } + if (Verbosity()>800) { truth_clusterer.print(truthtracks); truth_clusterer.print_file(truthtracks,"drift_clusters.txt"); } From c2998d252dd2e4118a29e27a1d2dc837ef3016a9 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 30 May 2023 00:10:19 -0400 Subject: [PATCH 466/468] sync with master --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h index d368d491b1..a5bdad188b 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.h @@ -118,12 +118,8 @@ class PHG4TpcPadPlaneReadout : public PHG4TpcPadPlane // return random distribution of number of electrons after amplification of GEM for each initial ionizing electron double getSingleEGEMAmplification(); gsl_rng *RandomGenerator; -<<<<<<< HEAD -======= TH2F *h_gain[2]; - ->>>>>>> 1156c7778bc35f1f1db5ffc22d5632a9e99a9c8b }; #endif From d92424af393e1a7299f4d4af29e6b9a0b18eaf14 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 May 2023 08:47:37 -0400 Subject: [PATCH 467/468] add type 21, Jet >= 20GeV, add embed in pAu --- offline/framework/frog/CreateFileList.pl | 51 ++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 13a16bb972..a091eaa2f3 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -55,7 +55,8 @@ "17" => "HF pythia8 D0 pi-k Jets ptmin = 5GeV ", "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV", "19" => "JS pythia8 Jet ptmin = 40GeV", - "20" => "hijing pAu (0-10fm) pileup 0-10fm" + "20" => "hijing pAu (0-10fm) pileup 0-10fm", + "21" => "JS pythia8 Jet ptmin = 20GeV" ); my %pileupdesc = ( @@ -79,7 +80,7 @@ my $pmax; my $production; my $momentum; -GetOptions('embed' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); +GetOptions('embed:s' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); my $filenamestring; my %filetypes = (); my %notlike = (); @@ -232,7 +233,15 @@ { if (defined $embed) { - $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); + print "embed is $embed\n"; + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm_%s_bkg_0_10fm",$filenamestring, $pAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); + } } else { @@ -386,6 +395,32 @@ $pileupstring = $pAu_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 21) + { + $embedok = 1; + $filenamestring = "pythia8_Jet20"; + if (! defined $nopileup) + { + if (defined $embed) + { + print "embed is $embed\n"; + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm_%s_bkg_0_10fm",$filenamestring, $pAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm_%s_bkg_0_20fm",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s_%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { print "no production type $prodtype\n"; @@ -399,6 +434,13 @@ print "Embedding not implemented for type $prodtype\n"; exit(1); } +if (defined $embed) +{ + if ($embed ne "pau" && $embed ne "auau") + { + push(@ARGV,$embed); + } +} my $filenamestring_with_runnumber = sprintf("%s\-%010d-",$filenamestring,$runnumber); if ($#ARGV < 0) @@ -407,7 +449,8 @@ { print "usage: CreateFileLists.pl -type \n"; print "parameters:\n"; - print "-embed : pp embedded into hijing (only for pp types)\n"; + print "-embed : pp embedded into AuAu hijing (only for pp types)\n"; + print "-embed pau : embedded into pAu (only for pp types\n"; print "-l : last segment\n"; print "-n : \n"; print "-nopileup : without pileup\n"; From 15720f56196ad0dfc39cbc03f89b3276bcaceb0e Mon Sep 17 00:00:00 2001 From: cdean-github Date: Tue, 30 May 2023 13:09:46 -0400 Subject: [PATCH 468/468] Changed speed of light in decay time calculation to reflect new mag. field value --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 2 +- offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index a6654b9e03..e4080d1280 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -618,7 +618,7 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida goodCandidate = false; - const float speed = 2.99792458e-1; + const float speed = 2.99792458e-2; calculated_decayTime /= speed; if (calculated_fdchi2 >= m_fdchi2 && calculated_ipchi2 <= m_mother_ipchi2 && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength)) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 1114eb5f85..dcac3ecfcd 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -283,7 +283,7 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, std::vector intermediates, int nPVs, int multiplicity) { - const float speedOfLight = 2.99792458e-1; + const float speedOfLight = 2.99792458e-2; KFParticle temp; KFParticle* daughterArray = &daughters[0];