diff --git a/Modules/MUON/MCH/CMakeLists.txt b/Modules/MUON/MCH/CMakeLists.txt index 208adabf27..ccd5d2b402 100644 --- a/Modules/MUON/MCH/CMakeLists.txt +++ b/Modules/MUON/MCH/CMakeLists.txt @@ -7,8 +7,11 @@ set(SRCS src/Decoding.cxx src/GlobalHistogram.cxx src/PedestalsTask.cxx - src/PhysicsTask.cxx + src/PhysicsTaskDigits.cxx + src/PhysicsTaskPreclusters.cxx src/PedestalsCheck.cxx + src/PhysicsCheck.cxx + src/TH1MCHReductor.cxx ) set(HEADERS @@ -16,8 +19,11 @@ set(HEADERS include/MCH/Decoding.h include/MCH/GlobalHistogram.h include/MCH/PedestalsTask.h - include/MCH/PhysicsTask.h + include/MCH/PhysicsTaskDigits.h + include/MCH/PhysicsTaskPreclusters.h include/MCH/PedestalsCheck.h + include/MCH/PhysicsCheck.h + include/MCH/TH1MCHReductor.h ) # ---- Library ---- @@ -31,7 +37,7 @@ target_include_directories( ) target_link_libraries(${MODULE_NAME} PUBLIC QualityControl O2::CommonDataFormat O2::GPUCommon - $ O2::MCHMappingImpl3 O2::MCHMappingSegContour) + $ O2::MCHMappingImpl3 O2::MCHMappingSegContour O2::MCHRawDecoder O2::MCHPreClustering) target_compile_definitions(${MODULE_NAME} PRIVATE $<$:MCH_HAS_MAPPING_FACTORY>) @@ -49,8 +55,11 @@ add_root_dictionary(${MODULE_NAME} include/MCH/Decoding.h include/MCH/GlobalHistogram.h include/MCH/PedestalsTask.h - include/MCH/PhysicsTask.h + include/MCH/PhysicsTaskDigits.h + include/MCH/PhysicsTaskPreclusters.h + include/MCH/PhysicsCheck.h include/MCH/PedestalsCheck.h + include/MCH/TH1MCHReductor.h include/MCH/sampa_header.h LINKDEF include/MCH/LinkDef.h) diff --git a/Modules/MUON/MCH/include/MCH/Decoding.h b/Modules/MUON/MCH/include/MCH/Decoding.h index 8fec2c76e0..34562162df 100644 --- a/Modules/MUON/MCH/include/MCH/Decoding.h +++ b/Modules/MUON/MCH/include/MCH/Decoding.h @@ -37,6 +37,7 @@ struct SampaHit { uint32_t size, time; std::vector samples; uint64_t csum; + int32_t delta; MapPad pad; }; @@ -49,7 +50,7 @@ struct DualSampa { int nsyn2Bits; // Nb of words waiting synchronization Sampa::SampaHeaderStruct header; // current channel header unsigned long bxc[2]; - uint32_t csize, ctime, cid, sample; + int32_t csize, ctime, cid, sample; int chan_addr[2]; uint64_t packetsize; int nbHit; // incremented each time a header packet is received for this card @@ -57,6 +58,7 @@ struct DualSampa { int ndata[2][32]; int nclus[2][32]; double pedestal[2][32], noise[2][32]; + int32_t min[2][32], max[2][32], delta[2][32]; SampaHit hit; }; @@ -85,13 +87,30 @@ class Decoder std::vector& getDigits() { return mDigits; } void reset(); - int32_t getMapCRU(int cruid, int linkid) { return mMapCRU.getLink(cruid, linkid); } + int32_t getMapCRU(int cruid, int linkid) + { + return mMapCRU.getLink(cruid, linkid); + } + + bool getMapCRUInv(int32_t link_id, int32_t& cruid, int32_t& crulink) + { + return mMapCRU.getLinkInv(link_id, cruid, crulink); + } + int32_t getMapFEC(uint32_t link_id, uint32_t ds_addr, uint32_t& de, uint32_t& dsid) { if (!mMapFEC.getDSMapping(link_id, ds_addr, de, dsid)) return -1; return de; } + + int32_t getMapFECinv(uint32_t de, uint32_t dsid, uint32_t& link_id, uint32_t& ds_addr) + { + if (!mMapFEC.getDSMappingInv(de, dsid, link_id, ds_addr)) + return -1; + return link_id; + } + MapFEC& getMapFEC() { return mMapFEC; } private: diff --git a/Modules/MUON/MCH/include/MCH/GlobalHistogram.h b/Modules/MUON/MCH/include/MCH/GlobalHistogram.h index b90936f9dc..b285b9e0a7 100644 --- a/Modules/MUON/MCH/include/MCH/GlobalHistogram.h +++ b/Modules/MUON/MCH/include/MCH/GlobalHistogram.h @@ -34,8 +34,11 @@ class GlobalHistogram : public TH2F // add the histograms of the individual detection elements void add(std::map& histB, std::map& histNB); + // replace the contents with the histograms of the individual detection elements, including null bins + void set_includeNull(std::map& histB, std::map& histNB); + // replace the contents with the histograms of the individual detection elements - void set(std::map& histB, std::map& histNB, bool doAverage = true); + void set(std::map& histB, std::map& histNB, bool doAverage = true, bool includeNullBins = false); }; } // namespace muonchambers diff --git a/Modules/MUON/MCH/include/MCH/LinkDef.h b/Modules/MUON/MCH/include/MCH/LinkDef.h index 25f29f8858..e0acf1e4cf 100644 --- a/Modules/MUON/MCH/include/MCH/LinkDef.h +++ b/Modules/MUON/MCH/include/MCH/LinkDef.h @@ -6,6 +6,9 @@ //#pragma link C++ class o2::quality_control_modules::muonchambers::Decoder+; //#pragma link C++ class o2::quality_control_modules::muonchambers::MuonChambersMapping+; #pragma link C++ class o2::quality_control_modules::muonchambers::PedestalsTask + ; -#pragma link C++ class o2::quality_control_modules::muonchambers::PhysicsTask + ; +#pragma link C++ class o2::quality_control_modules::muonchambers::PhysicsTaskDigits + ; +#pragma link C++ class o2::quality_control_modules::muonchambers::PhysicsTaskPreclusters + ; #pragma link C++ class o2::quality_control_modules::muonchambers::PedestalsCheck + ; +#pragma link C++ class o2::quality_control_modules::muonchambers::PhysicsCheck + ; +#pragma link C++ class o2::quality_control_modules::muonchambers::TH1MCHReductor + ; #endif diff --git a/Modules/MUON/MCH/include/MCH/Mapping.h b/Modules/MUON/MCH/include/MCH/Mapping.h index 897b8cc78f..8bc8a7eb98 100644 --- a/Modules/MUON/MCH/include/MCH/Mapping.h +++ b/Modules/MUON/MCH/include/MCH/Mapping.h @@ -11,6 +11,7 @@ #include "QualityControl/TaskInterface.h" #define MCH_DE_MAX 2000 +#define MCH_DSID_MAX 2047 #define MCH_MAX_CRU_ID 31 #define MCH_MAX_CRU_IN_FLP 31 #define LINKID_MAX 0x7FF @@ -33,6 +34,16 @@ class MapSolar ~MapSolar(); }; +class MapSolarInv +{ + public: + int mCruId; // CRU ID + int mCruLink; // CRU link + + MapSolarInv(); + ~MapSolarInv(); +}; + class MapDualSampa { public: @@ -44,6 +55,16 @@ class MapDualSampa ~MapDualSampa(); }; +class MapDualSampaInv +{ + public: + int mLink; // detector element + int mAddress; // DS index + + MapDualSampaInv(); + ~MapDualSampaInv(); +}; + class MapPad { public: @@ -67,24 +88,28 @@ class MapCRU { MapSolar mSolarMap[MCH_MAX_CRU_IN_FLP][24]; + MapSolarInv mSolarMapInv[LINKID_MAX + 1]; public: MapCRU(); bool readMapping(std::string mapFile); int32_t getLink(int32_t c, int32_t l); + bool getLinkInv(uint32_t link_id, int32_t& c, int32_t& l); }; class MapFEC { MapDualSampa mDsMap[LINKID_MAX + 1][40]; + MapDualSampaInv mDsMapInv[MCH_DE_MAX + 1][MCH_DSID_MAX + 1]; public: MapFEC(); bool readDSMapping(std::string mapFile); bool getDSMapping(uint32_t link_id, uint32_t ds_addr, uint32_t& de, uint32_t& dsid); + bool getDSMappingInv(uint32_t de, uint32_t dsid, uint32_t& link_id, uint32_t& ds_addr); bool getPadByLinkID(uint32_t link_id, uint32_t ds_addr, uint32_t dsch, MapPad& pad); - bool getPadByDE(uint32_t de, uint32_t dsis, uint32_t dsch, MapPad& pad); + bool getPadByDE(uint32_t de, uint32_t dsid, uint32_t dsch, MapPad& pad); }; } // namespace muonchambers diff --git a/Modules/MUON/MCH/include/MCH/PhysicsCheck.h b/Modules/MUON/MCH/include/MCH/PhysicsCheck.h new file mode 100644 index 0000000000..3e400f85f3 --- /dev/null +++ b/Modules/MUON/MCH/include/MCH/PhysicsCheck.h @@ -0,0 +1,53 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PhysicsCheck.h +/// \author Andrea Ferrero, Sebastien Perrin +/// + +#ifndef QC_MODULE_MCH_PHYSICSCHECK_H +#define QC_MODULE_MCH_PHYSICSCHECK_H + +#include "QualityControl/CheckInterface.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include + +namespace o2::quality_control_modules::muonchambers +{ + +/// \brief Check if the occupancy on each pad is between the two specified values +/// +/// \author Andrea Ferrero, Sebastien Perrin +class PhysicsCheck : public o2::quality_control::checker::CheckInterface +{ + public: + /// Default constructor + PhysicsCheck(); + /// Destructor + ~PhysicsCheck() override; + + // Override interface + void configure(std::string name) override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + private: + int mPrintLevel; + double minOccupancy; + double maxOccupancy; + ClassDefOverride(PhysicsCheck, 1); +}; + +} // namespace o2::quality_control_modules::muonchambers + +#endif // QC_MODULE_TOF_TOFCHECKRAWSTIME_H diff --git a/Modules/MUON/MCH/include/MCH/PhysicsTask.h b/Modules/MUON/MCH/include/MCH/PhysicsTask.h deleted file mode 100644 index 0e0ba212db..0000000000 --- a/Modules/MUON/MCH/include/MCH/PhysicsTask.h +++ /dev/null @@ -1,75 +0,0 @@ -/// -/// \file PhysicsTask.h -/// \author Barthelemy von Haller -/// \author Piotr Konopka -/// \author Andrea Ferrero -/// - -#ifndef QC_MODULE_MUONCHAMBERS_PHYSICSTASK_H -#define QC_MODULE_MUONCHAMBERS_PHYSICSTASK_H - -#include "QualityControl/TaskInterface.h" -#include "MCH/Mapping.h" -#include "MCH/Decoding.h" -#include "MCHBase/Digit.h" - -class TH1F; -class TH2F; - -using namespace o2::quality_control::core; - -namespace o2 -{ -namespace quality_control_modules -{ -namespace muonchambers -{ - -/// \brief Quality Control Task for the analysis of MCH physics data -/// \author Andrea Ferrero -/// \author Sebastien Perrin -class PhysicsTask /*final*/ : public TaskInterface // todo add back the "final" when doxygen is fixed -{ - public: - /// \brief Constructor - PhysicsTask(); - /// Destructor - ~PhysicsTask() override; - - // Definition of the methods for the template method pattern - void initialize(o2::framework::InitContext& ctx) override; - void startOfActivity(Activity& activity) override; - void startOfCycle() override; - void monitorData(o2::framework::ProcessingContext& ctx) override; - void endOfCycle() override; - void endOfActivity(Activity& activity) override; - void reset() override; - - ssize_t getNumberOfDigits(); - void storeDigits(void* bufferPtr); - - private: - int count; - Decoder mDecoder; - uint64_t nhits[24][40][64]; - - std::vector> digits; - mch::Digit* digitsBuffer; - int nDigits; - - TH2F* mHistogramNhits[72]; - TH1F* mHistogramADCamplitude[72]; - std::vector DEs; - std::map mHistogramADCamplitudeDE; - std::map mHistogramNhitsDE; - std::map mHistogramNhitsHighAmplDE; - - std::map mHistogramClchgDE; - std::map mHistogramClsizeDE; -}; - -} // namespace muonchambers -} // namespace quality_control_modules -} // namespace o2 - -#endif // QC_MODULE_MUONCHAMBERS_PHYSICSDATAPROCESSOR_H diff --git a/Modules/MUON/MCH/include/MCH/PhysicsTaskDigits.h b/Modules/MUON/MCH/include/MCH/PhysicsTaskDigits.h new file mode 100644 index 0000000000..fef6074ebd --- /dev/null +++ b/Modules/MUON/MCH/include/MCH/PhysicsTaskDigits.h @@ -0,0 +1,96 @@ +/// +/// \file PhysicsTaskDigits.h +/// \author Barthelemy von Haller +/// \author Piotr Konopka +/// \author Andrea Ferrero +/// + +#ifndef QC_MODULE_MUONCHAMBERS_PHYSICSTASKDIGITS_H +#define QC_MODULE_MUONCHAMBERS_PHYSICSTASKDIGITS_H + +#include "QualityControl/TaskInterface.h" +#include "MCHRawElecMap/Mapper.h" +#include "MCHBase/Digit.h" +#include "MCH/GlobalHistogram.h" + +class TH1F; +class TH2F; + +#define MCH_FEEID_NUM 64 + +using namespace o2::quality_control::core; + +namespace o2 +{ +namespace quality_control_modules +{ +namespace muonchambers +{ + +/// \brief Quality Control Task for the analysis of MCH physics data +/// \author Andrea Ferrero +/// \author Sebastien Perrin +class PhysicsTaskDigits /*final*/ : public TaskInterface // todo add back the "final" when doxygen is fixed +{ + public: + /// \brief Constructor + PhysicsTaskDigits(); + /// Destructor + ~PhysicsTaskDigits() override; + + // Definition of the methods for the template method pattern + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(Activity& activity) override; + void reset() override; + + private: + void plotDigit(const o2::mch::Digit& digit); + + o2::mch::raw::Elec2DetMapper mElec2DetMapper; + o2::mch::raw::Det2ElecMapper mDet2ElecMapper; + o2::mch::raw::FeeLink2SolarMapper mFeeLink2SolarMapper; + o2::mch::raw::Solar2FeeLinkMapper mSolar2FeeLinkMapper; + + uint32_t norbits[MCH_FEEID_NUM][12]; + uint32_t lastorbitseen[MCH_FEEID_NUM][12]; + // Mesn Occupancy on each DE + double MeanOccupancyDE[1100]; + // Mean Occupancy on each DE during the elapsed cycle, and arrays needed to compute it + double MeanOccupancyDECycle[1100]; + // Arrays needed for the computation of Occupancy on elapsed cycle + double LastMeanNhitsDE[1100]; + double LastMeanNorbitsDE[1100]; + double NewMeanNhitsDE[1100]; + double NewMeanNorbitsDE[1100]; + + int NbinsDE[1100]; + + // 2D Histograms, using Elec view (where x and y uniquely identify each pad based on its Elec info (fee, link, de) + TH2F* mHistogramNHitsElec; + TH2F* mHistogramNorbitsElec; + TH2F* mHistogramOccupancyElec; + + // TH1 of the Mean Occupancy on each DE, integrated or only on elapsed cycle - Sent for Trending + TH1F* mMeanOccupancyPerDE; + TH1F* mMeanOccupancyPerDECycle; + + TH2F* mHistogramNhits[1100]; + TH1F* mHistogramADCamplitude[1100]; + std::map mHistogramADCamplitudeDE; + std::map mHistogramNhitsDE[2]; + std::map mHistogramNorbitsDE[2]; + std::map mHistogramOccupancyXY[2]; + + GlobalHistogram* mHistogramOccupancy[1]; + GlobalHistogram* mHistogramOrbits[1]; +}; + +} // namespace muonchambers +} // namespace quality_control_modules +} // namespace o2 + +#endif // QC_MODULE_MUONCHAMBERS_PHYSICSDATAPROCESSOR_H diff --git a/Modules/MUON/MCH/include/MCH/PhysicsTaskPreclusters.h b/Modules/MUON/MCH/include/MCH/PhysicsTaskPreclusters.h new file mode 100644 index 0000000000..b9167fa66a --- /dev/null +++ b/Modules/MUON/MCH/include/MCH/PhysicsTaskPreclusters.h @@ -0,0 +1,78 @@ +/// +/// \file PhysicsTaskPreclusters.h +/// \author Barthelemy von Haller +/// \author Piotr Konopka +/// \author Andrea Ferrero +/// + +#ifndef QC_MODULE_MUONCHAMBERS_PHYSICSTASKPRECLUSTERS_H +#define QC_MODULE_MUONCHAMBERS_PHYSICSTASKPRECLUSTERS_H + +#include + +#include +#include "QualityControl/TaskInterface.h" +#include "MCH/GlobalHistogram.h" +#include "MCHBase/Digit.h" +#include "MCHBase/PreCluster.h" + +namespace o2 +{ +namespace quality_control_modules +{ +namespace muonchambers +{ + +/// \brief Quality Control Task for the analysis of MCH physics data +/// \author Andrea Ferrero +/// \author Sebastien Perrin +class PhysicsTaskPreclusters /*final*/ : public o2::quality_control::core::TaskInterface // todo add back the "final" when doxygen is fixed +{ + public: + /// \brief Constructor + PhysicsTaskPreclusters(); + /// Destructor + ~PhysicsTaskPreclusters() override; + + // Definition of the methods for the template method pattern + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(o2::quality_control::core::Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(o2::quality_control::core::Activity& activity) override; + void reset() override; + + bool plotPrecluster(const o2::mch::PreCluster& preCluster, gsl::span digits); + void printPreclusters(gsl::span preClusters, gsl::span digits); + + private: + double MeanPseudoeffDE[1100]; + double MeanPseudoeffDECycle[1100]; + // Arrays needed to compute the Pseudo-efficiency on the elapsed cycle + double LastPreclBNBDE[1100]; + double NewPreclBNBDE[1100]; + double LastPreclNumDE[1100]; + double NewPreclNumDE[1100]; + + std::vector> digits; + + // TH1 of Mean Pseudo-efficiency on DEs, integrated or only on the elapsed cycle - Sent for Trending + TH1F* mMeanPseudoeffPerDE; + TH1F* mMeanPseudoeffPerDECycle; + + std::map mHistogramClchgDE; + std::map mHistogramClchgDEOnCycle; + std::map mHistogramClsizeDE; + + std::map mHistogramPreclustersXY[4]; + std::map mHistogramPseudoeffXY[3]; + + GlobalHistogram* mHistogramPseudoeff[3]; +}; + +} // namespace muonchambers +} // namespace quality_control_modules +} // namespace o2 + +#endif // QC_MODULE_MUONCHAMBERS_PHYSICSDATAPROCESSOR_H diff --git a/Modules/MUON/MCH/include/MCH/TH1MCHReductor.h b/Modules/MUON/MCH/include/MCH/TH1MCHReductor.h new file mode 100644 index 0000000000..b690dff27f --- /dev/null +++ b/Modules/MUON/MCH/include/MCH/TH1MCHReductor.h @@ -0,0 +1,219 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TH1MCHReductor.h +/// \author Piotr Konopka, Sebastien Perrin +/// +#ifndef QUALITYCONTROL_TH1MCHREDUCTOR_H +#define QUALITYCONTROL_TH1MCHREDUCTOR_H + +#include "QualityControl/Reductor.h" + +namespace o2::quality_control_modules::muonchambers +{ + +/// \brief A Reductor which obtains the most popular characteristics of TH1. +/// +/// A Reductor which obtains the most popular characteristics of TH1. + +class TH1MCHReductor : public quality_control::postprocessing::Reductor +{ + public: + TH1MCHReductor() = default; + ~TH1MCHReductor() = default; + + void* getBranchAddress() override; + const char* getBranchLeafList() override; + void update(TObject* obj) override; + + private: + struct { + union { + struct { + Double_t val500; + Double_t val501; + Double_t val502; + Double_t val503; + Double_t val504; + Double_t val505; + Double_t val506; + Double_t val507; + Double_t val508; + Double_t val509; + Double_t val510; + Double_t val511; + Double_t val512; + Double_t val513; + Double_t val514; + Double_t val515; + Double_t val516; + Double_t val517; + Double_t val600; + Double_t val601; + Double_t val602; + Double_t val603; + Double_t val604; + Double_t val605; + Double_t val606; + Double_t val607; + Double_t val608; + Double_t val609; + Double_t val610; + Double_t val611; + Double_t val612; + Double_t val613; + Double_t val614; + Double_t val615; + Double_t val616; + Double_t val617; + Double_t val700; + Double_t val701; + Double_t val702; + Double_t val703; + Double_t val704; + Double_t val705; + Double_t val706; + Double_t val707; + Double_t val708; + Double_t val709; + Double_t val710; + Double_t val711; + Double_t val712; + Double_t val713; + Double_t val714; + Double_t val715; + Double_t val716; + Double_t val717; + Double_t val718; + Double_t val719; + Double_t val720; + Double_t val721; + Double_t val722; + Double_t val723; + Double_t val724; + Double_t val725; + Double_t val800; + Double_t val801; + Double_t val802; + Double_t val803; + Double_t val804; + Double_t val805; + Double_t val806; + Double_t val807; + Double_t val808; + Double_t val809; + Double_t val810; + Double_t val811; + Double_t val812; + Double_t val813; + Double_t val814; + Double_t val815; + Double_t val816; + Double_t val817; + Double_t val818; + Double_t val819; + Double_t val820; + Double_t val821; + Double_t val822; + Double_t val823; + Double_t val824; + Double_t val825; + Double_t val900; + Double_t val901; + Double_t val902; + Double_t val903; + Double_t val904; + Double_t val905; + Double_t val906; + Double_t val907; + Double_t val908; + Double_t val909; + Double_t val910; + Double_t val911; + Double_t val912; + Double_t val913; + Double_t val914; + Double_t val915; + Double_t val916; + Double_t val917; + Double_t val918; + Double_t val919; + Double_t val920; + Double_t val921; + Double_t val922; + Double_t val923; + Double_t val924; + Double_t val925; + Double_t val1000; + Double_t val1001; + Double_t val1002; + Double_t val1003; + Double_t val1004; + Double_t val1005; + Double_t val1006; + Double_t val1007; + Double_t val1008; + Double_t val1009; + Double_t val1010; + Double_t val1011; + Double_t val1012; + Double_t val1013; + Double_t val1014; + Double_t val1015; + Double_t val1016; + Double_t val1017; + Double_t val1018; + Double_t val1019; + Double_t val1020; + Double_t val1021; + Double_t val1022; + Double_t val1023; + Double_t val1024; + Double_t val1025; + } named; + Double_t values[140]; + } de_values; + union { + struct { + Double_t val5I; + Double_t val5O; + Double_t val6I; + Double_t val6O; + Double_t val7I; + Double_t val7O; + Double_t val8I; + Double_t val8O; + Double_t val9I; + Double_t val9O; + Double_t val10I; + Double_t val10O; + } named; + Double_t values[12]; + } halfch_values; + Double_t entries; + } mStats; + std::array detCH5I = { 500, 501, 502, 503, 504, 514, 515, 516, 517 }; + std::array detCH5O = { 505, 506, 507, 508, 509, 510, 511, 512, 513 }; + std::array detCH6I = { 600, 601, 602, 603, 604, 614, 615, 616, 617 }; + std::array detCH6O = { 605, 606, 607, 608, 609, 610, 611, 612, 613 }; + std::array detCH7I = { 700, 701, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725 }; + std::array detCH7O = { 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719 }; + std::array detCH8I = { 800, 801, 802, 803, 804, 805, 806, 820, 821, 822, 823, 824, 825 }; + std::array detCH8O = { 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819 }; + std::array detCH9I = { 900, 901, 902, 903, 904, 905, 906, 920, 921, 922, 923, 924, 925 }; + std::array detCH9O = { 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919 }; + std::array detCH10I = { 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1020, 1021, 1022, 1023, 1024, 1025 }; + std::array detCH10O = { 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019 }; +}; + +} // namespace o2::quality_control_modules::muonchambers + +#endif //QUALITYCONTROL_TH1mchREDUCTOR_H diff --git a/Modules/MUON/MCH/src/Decoding.cxx b/Modules/MUON/MCH/src/Decoding.cxx index 6577777f78..9abf965d34 100644 --- a/Modules/MUON/MCH/src/Decoding.cxx +++ b/Modules/MUON/MCH/src/Decoding.cxx @@ -8,6 +8,7 @@ #include #include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" #include "QualityControl/QcInfoLogger.h" #include "MCH/Decoding.h" #include "MCHBase/Digit.h" @@ -17,13 +18,10 @@ using namespace std; -static int gPrintLevel; static int gPattern; static int gNbErrors; static int gNbWarnings; -static FILE* flog = NULL; - struct CRUheader { uint8_t header_version; uint8_t header_size; @@ -61,8 +59,11 @@ namespace quality_control_modules namespace muonchambers { +using RDH = o2::header::RDHAny; + bool BXCNT_compare(long int c1, long int c2) { + return true; const int64_t MAX = 0xFFFFF; //int64_t diff = c1 - c2; //if(diff >= MAX) diff -= MAX; @@ -80,8 +81,6 @@ bool BXCNT_compare(long int c1, long int c2) void DualSampaInit(DualSampa* ds) { - if (gPrintLevel >= 4) - fprintf(flog, "DualSampaInit() called\n"); ds->status = notSynchronized; ds->data = 0; ds->bit = 0; @@ -96,14 +95,13 @@ void DualSampaInit(DualSampa* ds) ds->nclus[j][k] = 0; ds->pedestal[j][k] = 0; ds->noise[j][k] = 0; + ds->delta[j][k] = 0; } } } void DualSampaReset(DualSampa* ds) { - if (gPrintLevel >= 4) - fprintf(flog, "DualSampaReset() called\n"); ds->status = notSynchronized; ds->data = 0; ds->bit = 0; @@ -385,8 +383,6 @@ void DecodeGBTWord(uint32_t* bufpt, uint32_t* data) decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* dsg) { decode_state_t result = DECODE_STATE_UNKNOWN; - if (gPrintLevel >= 2) - fprintf(flog, "ds->status=%d\n", dsr.status); if (!(dsr.status == notSynchronized)) { // data is synchronized => build the data word dsr.data += (gbtdata & 0x1) * dsr.powerMultiplier; dsr.powerMultiplier *= 2; @@ -399,12 +395,8 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d case notSynchronized: { // Looking for Sync word (2 packets) // Look for 10 consecutives 01 (sent 10 from the GBT) - if (gPrintLevel >= 2) - fprintf(flog, " ds[%d]->bit=%d\n ->powerMultiplier=%" PRIu64 "\n (gbtdata&0x1)=%d\n", - ds->id, ds->bit, ds->powerMultiplier, (int)(gbtdata & 0x1)); if (ds->bit < 50) { // Fill the word ds->data += (gbtdata & 0x1) * ds->powerMultiplier; - //if( gPrintLevel >= 2 ) fprintf(flog,"Add1BitOfData()\n ds[%d]->data=%lX\n", ds->id, ds->data); ds->powerMultiplier *= 2; ds->bit++; } else { @@ -413,15 +405,10 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d ds->data /= 2; // Take out the bit 0 ds->data &= 0x1FFFFFFFFFFFF; ds->data += (gbtdata & 0x1) * ds->powerMultiplier; // Fill bit 49 - //if( gPrintLevel >= 2 ) fprintf(flog,"Add1BitOfData()\n ds[%d]->data=%lX\n", ds->data); ds->bit++; } - if (gPrintLevel >= 2) - fprintf(flog, " ==> ds[%d]->data: %.16" PRIu64 "\n", ds->id, ds->data); if (ds->data == 0x1555540f00113 && ds->bit >= 50) { - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA #%d: Synchronizing... (Sync word found)\n", ds->id); // Next word of 50 bits should be a Sync Word ds->bit = 0; ds->data = 0; ds->powerMultiplier = 1; @@ -435,60 +422,30 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d case headerToRead: { // We are waiting for a Sampa header // It can be preceded by an undefined number os Sync words - if (gPrintLevel >= 2) - fprintf(flog, " ds[%d]->bit=%d\n ->powerMultiplier=%" PRIu64 "\n (gbtdata&0x1)=%d\n", - dsr.id, dsr.bit, dsr.powerMultiplier, (int)(gbtdata & 0x1)); - if (gPrintLevel >= 2) - fprintf(flog, " ==> ds[%d]->data: %.16" PRIu64 "\n", dsr.id, dsr.data); if (dsr.bit < 50) break; if (dsr.data == 0x1555540f00113) { - if (gPrintLevel >= 2) - fprintf(flog, "SAMPA #%d: Sync word found\n", dsr.id); // Next word of 50 bits should be a Sync Word result = DECODE_STATE_SYNC_FOUND; } else { result = DECODE_STATE_HEADER_FOUND; memcpy(&(ds->header), &(ds->data), sizeof(Sampa::SampaHeaderStruct)); - //if( gPrintLevel >= 1 ) fprintf(flog,"SAMPA #%d: ds->nbHit=%d\n", ds->id, ds->nbHit); if (ds->nbHit >= 0) // if chip was synchronized ds->nbHit++; else ds->nbHit = 1; if ((ds->header.fChannelAddress >= 0) && (ds->header.fChannelAddress < 32)) { - //fprintf(flog,"%.2d %.2d\n",ds->header.fChipAddress,(ds->header.fChipAddress%2)); ds->nbHitChan[ds->header.fChannelAddress + 32 * (ds->header.fChipAddress % 2)]++; } - if (gPrintLevel >= 1 || (false && ds->id == 0 && ds->header.fChipAddress == 0 && ds->header.fChannelAddress >= 30)) - fprintf(flog, "SAMPA [%2d]: Header 0x%014" PRIu64 " HCode %2lu HPar %lu PkgType %lu 10BitWords %lu ChipAdd %lu ChAdd %2lu BX %lu PPar %d\n", - ds->id, ds->data, (unsigned long)ds->header.fHammingCode, (unsigned long)ds->header.fHeaderParity, (unsigned long)ds->header.fPkgType, - (unsigned long)ds->header.fNbOf10BitWords, (unsigned long)ds->header.fChipAddress, (unsigned long)ds->header.fChannelAddress, - (unsigned long)ds->header.fBunchCrossingCounter, (int)ds->header.fPayloadParity); - int parity = CheckDataParity(ds->data); - if (parity) - fprintf(flog, "===> SAMPA [%2d]: WARNING Parity %d\n", ds->id, parity); - - //fprintf(flog,"SAMPA [%2d]: ChipAdd %d ChAdd %2d BX %d, expected %d\n", - // ds->id, ds->header.fChipAddress,ds->header.fChannelAddress, - // ds->header.fBunchCrossingCounter, ds->bxc); - int link = ds->id / 5; - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA [%2d]: BX counter for link %d is %ld\n", ds->id, link, dsg->bxc); + if (dsg && dsg->bxc >= 0) { if (!BXCNT_compare(dsg->bxc, static_cast(ds->header.fBunchCrossingCounter))) { gNbErrors++; - fprintf(flog, "===> ERROR SAMPA [%2d]: ChipAdd %lu ChAdd %2lu BX %lu, expected %ld, diff %ld\n", - ds->id, (unsigned long)ds->header.fChipAddress, (unsigned long)ds->header.fChannelAddress, - (unsigned long)ds->header.fBunchCrossingCounter, dsg->bxc, - (unsigned long)ds->header.fBunchCrossingCounter - dsg->bxc); } } else { if (dsg && ds->header.fPkgType == 4) { // physics trigger dsg->bxc = ds->header.fBunchCrossingCounter; - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA [%2d]: BX counter for link %d set to %ld\n", ds->id, link, dsg->bxc); } } - //if( gPrintLevel >= 1 ) fprintf(flog,"SAMPA [%2d]: BX counter for link %d is %d (2)\n", ds->id, link, dsg->bxc); ds->packetsize = 0; @@ -501,7 +458,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d HammingDecode(buf, hamming_error, hamming_uncorr, hamming_enable); if (hamming_error) { gNbErrors++; - fprintf(flog, "SAMPA [%2d]: Hamming ERROR -> Correctable: %s\n", ds->id, hamming_uncorr ? "NO" : "YES"); ds->status = notSynchronized; result = DECODE_STATE_UNKNOWN; } else { // No Hamming error @@ -511,7 +467,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d } else { if (ds->header.fPkgType == 1 || ds->header.fPkgType == 3) { // Data truncated gNbErrors++; - fprintf(flog, "ERROR: Truncated data found -> skip the data\n"); if (ds->header.fNbOf10BitWords) ds->status = dataToRead; else @@ -519,25 +474,19 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d } if (ds->header.fPkgType == 0) { // Heartbeat: Pkg 0, NbOfWords 0 ?, ChAdd 21 gNbErrors++; - fprintf(flog, "ERROR: Hearbeat word found\n"); ds->status = headerToRead; ds->bxc[ds->header.fChipAddress % 2] = ds->header.fBunchCrossingCounter; } if (ds->header.fPkgType == 5) { // gNbErrors++; - fprintf(flog, "ERROR: Data word (?) type 5 found\n"); ds->status = headerToRead; } if (ds->header.fPkgType == 6) { // - if (gPrintLevel >= 1) - fprintf(flog, "INFO: Trigger too early word found\n"); //ds->status = headerToRead; ds->status = sizeToRead; } if (ds->header.fPkgType == 2) { // gNbErrors++; - fprintf(flog, "ERROR: Supposed to be a SYNC!!!\n"); - fprintf(flog, "Trying to re-synchronise...\n"); ds->status = notSynchronized; result = DECODE_STATE_UNKNOWN; } @@ -561,33 +510,16 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d int chip0 = (ds->id % 5) * 2; int chip1 = chip0 + 1; - if (gPrintLevel >= 5) - fprintf(flog, "SAMPA: chip addresses: %lu\n", (unsigned long)ds->header.fChipAddress); - if (gPrintLevel >= 5) - fprintf(flog, "SAMPA: channel addresses: %d, %d\n", - ds->chan_addr[0], ds->chan_addr[1]); if (ds->header.fChipAddress < chip0 || ds->header.fChipAddress > chip1) { gNbWarnings++; - if (gPrintLevel >= 1) - fprintf(flog, "===> WARNING SAMPA [%2d]: chip address = %lu, expected = [%d,%d]\n", ds->id, - (unsigned long)ds->header.fChipAddress, chip0, chip1); } if (ds->chan_addr[ds->header.fChipAddress - chip0] != ds->header.fChannelAddress) { gNbWarnings++; - if (gPrintLevel >= 1) - fprintf(flog, "===> WARNING SAMPA [%2d]: channel address = %lu, expected = %d\n", ds->id, - (unsigned long)ds->header.fChannelAddress, ds->chan_addr[ds->header.fChipAddress - chip0]); } ds->chan_addr[ds->header.fChipAddress - chip0] += 1; if (ds->chan_addr[ds->header.fChipAddress - chip0] > 31) { ds->chan_addr[ds->header.fChipAddress - chip0] = 0; } - if (gPrintLevel >= 5) - fprintf(flog, "SAMPA: next channel addresses: %d, %d\n", - ds->chan_addr[0], ds->chan_addr[1]); - - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA [%2d]: Cluster Size 0x%" PRIu64 " (%" PRIu64 ")\n", ds->id, ds->data, ds->data); ds->csize = ds->data; ds->cid = 0; @@ -606,8 +538,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d if (ds->bit < 10) break; result = DECODE_STATE_CTIME_FOUND; - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA [%2d]: Cluster Time 0x%" PRIu64 " (%" PRIu64 ")\n", ds->id, ds->data, ds->data); ds->ctime = ds->data; ds->packetsize += 1; @@ -625,8 +555,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d case dataToRead: { // Read ADC data words (10 bits) if (ds->bit < 10) break; - if (gPrintLevel >= 2) - fprintf(flog, "SAMPA #%d Data word: 0x%" PRIu64 " (%" PRIu64 ")\n", ds->id, ds->data, ds->data); if (1 /*ds->header.fPkgType == 4*/) { if (ds->header.fPkgType == 4) { // Good data @@ -637,8 +565,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d int patt = (gPattern & 0xFF) + (gPattern << 8 & 0xFF00); if ((ds->data & 0x2FF) != (patt & 0x2FF)) { gNbWarnings++; - fprintf(flog, "===> WARNING SAMPA [%2d]: wrong data pattern 0x%" PRIu64 ", expected 0x%X\n", ds->id, - ds->data & 0x2FF, (patt & 0x2FF)); } } } @@ -649,23 +575,11 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d if (end_of_packet && !end_of_cluster) { // That's the end of the packet, but the cluster is still being read... that's not normal gNbErrors++; - //fprintf(flog,"===> ERROR SAMPA [%2d]: End-of-packet without End-of-cluster. packet size = %lu, cluster size = %d\n", - // ds->id, ds->header.fNbOf10BitWords, ds->csize); ds->status = headerToRead; } else if (end_of_cluster) { - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA #%d : End of cluster found\n", ds->id); if (ds->header.fPkgType == 4) { // Good data ds->nclus[ds->header.fChipAddress % 2][ds->header.fChannelAddress] += 1; result = DECODE_STATE_END_OF_CLUSTER; - if (ds->id == 0 && ds->header.fChipAddress == 0 && ds->header.fChannelAddress >= 30) { - if (false) { - if (ds->header.fChannelAddress == 31) - fprintf(flog, " "); - fprintf(flog, "%d %lu %lu: End of cluster found (%d)\n", ds->id, (unsigned long)ds->header.fChipAddress, (unsigned long)ds->header.fChannelAddress, - ds->nclus[ds->header.fChipAddress % 2][ds->header.fChannelAddress]); - } - } } if (ds->header.fNbOf10BitWords > ds->packetsize) ds->status = sizeToRead; @@ -677,7 +591,6 @@ decode_state_t Add1BitOfData(uint32_t gbtdata, DualSampa& dsr, DualSampaGroup* d } else { if (ds->header.fPkgType == 1 || ds->header.fPkgType == 3) { // Data truncated gNbWarnings++; - fprintf(flog, "WARNING: SAMPA PkgType = 1 or 3 (data truncated) found\n"); if (ds->header.fNbOf10BitWords - 1) ds->header.fNbOf10BitWords--; else @@ -707,15 +620,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* case notSynchronized: dsr.data += data << dsr.bit; - if (gPrintLevel >= 1) - fprintf(flog, "notSynchronized[%d]: bit=%02d data=%013" PRIu64 " %03X %03X %03X %03X %03X\n", - dsr.id, dsr.bit, dsr.data, - (int)((dsr.data >> 40) & 0x3FF), - (int)((dsr.data >> 30) & 0x3FF), - (int)((dsr.data >> 20) & 0x3FF), - (int)((dsr.data >> 10) & 0x3FF), - (int)(dsr.data & 0x3FF)); - dsr.bit += 10; if (dsr.bit == 50) { @@ -725,8 +629,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* dsr.bit = 0; dsr.data = 0; dsr.packetsize = 0; - if (gPrintLevel >= 1) - fprintf(flog, "notSynchronized[%d]: SYNC word found\n", dsr.id); } else { dsr.data = dsr.data >> 10; dsr.bit -= 10; @@ -737,15 +639,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* case headerToRead: dsr.data += data << dsr.bit; - if (gPrintLevel >= 1) - fprintf(flog, "headerToRead[%d]: bit=%02d data=%013" PRIu64 " %03X %03X %03X %03X %03X\n", - dsr.id, dsr.bit, dsr.data, - (int)((dsr.data >> 40) & 0x3FF), - (int)((dsr.data >> 30) & 0x3FF), - (int)((dsr.data >> 20) & 0x3FF), - (int)((dsr.data >> 10) & 0x3FF), - (int)(dsr.data & 0x3FF)); - dsr.bit += 10; if (dsr.bit == 50) { @@ -755,8 +648,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* dsr.bit = 0; dsr.data = 0; dsr.packetsize = 0; - if (gPrintLevel >= 1) - fprintf(flog, "headerToRead[%d]: SYNC word found\n", dsr.id); } else { result = DECODE_STATE_HEADER_FOUND; memcpy(&(dsr.header), &(dsr.data), sizeof(Sampa::SampaHeaderStruct)); @@ -764,12 +655,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* dsr.bit = 0; dsr.data = 0; dsr.packetsize = 0; - Sampa::SampaHeaderStruct* header = (Sampa::SampaHeaderStruct*)&(dsr.header); - if (gPrintLevel >= 1) - fprintf(flog, "SAMPA Header: HCode %2lu HPar %lu PkgType %lu 10BitWords %lu ChipAdd %lu ChAdd %2lu BX %lu PPar %lu\n", - (unsigned long)header->fHammingCode, (unsigned long)header->fHeaderParity, (unsigned long)header->fPkgType, - (unsigned long)header->fNbOf10BitWords, (unsigned long)header->fChipAddress, (unsigned long)header->fChannelAddress, - (unsigned long)header->fBunchCrossingCounter, (unsigned long)header->fPayloadParity); } } break; @@ -778,17 +663,13 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* dsr.csize = data; dsr.cid = 0; dsr.packetsize += 1; - if (gPrintLevel >= 1) - fprintf(flog, "sizeToRead[%d]: SAMPA cluster size: %d\n", dsr.id, dsr.csize); if ((dsr.csize + 2) > dsr.header.fNbOf10BitWords) { - //fprintf(flog,"ERROR: cluster size bigger than SAMPA payload\n"); dsr.status = notSynchronized; dsr.bit = 0; dsr.data = 0; dsr.packetsize = 0; } else { if (dsr.packetsize == dsr.header.fNbOf10BitWords) { - ///fprintf(flog,"sizeToRead[%d]: ERROR: end-of-packet found while reading cluster size\n", dsr.id); dsr.status = notSynchronized; dsr.bit = 0; dsr.data = 0; @@ -804,7 +685,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* dsr.ctime = data; dsr.packetsize += 1; if (dsr.packetsize == dsr.header.fNbOf10BitWords) { - //fprintf(flog,"timeToRead[%d]: ERROR: end-of-packet found while reading cluster time\n", dsr.id); dsr.status = notSynchronized; dsr.bit = 0; dsr.data = 0; @@ -812,8 +692,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* } else { dsr.status = dataToRead; result = DECODE_STATE_CTIME_FOUND; - if (gPrintLevel >= 1) - fprintf(flog, "timeToRead[%d]: SAMPA cluster time: %d\n", dsr.id, dsr.ctime); } break; @@ -826,7 +704,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* //printf("dataToRead: cid=%d packetsize=%d end_of_packet=%d end_of_cluster=%d\n", // dsr.cid, dsr.packetsize, (int)end_of_packet, (int)end_of_cluster); if (end_of_packet && !end_of_cluster) { - //fprintf(flog,"dataToRead[%d]: ERROR: end-of-packet found while reading cluster data\n", dsr.id); dsr.bit = 0; dsr.data = 0; dsr.packetsize = 0; @@ -834,8 +711,6 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* } else { result = DECODE_STATE_SAMPLE_FOUND; dsr.status = dataToRead; - if (gPrintLevel >= 1) - fprintf(flog, "dataToRead[%d]: SAMPA sample: %d\n", dsr.id, dsr.sample); if (end_of_cluster) { result = DECODE_STATE_END_OF_CLUSTER; if (end_of_packet) { @@ -857,7 +732,7 @@ decode_state_t Add10BitsOfData(uint64_t data, DualSampa& dsr, DualSampaGroup* /* Decoder::Decoder() {} -Decoder::~Decoder() { fclose(flog); } +Decoder::~Decoder() {} void Decoder::initialize() { @@ -884,14 +759,26 @@ void Decoder::initialize() } } + mMapCRU.readMapping("cru.map"); + mMapFEC.readDSMapping("fec.map"); + fprintf(stdout, "initialize ds_enable\n"); for (int c = 0; c < MCH_MAX_CRU_IN_FLP; c++) { for (int l = 0; l < 24; l++) { - for (int i = 0; i < 40; i++) { - ds_enable[c][l][i] = 1; + int32_t link_id = mMapCRU.getLink(c, l); + if (link_id < 0) { + for (int i = 0; i < 40; i++) { + ds_enable[c][l][i] = 0; + } + } else { + for (int i = 0; i < 40; i++) { + uint32_t de, dsid; + ds_enable[c][l][i] = mMapFEC.getDSMapping(link_id, i, de, dsid) ? 1 : 0; + } } } } + /* std::ifstream ds_enable_f("/tmp/board_enable.txt"); fprintf(stdout, "Reading /tmp/board_enable.txt"); while (!ds_enable_f.fail()) { @@ -906,20 +793,15 @@ void Decoder::initialize() ds_enable[c][l][b] = e; fprintf(stdout, "ds_enable[%d][%d][%d]=%d\n", c, l, b, ds_enable[c][l][b]); } + */ - mMapCRU.readMapping("cru.map"); - mMapFEC.readDSMapping("fec.map"); - - gPrintLevel = 0; - - //if( gPrintLevel > 0 ) flog = fopen("/home/flp/qc.log", "w"); //else - flog = stdout; fprintf(stdout, "Decoder initialization finished\n"); } void Decoder::decodeRaw(uint32_t* payload_buf, size_t nGBTwords, int cru_id, int link_id) { + //fprintf(stdout,"[decodeRaw] payload_buf=%p\n", (void*)payload_buf); uint32_t hhvalue, hlvalue, lhvalue, llvalue; for (size_t wi = 0; wi < nGBTwords; wi++) { uint32_t* ptr = payload_buf + wi * 4; @@ -941,25 +823,23 @@ void Decoder::decodeRaw(uint32_t* payload_buf, size_t nGBTwords, int cru_id, int uint32_t group = ds[cru_id][link_id][i].id / 5; uint32_t bits[2] = { data2bits[i] & 0x1, (data2bits[i] >> 1) & 0x1 }; + + SampaHit& hit = ds[cru_id][link_id][i].hit; + hit.cru_id = cru_id; + hit.data_path = link_id / 12; + hit.fee_id = cru_id * 2 + hit.data_path; + hit.link_id = link_id; + hit.ds_addr = ds[cru_id][link_id][i].id; for (int k = 0; k < 2; k++) { decode_state_t state = Add1BitOfData(bits[k], (ds[cru_id][link_id][i]), &(dsg[cru_id][link_id][group])); switch (state) { case DECODE_STATE_SYNC_FOUND: - if (gPrintLevel >= 1) - fprintf(flog, "SYNC found\n"); break; case DECODE_STATE_HEADER_FOUND: uint64_t _h; memcpy(&_h, &(ds[cru_id][link_id][i].header), sizeof(ds[cru_id][link_id][i].header)); - if (gPrintLevel >= 1) - fprintf(flog, "board %d %d %d -> HEADER: %05" PRIu64 ", %lu, %lu\n", - cru_id, link_id, i, _h, - (unsigned long)ds[cru_id][link_id][i].header.fChipAddress, - (unsigned long)ds[cru_id][link_id][i].header.fChannelAddress); break; case DECODE_STATE_CSIZE_FOUND: { - if (gPrintLevel >= 2) - fprintf(flog, "CLUSTER SIZE: %" PRIu32 "\n", ds[cru_id][link_id][i].csize); Sampa::SampaHeaderStruct& header = ds[cru_id][link_id][i].header; SampaHit& hit = ds[cru_id][link_id][i].hit; hit.cru_id = cru_id; @@ -974,22 +854,34 @@ void Decoder::decodeRaw(uint32_t* payload_buf, size_t nGBTwords, int cru_id, int hit.samples.clear(); hit.csum = 0; hit.time = 0; + for (int ci = 0; ci < 2; ci++) { + for (int cj = 0; cj < 32; cj++) { + ds[cru_id][link_id][i].min[ci][cj] = 0xFFFFFFFF; + ds[cru_id][link_id][i].max[ci][cj] = 0; + } + } break; } case DECODE_STATE_CTIME_FOUND: - if (gPrintLevel >= 2) - fprintf(flog, "CLUSTER TIME: %d\n", ds[cru_id][link_id][i].ctime); ds[cru_id][link_id][i].hit.time = ds[cru_id][link_id][i].ctime; break; case DECODE_STATE_SAMPLE_FOUND: case DECODE_STATE_END_OF_CLUSTER: { SampaHit& hit = ds[cru_id][link_id][i].hit; - if (gPrintLevel >= 2) - fprintf(flog, "SAMPLE: %X\n", ds[cru_id][link_id][i].sample); hit.samples.push_back(ds[cru_id][link_id][i].sample); hit.csum += ds[cru_id][link_id][i].sample; + int chipid = hit.ds_addr % 2; + int chid = hit.chan_addr; + if (ds[cru_id][link_id][i].min[chipid][chid] > ds[cru_id][link_id][i].sample) + ds[cru_id][link_id][i].min[chipid][chid] = ds[cru_id][link_id][i].sample; + if (ds[cru_id][link_id][i].max[chipid][chid] < ds[cru_id][link_id][i].sample) + ds[cru_id][link_id][i].max[chipid][chid] = ds[cru_id][link_id][i].sample; + if (state == DECODE_STATE_END_OF_CLUSTER) { + int32_t deltaNew = ds[cru_id][link_id][i].max[chipid][chid] - ds[cru_id][link_id][i].min[chipid][chid]; + //if( hit.deltaMax < deltaNew ) + hit.delta = deltaNew; mHits.push_back(hit); if (hit.link_id >= 24) { fprintf(stdout, "hit: link_id=%d, ds_addr=%d, chan_addr=%d\n", @@ -1022,8 +914,6 @@ void Decoder::decodeUL(uint32_t* payload_buf_32, size_t nWords, int cru_id, int int link_id = (value >> 59) & 0x1F; int ds_id = (value >> 53) & 0x3F; link_id += 12 * dpw_id; - if (gPrintLevel >= 1) - fprintf(flog, "64 bits: %016" PRIu64 "\n", value); if (value == 0xFFFFFFFFFFFFFFFF) continue; @@ -1031,24 +921,7 @@ void Decoder::decodeUL(uint32_t* payload_buf_32, size_t nWords, int cru_id, int continue; int is_incomplete = (value >> 52) & 0x1; - int err_code = (value >> 50) & 0x3; - if (gPrintLevel >= 1) { - fprintf(flog, "cru: %d dpw: %d link: %d ds: %d incomplete: %d err: %d\n", - cru_id, dpw_id, link_id, ds_id, is_incomplete, err_code); - fprintf(flog, "14 bits: %016" PRIu64 "\n", (value >> 50) & 0xFFF); - fprintf(flog, "50 bits: %016" PRIu64 "\n", value & 0x3FFFFFFFFFFFF); - - fprintf(flog, "10 bits:\n"); - fprintf(flog, " %" PRIu64 "\n", value & 0x3FF); - fprintf(flog, " %" PRIu64 "\n", (value >> 10) & 0x3FF); - fprintf(flog, " %" PRIu64 "\n", (value >> 20) & 0x3FF); - fprintf(flog, " %" PRIu64 "\n", (value >> 30) & 0x3FF); - fprintf(flog, " %" PRIu64 "\n", (value >> 40) & 0x3FF); - fprintf(flog, "DS status: %d\n", ds[cru_id][link_id][ds_id].status); - } if (link_id < 0 || link_id >= 24 || ds_id < 0 || ds_id >= 40) { - fprintf(flog, "ERROR: wrong DS board address cru: %d dpw: %d link: %d ds: %d\n", - cru_id, dpw_id, link_id, ds_id); continue; } @@ -1062,12 +935,8 @@ void Decoder::decodeUL(uint32_t* payload_buf_32, size_t nWords, int cru_id, int case DECODE_STATE_HEADER_FOUND: uint64_t _h; memcpy(&_h, &(ds[cru_id][link_id][ds_id].header), sizeof(ds[cru_id][link_id][ds_id].header)); - if (gPrintLevel >= 1) - fprintf(flog, "HEADER: %05" PRIu64 "\n", _h); break; case DECODE_STATE_CSIZE_FOUND: { - if (gPrintLevel >= 1) - fprintf(flog, "CLUSTER SIZE: %d\n", ds[cru_id][link_id][ds_id].csize); Sampa::SampaHeaderStruct& header = ds[cru_id][link_id][ds_id].header; SampaHit& hit = ds[cru_id][link_id][ds_id].hit; hit.cru_id = cru_id; @@ -1083,16 +952,12 @@ void Decoder::decodeUL(uint32_t* payload_buf_32, size_t nWords, int cru_id, int break; } case DECODE_STATE_CTIME_FOUND: - if (gPrintLevel >= 1) - fprintf(flog, "CLUSTER TIME: %d\n", ds[cru_id][link_id][ds_id].ctime); ds[cru_id][link_id][ds_id].hit.time = ds[cru_id][link_id][ds_id].ctime; break; case DECODE_STATE_SAMPLE_FOUND: case DECODE_STATE_END_OF_CLUSTER: case DECODE_STATE_END_OF_PACKET: { SampaHit& hit = ds[cru_id][link_id][ds_id].hit; - if (gPrintLevel >= 1) - fprintf(flog, "SAMPLE: %X\n", ds[cru_id][link_id][ds_id].sample); hit.samples.push_back(ds[cru_id][link_id][ds_id].sample); hit.csum += ds[cru_id][link_id][ds_id].sample; @@ -1144,84 +1009,57 @@ void Decoder::processData(const char* buf, size_t size) } } - const char* rdh = buf; + const RDH* rdh = (const RDH*)buf; uint32_t payload_offset = 0; - uint32_t CRUbuf[4 * 4]; - CRUheader CRUh; - if (size < sizeof(CRUbuf)) + if (size < sizeof(RDH)) return; while (payload_offset < size) { - if (gPrintLevel >= 1) - fprintf(flog, "CRU payload_offset: %d, size: %d\n", (int)payload_offset, (int)size); - - memcpy(CRUbuf, rdh, sizeof(CRUbuf)); - memcpy(&CRUh, CRUbuf, sizeof(CRUheader)); - - uint32_t* payload_buf = (uint32_t*)(rdh + 16 * 4); + uint32_t* payload_buf = (uint32_t*)(buf + 16 * 4); + //fprintf(stdout,"[processData] payload_buf=%p\n", (void*)payload_buf); - if (gPrintLevel >= 1) - fprintf(flog, "%d: header_version: %X, header_size: %d, memory_size: %d, next_packet_offset: %d, block_length: %d, packet: %d, cru_id: %d, link_id: %d, orbit: %d\n", - nFrames, (int)CRUh.header_version, (int)CRUh.header_size, (int)CRUh.memory_size, (int)CRUh.next_packet_offset, (int)CRUh.block_length, - (int)CRUh.packet_counter, (int)CRUh.cru_id, (int)CRUh.link_id, (int)CRUh.hb_orbit); + auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh); + auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh); + auto frameSize = o2::raw::RDHUtils::getOffsetToNext(rdh); + auto memorySize = o2::raw::RDHUtils::getMemorySize(rdh); + auto payloadSize = memorySize - rdhHeaderSize; + int cruId = o2::raw::RDHUtils::getCRUID(rdh); + auto rdhLinkId = o2::raw::RDHUtils::getLinkID(rdh); + int dpwId = o2::raw::RDHUtils::getEndPointID(rdh); + auto rdhOrbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdh); // Check RDH version and size - if (((int)CRUh.header_version) != 4) { - QcInfoLogger::GetInstance() << "[Decoder::processData] Wrong CRU header version: " << (int)CRUh.header_version << AliceO2::InfoLogger::InfoLogger::endm; + if (rdhVersion < 4 || rdhVersion > 6) { + QcInfoLogger::GetInstance() << "[Decoder::processData] Wrong CRU header version: " << (int)rdhVersion << AliceO2::InfoLogger::InfoLogger::endm; return; } - if (((int)CRUh.header_size) != 64) { - QcInfoLogger::GetInstance() << "[Decoder::processData] Wrong CRU header size: " << (int)CRUh.header_size << AliceO2::InfoLogger::InfoLogger::endm; + if (rdhHeaderSize != 64) { + QcInfoLogger::GetInstance() << "[Decoder::processData] Wrong CRU header size: " << (int)rdhHeaderSize << AliceO2::InfoLogger::InfoLogger::endm; return; } + // Compute size of payload inside 8kB block - CRUh.block_length = CRUh.memory_size - CRUh.header_size; - RDH_BLOCK_SIZE = CRUh.next_packet_offset; // - CRUh.header_size; + RDH_BLOCK_SIZE = frameSize; rdh += RDH_BLOCK_SIZE; payload_offset += RDH_BLOCK_SIZE; - int cruId = CRUh.cru_id; - int dpwId = CRUh.dpw_id; - - //fprintf(flog, "CRU header: %08X %08X %08X %08X \n", CRUbuf[0], CRUbuf[1], CRUbuf[2], CRUbuf[3]); - //fprintf(flog, "CRU header: %08X %08X %08X %08X \n", CRUbuf[4], CRUbuf[5], CRUbuf[6], CRUbuf[7]); - //fprintf(flog, "CRU header: %08X %08X %08X %08X \n", CRUbuf[8], CRUbuf[9], CRUbuf[10], CRUbuf[11]); - //fprintf(flog, "CRU header: %08X %08X %08X %08X \n", CRUbuf[12], CRUbuf[13], CRUbuf[14], CRUbuf[15]); - //fprintf(flog, "CRU header version: %d\n", (int)CRUh.header_version); - //fprintf(flog, "CRU header size: %d\n", (int)CRUh.header_size); - //fprintf(flog, "CRU header block length: %d\n", (int)CRUh.block_length); - if (gPrintLevel >= 3) - fprintf(flog, "CRU packet counter: %d\n", (int)CRUh.packet_counter); - if (gPrintLevel >= 3) - fprintf(flog, "CRU orbit id: %d\n", (int)CRUh.hb_orbit); - if (gPrintLevel >= 1) - fprintf(flog, "CRU link ID: %d\n", (int)CRUh.link_id); - if (gPrintLevel >= 1) - fprintf(flog, "CRU ID: %d\n", (int)cruId); - if (gPrintLevel >= 1) - fprintf(flog, "DPW ID: %d\n", (int)dpwId); - nFrames += 1; - int rdh_lid = CRUh.link_id; - int cru_lid = (rdh_lid == 15) ? rdh_lid : rdh_lid + 12 * dpwId; - bool is_raw = (rdh_lid != 15); + int cru_lid = (rdhLinkId == 15) ? rdhLinkId : rdhLinkId + 12 * dpwId; + bool is_raw = (rdhLinkId != 15); bool orbit_jump = true; - int Dorbit1 = CRUh.hb_orbit - hb_orbit; - int Dorbit2 = (uint32_t)(((uint64_t)CRUh.hb_orbit) + 0x100000000 - hb_orbit); + int Dorbit1 = rdhOrbit - hb_orbit; + int Dorbit2 = (uint32_t)(((uint64_t)rdhOrbit) + 0x100000000 - hb_orbit); if (Dorbit1 >= 0 && Dorbit1 <= 1) orbit_jump = false; if (Dorbit2 >= 0 && Dorbit2 <= 1) orbit_jump = false; if (true && orbit_jump) { - int lid_min = (rdh_lid == 15) ? dpwId * 12 : 0; - int lid_max = (rdh_lid == 15) ? 11 + dpwId * 12 : 23; - if (gPrintLevel >= 1) - fprintf(flog, "Resetting decoding FSM: orbit=%d, previous=%d, links=%d-%d\n", - CRUh.hb_orbit, hb_orbit, lid_min, lid_max); + int lid_min = (rdhLinkId == 15) ? dpwId * 12 : 0; + int lid_max = (rdhLinkId == 15) ? 11 + dpwId * 12 : 23; for (int l = lid_min; l <= lid_max; l++) { for (int i = 0; i < 40; i++) { DualSampaReset(&(ds[cruId][l][i])); @@ -1236,20 +1074,16 @@ void Decoder::processData(const char* buf, size_t size) } } } - hb_orbit = CRUh.hb_orbit; + hb_orbit = rdhOrbit; - int nGBTwords = CRUh.block_length / 16; - int n64bitWords = CRUh.block_length / 8; + int nGBTwords = payloadSize / 16; + int n64bitWords = payloadSize / 8; - if (gPrintLevel >= 1) - fprintf(flog, "Starting to decode buffer...\n"); if (is_raw) decodeRaw(payload_buf, nGBTwords, cruId, cru_lid); else decodeUL(payload_buf, n64bitWords, cruId, dpwId); - if (gPrintLevel >= 1) - fprintf(flog, "mHits.size(): %d\n", (int)mHits.size()); for (size_t ih = 0; ih < mHits.size(); ih++) { SampaHit& hit = mHits[ih]; hit.pad.fDE = -1; @@ -1264,9 +1098,9 @@ void Decoder::processData(const char* buf, size_t size) if (!mMapFEC.getPadByLinkID(link_id, hit.ds_addr, hit.chan_addr, hit.pad)) continue; + + mDigits.emplace_back(o2::mch::Digit(hit.pad.fDE, hit.pad.fAddress, hit.csum, o2::mch::Digit::Time{})); } - if (gPrintLevel >= 1) - fprintf(flog, "Finished processing hits\n"); } } diff --git a/Modules/MUON/MCH/src/GlobalHistogram.cxx b/Modules/MUON/MCH/src/GlobalHistogram.cxx index 03138d09dc..9efa160fcc 100644 --- a/Modules/MUON/MCH/src/GlobalHistogram.cxx +++ b/Modules/MUON/MCH/src/GlobalHistogram.cxx @@ -342,7 +342,12 @@ void GlobalHistogram::add(std::map& histB, std::map& his set(histB, histNB, false); } -void GlobalHistogram::set(std::map& histB, std::map& histNB, bool doAverage) +void GlobalHistogram::set_includeNull(std::map& histB, std::map& histNB) +{ + set(histB, histNB, true, true); +} + +void GlobalHistogram::set(std::map& histB, std::map& histNB, bool doAverage, bool includeNullBins) { for (auto& ih : histB) { int de = ih.first; @@ -358,6 +363,8 @@ void GlobalHistogram::set(std::map& histB, std::map& his bool swapX = getLR(de) == 1; + //std::cout<<"[GlobalHistogram::set] de="< bboxB = o2::mch::mapping::getBBox(csegmentB); + o2::mch::contour::Contour envelopB = o2::mch::mapping::getEnvelop(csegmentB); - //std::cout<<"DE "< bboxNB = o2::mch::mapping::getBBox(csegmentNB); + o2::mch::contour::Contour envelopNB = o2::mch::mapping::getEnvelop(csegmentNB); + + if (de == 500 || de == 509) { + std::cout << "DE " << de << " B BBOX LIMITS " << bboxB.xmin() << " " << bboxB.xmax() << ", " << bboxB.ymin() << " " << bboxB.ymax() << std::endl; + std::cout << "DE " << de << " NB BBOX LIMITS " << bboxNB.xmin() << " " << bboxNB.xmax() << ", " << bboxNB.ymin() << " " << bboxNB.ymax() << std::endl; + } + + float xMin[2] = { static_cast(xB0 - bboxB.width() / 2), static_cast(xNB0 - bboxNB.width() / 2) }; + float xMax[2] = { static_cast(xB0 + bboxB.width() / 2), static_cast(xNB0 + bboxNB.width() / 2) }; + float yMin[2] = { static_cast(yB0 + bboxB.ymin()), static_cast(yNB0 + bboxNB.ymin()) }; + float yMax[2] = { static_cast(yB0 + bboxB.ymax()), static_cast(yNB0 + bboxNB.ymax()) }; + + //float xMin[2] = {xB0 - DE_WIDTH / 2, xNB0 - DE_WIDTH / 2}; + //float xMax[2] = {xB0 + DE_WIDTH / 2, xNB0 + DE_WIDTH / 2}; + //float yMin[2] = {yB0 - DE_HEIGHT / 2, yNB0 - DE_HEIGHT / 2}; + //float yMax[2] = {yB0 + DE_HEIGHT / 2, yNB0 + DE_HEIGHT / 2}; + + if (de == 500 || de == 509) { + std::cout << "DE " << de << "B LIMITS " << xMin[0] << " " << xMax[0] << ", " << yMin[0] << " " << yMax[0] << std::endl; + std::cout << "DE " << de << "NB LIMITS " << xMin[1] << " " << xMax[1] << ", " << yMin[1] << " " << yMax[1] << std::endl; + } float binWidthX = GetXaxis()->GetBinWidth(1); float binWidthY = GetYaxis()->GetBinWidth(1); @@ -396,7 +432,9 @@ void GlobalHistogram::set(std::map& histB, std::map& his int binYmin = GetYaxis()->FindBin(yMin[i] + binWidthY / 2); int binYmax = GetYaxis()->FindBin(yMax[i] - binWidthY / 2); - //std::cout<<(i==0 ? "B " : "NB")<<" BIN LIMITS "<& histB, std::map& his srcBinXmax -= 1; } + if (by == (binYmin + binYmax) / 2 && (de == 500 || de == 509)) { + //std::cout<<"DE "< %d\n", c, l, link_id); mSolarMap[c][l].mLink = link_id; + + if (link_id < 0 || link_id > LINKID_MAX) + continue; + mSolarMapInv[link_id].mCruId = c; + mSolarMapInv[link_id].mCruLink = l; } return true; } @@ -107,6 +136,18 @@ int32_t MapCRU::getLink(int32_t c, int32_t l) return mSolarMap[c][l].mLink; } +bool MapCRU::getLinkInv(uint32_t link_id, int32_t& c, int32_t& l) +{ + if (link_id > LINKID_MAX) + return false; + if (mSolarMapInv[link_id].mCruId < 0 || mSolarMapInv[link_id].mCruLink < 0) + return false; + + c = mSolarMapInv[link_id].mCruId; + l = mSolarMapInv[link_id].mCruLink; + return true; +} + /* * Electronics mapping */ @@ -137,6 +178,13 @@ bool MapFEC::readDSMapping(std::string mapFile) mDsMap[link_id][ds_addr].mDE = de; mDsMap[link_id][ds_addr].mIndex = ds_id[i]; mDsMap[link_id][ds_addr].mBad = 0; + + if (de < 0 || de > MCH_DE_MAX) + continue; + if (ds_id[i] < 0 || ds_id[i] > MCH_DSID_MAX) + continue; + mDsMapInv[de][ds_id[i]].mLink = link_id; + mDsMapInv[de][ds_id[i]].mAddress = ds_addr; } } return true; @@ -152,6 +200,16 @@ bool MapFEC::getDSMapping(uint32_t link_id, uint32_t ds_addr, uint32_t& de, uint return true; } +bool MapFEC::getDSMappingInv(uint32_t de, uint32_t dsid, uint32_t& link_id, uint32_t& ds_addr) +{ + //printf("getPad: link_id=%d ds_addr=%d bad=%d\n", link_id, ds_addr, mDsMap[link_id][ds_addr].mBad); + if (mDsMapInv[de][dsid].mLink < 0) + return false; + link_id = mDsMapInv[de][dsid].mLink; + ds_addr = mDsMapInv[de][dsid].mAddress; + return true; +} + bool MapFEC::getPadByLinkID(uint32_t link_id, uint32_t ds_addr, uint32_t dsch, MapPad& pad) { uint32_t de, dsid; diff --git a/Modules/MUON/MCH/src/PhysicsCheck.cxx b/Modules/MUON/MCH/src/PhysicsCheck.cxx new file mode 100644 index 0000000000..c6ea3c5d99 --- /dev/null +++ b/Modules/MUON/MCH/src/PhysicsCheck.cxx @@ -0,0 +1,140 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file PhysicsCheck.cxx +/// \author Andrea Ferrero, Sebastien Perrin +/// + +#include "MCHMappingInterface/Segmentation.h" +#include "MCHMappingSegContour/CathodeSegmentationContours.h" +#include "MCH/PhysicsCheck.h" + +// ROOT +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace o2::quality_control_modules::muonchambers +{ + +PhysicsCheck::PhysicsCheck() +{ + mPrintLevel = 0; + minOccupancy = 0.05; + maxOccupancy = 1.00; +} + +PhysicsCheck::~PhysicsCheck() {} + +void PhysicsCheck::configure(std::string) +{ + // if (AliRecoParam::ConvertIndex(specie) == AliRecoParam::kCosmic) { + // minTOFrawTime = 150.; //ns + // maxTOFrawTime = 250.; //ns + // } +} + +Quality PhysicsCheck::check(std::map>* moMap) +{ + std::cout << "=================================" << std::endl; + std::cout << "PhysicsCheck::check() called" << std::endl; + std::cout << "=================================" << std::endl; + Quality result = Quality::Null; + + for (auto& [moName, mo] : *moMap) { + + (void)moName; + if (mo->getName().find("QcMuonChambers_Occupancy_Elec") != std::string::npos) { + auto* h = dynamic_cast(mo->getObject()); + if (!h) + return result; + + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + int nbinsx = 3; //h->GetXaxis()->GetNbins(); + int nbinsy = h->GetYaxis()->GetNbins(); + int nbad = 0; + for (int i = 1; i <= nbinsx; i++) { + for (int j = 1; j <= nbinsy; j++) { + Float_t occ = h->GetBinContent(i, j); + if (occ < minOccupancy || occ >= maxOccupancy) { + nbad += 1; + int ds_addr = (i % 40) - 1; + int link_id = ((i - 1 - ds_addr) / 40) % 12; + int fee_id = (i - 1 - ds_addr - 40 * link_id) / (12 * 40); + int chan_addr = j - 1; + + if (mPrintLevel >= 1) { + std::cout << "Channel with unusual occupancy read from OccupancyElec histogrm: fee_id = " << fee_id << ", link_id = " << link_id << ", ds_addr = " << ds_addr << " , chan_addr = " << chan_addr << " with an occupancy of " << occ << std::endl; + } + } + } + } + if (nbad < 1) + result = Quality::Good; + else + result = Quality::Bad; + } + } + } + return result; +} + +std::string PhysicsCheck::getAcceptedType() { return "TH1"; } + +void PhysicsCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + //std::cout<<"===================================="<getName().find("QcMuonChambers_Occupancy_Elec") != std::string::npos) { + auto* h = dynamic_cast(mo->getObject()); + h->SetDrawOption("colz"); + TPaveText* msg = new TPaveText(0.1, 0.9, 0.9, 0.95, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + + if (checkResult == Quality::Good) { + msg->Clear(); + msg->AddText("All occupancies within limits: OK!!!"); + msg->SetFillColor(kGreen); + // + h->SetFillColor(kGreen); + } else if (checkResult == Quality::Bad) { + LOG(INFO) << "Quality::Bad, setting to red"; + // + msg->Clear(); + msg->AddText("Call MCH on-call."); + msg->SetFillColor(kRed); + // + h->SetFillColor(kRed); + } else if (checkResult == Quality::Medium) { + LOG(INFO) << "Quality::medium, setting to orange"; + // + msg->Clear(); + msg->AddText("No entries. If MCH in the run, check MCH TWiki"); + msg->SetFillColor(kYellow); + h->SetFillColor(kOrange); + } + h->SetLineColor(kBlack); + } +} + +} // namespace o2::quality_control_modules::muonchambers diff --git a/Modules/MUON/MCH/src/PhysicsTask.cxx b/Modules/MUON/MCH/src/PhysicsTask.cxx deleted file mode 100644 index 2ef9487a6c..0000000000 --- a/Modules/MUON/MCH/src/PhysicsTask.cxx +++ /dev/null @@ -1,289 +0,0 @@ -/// -/// \file PhysicsTask.cxx -/// \author Barthelemy von Haller -/// \author Piotr Konopka -/// \author Andrea Ferrero -/// - -#include -#include -#include -#include -#include - -#include "Headers/RAWDataHeader.h" -#include "QualityControl/QcInfoLogger.h" -#include "MCH/PhysicsTask.h" -//#include "MCHPreClustering/PreClusterFinder.h" - -using namespace std; - -static int gPrintLevel; - -static FILE* flog = NULL; - -struct CRUheader { - uint8_t header_version; - uint8_t header_size; - uint16_t block_length; - uint16_t fee_id; - uint8_t priority_bit; - uint8_t reserved_1; - uint16_t next_packet_offset; - uint16_t memory_size; - uint8_t link_id; - uint8_t packet_counter; - uint16_t source_id; - uint32_t hb_orbit; - //uint16_t cru_id; - //uint8_t dummy1; - //uint64_t dummy2; -}; - -enum decode_state_t { - DECODE_STATE_UNKNOWN, - DECODE_STATE_SYNC_FOUND, - DECODE_STATE_HEADER_FOUND, - DECODE_STATE_CSIZE_FOUND, - DECODE_STATE_CTIME_FOUND, - DECODE_STATE_SAMPLE_FOUND -}; - -namespace o2 -{ -namespace quality_control_modules -{ -namespace muonchambers -{ -PhysicsTask::PhysicsTask() : TaskInterface(), count(1) {} - -PhysicsTask::~PhysicsTask() { fclose(flog); } - -void PhysicsTask::initialize(o2::framework::InitContext& /*ctx*/) -{ - QcInfoLogger::GetInstance() << "initialize PhysicsTask" << AliceO2::InfoLogger::InfoLogger::endm; - fprintf(stdout, "initialize PhysicsTask\n"); - - mDecoder.initialize(); - - uint32_t dsid; - std::vector DEs; - for (int cruid = 0; cruid < 3; cruid++) { - QcInfoLogger::GetInstance() << "JE SUIS ENTRÉ DANS LA BOUCLE CRUID " << cruid << AliceO2::InfoLogger::InfoLogger::endm; - for (int linkid = 0; linkid < 24; linkid++) { - QcInfoLogger::GetInstance() << "JE SUIS ENTRÉ DANS LA BOUCLE LINKID " << linkid << AliceO2::InfoLogger::InfoLogger::endm; - - { - int index = 24 * cruid + linkid; - mHistogramNhits[index] = new TH2F(TString::Format("QcMuonChambers_NHits_CRU%01d_LINK%02d", cruid, linkid), - TString::Format("QcMuonChambers - Number of hits (CRU link %02d)", index), 40, 0, 40, 64, 0, 64); - //mHistogramPedestals->SetDrawOption("col"); - getObjectsManager()->startPublishing(mHistogramNhits[index]); - - mHistogramADCamplitude[index] = new TH1F(TString::Format("QcMuonChambers_ADC_Amplitude_CRU%01d_LINK%02d", cruid, linkid), - TString::Format("QcMuonChambers - ADC amplitude (CRU link %02d)", index), 5000, 0, 5000); - //mHistogramPedestals->SetDrawOption("col"); - getObjectsManager()->startPublishing(mHistogramADCamplitude[index]); - } - - int32_t link_id = mDecoder.getMapCRU(cruid, linkid); - if (link_id == -1) - continue; - for (int ds_addr = 0; ds_addr < 40; ds_addr++) { - QcInfoLogger::GetInstance() << "JE SUIS ENTRÉ DANS LA BOUCLE DS_ADDR " << ds_addr << AliceO2::InfoLogger::InfoLogger::endm; - uint32_t de = mDecoder.getMapFEC(link_id, ds_addr, de, dsid); - QcInfoLogger::GetInstance() << "C'EST LA LIGNE APRÈS LE GETMAPFEC, DE " << de << AliceO2::InfoLogger::InfoLogger::endm; - - if (!(std::find(DEs.begin(), DEs.end(), de) != DEs.end())) { - DEs.push_back(de); - - TH1F* h = new TH1F(TString::Format("QcMuonChambers_ADCamplitude_DE%03d", de), - TString::Format("QcMuonChambers - ADC amplitude (DE%03d)", de), 5000, 0, 5000); - mHistogramADCamplitudeDE.insert(make_pair(de, h)); - getObjectsManager()->startPublishing(h); - - float Xsize = 40 * 5; - float Xsize2 = Xsize / 2; - float Ysize = 50; - float Ysize2 = Ysize / 2; - - TH2F* h2 = new TH2F(TString::Format("QcMuonChambers_Nhits_DE%03d", de), - TString::Format("QcMuonChambers - Number of hits (DE%03d)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); - mHistogramNhitsDE.insert(make_pair(de, h2)); - getObjectsManager()->startPublishing(h2); - h2 = new TH2F(TString::Format("QcMuonChambers_Nhits_HighAmpl_DE%03d", de), - TString::Format("QcMuonChambers - Number of hits for Csum>500 (DE%03d)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); - mHistogramNhitsHighAmplDE.insert(make_pair(de, h2)); - getObjectsManager()->startPublishing(h2); - } - } - } - } - - gPrintLevel = 0; - - flog = stdout; //fopen("/root/qc.log", "w"); - fprintf(stdout, "PhysicsTask initialization finished\n"); -} - -void PhysicsTask::startOfActivity(Activity& /*activity*/) -{ - QcInfoLogger::GetInstance() << "startOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; -} - -void PhysicsTask::startOfCycle() -{ - QcInfoLogger::GetInstance() << "startOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; -} - -void PhysicsTask::monitorData(o2::framework::ProcessingContext& ctx) -{ - // todo: update API examples or refer to DPL README.md - - //QcInfoLogger::GetInstance() << "PhysicsTask::monitorData" << AliceO2::InfoLogger::InfoLogger::endm; - - printf("count: %d\n", count); - if ((count % 1) == 0) { - - TFile f("/tmp/qc.root", "RECREATE"); - for (int i = 0; i < 3 * 24; i++) { - mHistogramNhits[i]->Write(); - mHistogramADCamplitude[i]->Write(); - } - int nbDEs = DEs.size(); - for (int elem = 0; elem < nbDEs; elem++) { - int de = DEs[elem]; - auto h = mHistogramADCamplitudeDE.find(de); - if ((h != mHistogramADCamplitudeDE.end()) && (h->second != NULL)) { - h->second->Write(); - } - auto h2 = mHistogramNhitsDE.find(de); - if ((h2 != mHistogramNhitsDE.end()) && (h2->second != NULL)) { - h2->second->Write(); - } - - f.ls(); - f.Close(); - } - } - count += 1; - - // exemplary ways of accessing inputs (incoming data), that were specified in the .ini file - e.g.: - // [readoutInput] - // inputName=readout - // dataOrigin=ITS - // dataDescription=RAWDATA - - // 1. in a loop - for (auto&& input : ctx.inputs()) { - const auto* header = o2::header::get(input.header); - //QcInfoLogger::GetInstance() << "header: " << header << AliceO2::InfoLogger::InfoLogger::endm; - //if(gPrintLevel>=1) fprintf(flog, "Header: %p\n", header); - if (!header) - continue; - //QcInfoLogger::GetInstance() << "payloadSize: " << header->payloadSize << AliceO2::InfoLogger::InfoLogger::endm; - if (gPrintLevel >= 1) - fprintf(flog, "payloadSize: %d\n", (int)header->payloadSize); - if (gPrintLevel >= 1) - fprintf(flog, "payload: %s\n", input.payload); - //continue; - - mDecoder.processData(input.payload, header->payloadSize); - - std::vector& hits = mDecoder.getHits(); - if (gPrintLevel >= 1) - fprintf(flog, "hits.size()=%d\n", (int)hits.size()); - for (uint32_t i = 0; i < hits.size(); i++) { - //continue; - SampaHit& hit = hits[i]; - if (gPrintLevel >= 1) - fprintf(stdout, "hit[%d]: link_id=%d, ds_addr=%d, chan_addr=%d\n", - i, hit.link_id, hit.ds_addr, hit.chan_addr); - if (hit.link_id >= 24 || hit.ds_addr >= 40 || hit.chan_addr >= 64) { - fprintf(stdout, "hit[%d]: link_id=%d, ds_addr=%d, chan_addr=%d\n", - i, hit.link_id, hit.ds_addr, hit.chan_addr); - continue; - } - //if( hit.csum > 500 ) { - mHistogramNhits[hit.link_id]->Fill(hit.ds_addr, hit.chan_addr); - mHistogramADCamplitude[hit.link_id]->Fill(hit.csum); - //} - - //mch::DigitStruct digit; - - int de = hit.pad.fDE; - float padX = hit.pad.fX; - float padY = hit.pad.fY; - float padSizeX = hit.pad.fSizeX; - float padSizeY = hit.pad.fSizeY; - - if (gPrintLevel >= 1) - fprintf(flog, "mapping: link_id=%d ds_addr=%d chan_addr=%d ==> de=%d x=%f y=%f\n", - hit.link_id, hit.ds_addr, hit.chan_addr, de, padX, padY); - //if(pad.fX>=32 && pad.fX<=34 && pad.fY>=1.1 && pad.fY<=1.4) - // fprintf(flog, "mapping: link_id=%d ds_addr=%d chan_addr=%d ==> de=%d x=%f y=%f A=%d\n", - // hit.link_id, hit.ds_addr, hit.chan_addr, pad.fDE, pad.fX, pad.fY, hit.csum); - - auto h = mHistogramADCamplitudeDE.find(de); - if ((h != mHistogramADCamplitudeDE.end()) && (h->second != NULL)) { - h->second->Fill(hit.csum); - } - - if (hit.csum > 0) { - auto h2 = mHistogramNhitsDE.find(de); - if ((h2 != mHistogramNhitsDE.end()) && (h2->second != NULL)) { - int binx_min = h2->second->GetXaxis()->FindBin(padX - padSizeX / 2 + 0.1); - int binx_max = h2->second->GetXaxis()->FindBin(padX + padSizeX / 2 - 0.1); - int biny_min = h2->second->GetYaxis()->FindBin(padY - padSizeY / 2 + 0.1); - int biny_max = h2->second->GetYaxis()->FindBin(padY + padSizeY / 2 - 0.1); - for (int by = biny_min; by <= biny_max; by++) { - float y = h2->second->GetYaxis()->GetBinCenter(by); - for (int bx = binx_min; bx <= binx_max; bx++) { - float x = h2->second->GetXaxis()->GetBinCenter(bx); - h2->second->Fill(x, y); - } - } - } - } - if (hit.csum > 500) { - auto h2 = mHistogramNhitsHighAmplDE.find(de); - if ((h2 != mHistogramNhitsHighAmplDE.end()) && (h2->second != NULL)) { - int binx_min = h2->second->GetXaxis()->FindBin(padX - padSizeX / 2 + 0.1); - int binx_max = h2->second->GetXaxis()->FindBin(padX + padSizeX / 2 - 0.1); - int biny_min = h2->second->GetYaxis()->FindBin(padY - padSizeY / 2 + 0.1); - int biny_max = h2->second->GetYaxis()->FindBin(padY + padSizeY / 2 - 0.1); - for (int by = biny_min; by <= biny_max; by++) { - float y = h2->second->GetYaxis()->GetBinCenter(by); - for (int bx = binx_min; bx <= binx_max; bx++) { - float x = h2->second->GetXaxis()->GetBinCenter(bx); - h2->second->Fill(x, y); - } - } - } - } - } - - mDecoder.clearHits(); - } -} - -void PhysicsTask::endOfCycle() -{ - QcInfoLogger::GetInstance() << "endOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; -} - -void PhysicsTask::endOfActivity(Activity& /*activity*/) -{ - QcInfoLogger::GetInstance() << "endOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; -} - -void PhysicsTask::reset() -{ - // clean all the monitor objects here - - QcInfoLogger::GetInstance() << "Reseting the histogram" << AliceO2::InfoLogger::InfoLogger::endm; -} - -} // namespace muonchambers -} // namespace quality_control_modules -} // namespace o2 diff --git a/Modules/MUON/MCH/src/PhysicsTaskDigits.cxx b/Modules/MUON/MCH/src/PhysicsTaskDigits.cxx new file mode 100644 index 0000000000..3e295d2533 --- /dev/null +++ b/Modules/MUON/MCH/src/PhysicsTaskDigits.cxx @@ -0,0 +1,527 @@ +/// +/// \file PhysicsTaskDigits.cxx +/// \author Barthelemy von Haller +/// \author Piotr Konopka +/// \author Andrea Ferrero +/// \author Sebastien Perrin +/// + +#include +#include +#include +#include +#include + +#include "MCH/PhysicsTaskDigits.h" +#ifdef MCH_HAS_MAPPING_FACTORY +#include "MCHMappingFactory/CreateSegmentation.h" +#endif +#include "MCHMappingInterface/Segmentation.h" +#include "MCHMappingInterface/CathodeSegmentation.h" +#include "MCHMappingSegContour/CathodeSegmentationContours.h" +#include "QualityControl/QcInfoLogger.h" + +using namespace std; +using namespace o2::mch::raw; + +//#define QC_MCH_SAVE_TEMP_ROOTFILE 1 + +namespace o2 +{ +namespace quality_control_modules +{ +namespace muonchambers +{ + +PhysicsTaskDigits::PhysicsTaskDigits() : TaskInterface() {} + +PhysicsTaskDigits::~PhysicsTaskDigits() {} + +void PhysicsTaskDigits::initialize(o2::framework::InitContext& /*ctx*/) +{ + QcInfoLogger::GetInstance() << "initialize PhysicsTaskDigits" << AliceO2::InfoLogger::InfoLogger::endm; + + mElec2DetMapper = createElec2DetMapper(); + mDet2ElecMapper = createDet2ElecMapper(); + mFeeLink2SolarMapper = createFeeLink2SolarMapper(); + mSolar2FeeLinkMapper = createSolar2FeeLinkMapper(); + + for (int feeid = 0; feeid < MCH_FEEID_NUM; feeid++) { + for (int linkid = 0; linkid < 12; linkid++) { + int index = 12 * feeid + linkid; + mHistogramNhits[index] = new TH2F(TString::Format("QcMuonChambers_NHits_FEE%01d_LINK%02d", feeid, linkid), + TString::Format("QcMuonChambers - Number of hits (FEE link %02d)", index), 40, 0, 40, 64, 0, 64); + mHistogramADCamplitude[index] = new TH1F(TString::Format("QcMuonChambers_ADC_Amplitude_FEE%01d_LINK%02d", feeid, linkid), + TString::Format("QcMuonChambers - ADC amplitude (FEE link %02d)", index), 5000, 0, 5000); + } + } + for (auto de : o2::mch::raw::deIdsForAllMCH) { + TH1F* h = new TH1F(TString::Format("QcMuonChambers_ADCamplitude_DE%03d", de), + TString::Format("QcMuonChambers - ADC amplitude (DE%03d)", de), 5000, 0, 5000); + mHistogramADCamplitudeDE.insert(make_pair(de, h)); + + float Xsize = 40 * 5; + float Xsize2 = Xsize / 2; + float Ysize = 50; + float Ysize2 = Ysize / 2; + float scale = 0.5; + + TH2F* h2 = new TH2F(TString::Format("QcMuonChambers_Nhits_DE%03d_B", de), + TString::Format("QcMuonChambers - Number of hits (DE%03d B)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); + mHistogramNhitsDE[0].insert(make_pair(de, h2)); + // getObjectsManager()->startPublishing(h2); + h2 = new TH2F(TString::Format("QcMuonChambers_Nhits_DE%03d_NB", de), + TString::Format("QcMuonChambers - Number of hits (DE%03d NB)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); + mHistogramNhitsDE[1].insert(make_pair(de, h2)); + // getObjectsManager()->startPublishing(h2); + h2 = new TH2F(TString::Format("QcMuonChambers_Norbits_DE%03d_B", de), + TString::Format("QcMuonChambers - Number of orbits (DE%03d B)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); + mHistogramNorbitsDE[0].insert(make_pair(de, h2)); + h2 = new TH2F(TString::Format("QcMuonChambers_Norbits_DE%03d_NB", de), + TString::Format("QcMuonChambers - Number of orbits (DE%03d NB)", de), Xsize * 2, -Xsize2, Xsize2, Ysize * 2, -Ysize2, Ysize2); + mHistogramNorbitsDE[1].insert(make_pair(de, h2)); + + { + TH2F* hXY = new TH2F(TString::Format("QcMuonChambers_Occupancy_B_XY_%03d", de), + TString::Format("QcMuonChambers - Occupancy XY (DE%03d B) (MHz)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramOccupancyXY[0].insert(make_pair(de, hXY)); + // getObjectsManager()->startPublishing(hXY); + hXY = new TH2F(TString::Format("QcMuonChambers_Occupancy_NB_XY_%03d", de), + TString::Format("QcMuonChambers - Occupancy XY (DE%03d NB) (MHz)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramOccupancyXY[1].insert(make_pair(de, hXY)); + // getObjectsManager()->startPublishing(hXY); + } + } + + for (int fee = 0; fee < MCH_FEEID_NUM; fee++) { + for (int link = 0; link < 12; link++) { + norbits[fee][link] = lastorbitseen[fee][link] = 0; + } + } + for (int de = 0; de < 1100; de++) { + MeanOccupancyDE[de] = MeanOccupancyDECycle[de] = LastMeanNhitsDE[de] = LastMeanNorbitsDE[de] = NewMeanNhitsDE[de] = NewMeanNorbitsDE[de] = NbinsDE[de] = 0; + } + + // Histograms using the Electronic Mapping + + mHistogramNorbitsElec = new TH2F("QcMuonChambers_Norbits_Elec", "QcMuonChambers - Norbits", + MCH_FEEID_NUM * 12 * 40, 0, MCH_FEEID_NUM * 12 * 40, 64, 0, 64); + mHistogramNorbitsElec->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramNorbitsElec); + mHistogramNHitsElec = new TH2F("QcMuonChambers_NHits_Elec", "QcMuonChambers - NHits", + MCH_FEEID_NUM * 12 * 40, 0, MCH_FEEID_NUM * 12 * 40, 64, 0, 64); + mHistogramNHitsElec->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramNHitsElec); + mHistogramOccupancyElec = new TH2F("QcMuonChambers_Occupancy_Elec", "QcMuonChambers - Occupancy (MHz)", + MCH_FEEID_NUM * 12 * 40, 0, MCH_FEEID_NUM * 12 * 40, 64, 0, 64); + mHistogramOccupancyElec->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramOccupancyElec); + + // 1D histograms for mean occupancy per DE (integrated or per elapsed cycle) - Sent for Trending + + mMeanOccupancyPerDE = new TH1F("QcMuonChambers_MeanOccupancy", "Mean Occupancy of each DE (MHz)", 1100, -0.5, 1099.5); + getObjectsManager()->startPublishing(mMeanOccupancyPerDE); + mMeanOccupancyPerDECycle = new TH1F("QcMuonChambers_MeanOccupancy_OnCycle", "Mean Occupancy of each DE during the cycle (MHz)", 1100, -0.5, 1099.5); + getObjectsManager()->startPublishing(mMeanOccupancyPerDECycle); + + mHistogramOccupancy[0] = new GlobalHistogram("QcMuonChambers_Occupancy_den", "Occupancy (MHz)"); + mHistogramOccupancy[0]->init(); + mHistogramOccupancy[0]->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramOccupancy[0]); + + mHistogramOrbits[0] = new GlobalHistogram("QcMuonChambers_Orbits_den", "Orbits"); + mHistogramOrbits[0]->init(); + mHistogramOrbits[0]->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramOrbits[0]); +} + +void PhysicsTaskDigits::startOfActivity(Activity& /*activity*/) +{ + QcInfoLogger::GetInstance() << "startOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; +} + +void PhysicsTaskDigits::startOfCycle() +{ + QcInfoLogger::GetInstance() << "startOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; +} + +void PhysicsTaskDigits::monitorData(o2::framework::ProcessingContext& ctx) +{ + // get the input preclusters and associated digits with the orbit information + auto digits = ctx.inputs().get>("digits"); + auto orbits = ctx.inputs().get>("orbits"); + if (orbits.empty()) { + QcInfoLogger::GetInstance() << "WARNING: empty orbits vector" << AliceO2::InfoLogger::InfoLogger::endm; + return; + } + + for (auto& orb : orbits) { + uint32_t orbitnumber = (orb & 0xFFFFFFFF); + uint32_t link = (orb >> 32) & 0xFF; + uint32_t fee = (orb >> 40) & 0xFF; + if (link != 15) { + if (orbitnumber != lastorbitseen[fee][link]) { + norbits[fee][link] += 1; + } + lastorbitseen[fee][link] = orbitnumber; + } else if (link == 15) { + for (int li = 0; li < 12; li++) { + if (orbitnumber != lastorbitseen[fee][li]) { + norbits[fee][li] += 1; + } + lastorbitseen[fee][li] = orbitnumber; + } + } + } + + for (auto& d : digits) { + plotDigit(d); + } +} + +void PhysicsTaskDigits::plotDigit(const o2::mch::Digit& digit) +{ + int ADC = digit.getADC(); + int de = digit.getDetID(); + int padid = digit.getPadID(); + + if (ADC < 0 || de <= 0 || padid < 0) { + return; + } + + // Fill NHits Elec Histogram and ADC distribution + // Using the mapping to go from Digit info (de, pad) to Elec info (fee, link) and fill Elec Histogram, where one bin is one physical pad + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(de); + + double padX = segment.padPositionX(padid); + double padY = segment.padPositionY(padid); + float padSizeX = segment.padSizeX(padid); + float padSizeY = segment.padSizeY(padid); + int cathode = segment.isBendingPad(padid) ? 0 : 1; + int dsid = segment.padDualSampaId(padid); + int chan_addr = segment.padDualSampaChannel(padid); + + uint32_t solar_id = 0; + uint32_t ds_addr = 0; + int32_t linkid = 0; + int32_t fee_id = 0; + + // get the unique solar ID and the DS address associated to this digit + std::optional dsElecId = mDet2ElecMapper(DsDetId{ de, dsid }); + if (dsElecId.has_value()) { + solar_id = dsElecId->solarId(); + ds_addr = dsElecId->elinkId(); + + std::optional feeLinkId = mSolar2FeeLinkMapper(solar_id); + if (feeLinkId.has_value()) { + fee_id = feeLinkId->feeId(); + linkid = feeLinkId->linkId(); + } + } + + //xbin and ybin uniquely identify each physical pad + int xbin = fee_id * 12 * 40 + (linkid % 12) * 40 + ds_addr + 1; + int ybin = chan_addr + 1; + + mHistogramNHitsElec->Fill(xbin - 0.5, ybin - 0.5); + + auto h = mHistogramADCamplitudeDE.find(de); + if ((h != mHistogramADCamplitudeDE.end()) && (h->second != NULL)) { + h->second->Fill(ADC); + } + + if (ADC <= 0) { + return; + } + + // Fill X Y 2D hits histogram with fired pads distribution + auto h2 = mHistogramNhitsDE[cathode].find(de); + if ((h2 != mHistogramNhitsDE[cathode].end()) && (h2->second != NULL)) { + int binx_min = h2->second->GetXaxis()->FindBin(padX - padSizeX / 2 + 0.1); + int binx_max = h2->second->GetXaxis()->FindBin(padX + padSizeX / 2 - 0.1); + int biny_min = h2->second->GetYaxis()->FindBin(padY - padSizeY / 2 + 0.1); + int biny_max = h2->second->GetYaxis()->FindBin(padY + padSizeY / 2 - 0.1); + for (int by = biny_min; by <= biny_max; by++) { + float y = h2->second->GetYaxis()->GetBinCenter(by); + for (int bx = binx_min; bx <= binx_max; bx++) { + float x = h2->second->GetXaxis()->GetBinCenter(bx); + h2->second->Fill(x, y); + } + } + } + + // Get the Elec information to fill histogram of orbits (XY histogram) + h2 = mHistogramNorbitsDE[cathode].find(de); + if ((h2 != mHistogramNorbitsDE[cathode].end()) && (h2->second != NULL)) { + int NYbins = h2->second->GetYaxis()->GetNbins(); + int NXbins = h2->second->GetXaxis()->GetNbins(); + for (int by = 0; by < NYbins; by++) { + float y = h2->second->GetYaxis()->GetBinCenter(by); + for (int bx = 0; bx < NXbins; bx++) { + float x = h2->second->GetXaxis()->GetBinCenter(bx); + + // get pad and DS channel mappings for this bin + int bpad = 0; + int nbpad = 0; + uint32_t solar_id_boucle = 0; + + if (segment.findPadPairByPosition(x, y, bpad, nbpad)) { + + // get the unique solar ID and the DS address associated to this bin + int padid_boucle = (cathode == 0) ? bpad : nbpad; + int dsid_boucle = segment.padDualSampaId(padid_boucle); + std::optional dsElecId = mDet2ElecMapper(DsDetId{ de, dsid_boucle }); + if (dsElecId.has_value()) { + solar_id_boucle = dsElecId->solarId(); + } + + if (solar_id_boucle == solar_id) { + h2->second->SetBinContent(bx, by, norbits[fee_id][linkid]); + } + } + } + } + } +} + +void PhysicsTaskDigits::endOfCycle() +{ + QcInfoLogger::GetInstance() << "endOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; + for (int de = 100; de <= 1030; de++) { + for (int i = 0; i < 2; i++) { + auto ih = mHistogramOccupancyXY[i].find(de); + ih = mHistogramOccupancyXY[i].find(de); + if (ih == mHistogramOccupancyXY[i].end()) { + continue; + } + } + } + + // Compute Occupancy in GlobalHistograms by dividing Hits by Orbits and scaling + mHistogramOrbits[0]->set(mHistogramNorbitsDE[0], mHistogramNorbitsDE[1]); + mHistogramOccupancy[0]->set(mHistogramNhitsDE[0], mHistogramNhitsDE[1]); + mHistogramOccupancy[0]->Divide(mHistogramOrbits[0]); + mHistogramOccupancy[0]->Scale(1 / 87.5); // Converting Occupancy from NbHits/NbOrbits to MHz + + // Fill NOrbits, in Elec view, for electronics channels associated to readout pads (in order to then compute the Occupancy in Elec view, physically meaningful because in Elec view, each bin is a physical pad) + for (uint16_t fee_id = 0; fee_id < MCH_FEEID_NUM; fee_id++) { + + // loop on FEE links and check if it corresponds to an existing SOLAR board + for (uint8_t linkid = 0; linkid < 12; linkid++) { + + std::optional solar_id = mFeeLink2SolarMapper(FeeLinkId{ fee_id, linkid }); + if (!solar_id.has_value()) { + continue; + } + + // loop on DS boards and check if it exists in the mapping + for (uint8_t ds_addr = 0; ds_addr < 40; ds_addr++) { + uint32_t de, dsid; + std::optional dsDetId = + mElec2DetMapper(DsElecId{ solar_id.value(), static_cast(ds_addr / 5), static_cast(ds_addr % 5) }); + if (!dsDetId.has_value()) { + continue; + } + de = dsDetId->deId(); + dsid = dsDetId->dsId(); + + int xbin = fee_id * 12 * 40 + (linkid % 12) * 40 + ds_addr + 1; + + // loop on DS channels and check if it is associated to a readout pad + for (int chan_addr = 0; chan_addr < 64; chan_addr++) { + + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(de); + int padid = segment.findPadByFEE(dsid, chan_addr); + if (padid < 0) { + continue; + } + + int ybin = chan_addr + 1; + mHistogramNorbitsElec->SetBinContent(xbin, ybin, norbits[fee_id][linkid]); + } + } + } + } + + // Compute Occupancy in Elec view by dividing Hits by Orbits and scaling + mHistogramOccupancyElec->Reset(); + mHistogramOccupancyElec->Add(mHistogramNHitsElec); + mHistogramOccupancyElec->Divide(mHistogramNorbitsElec); + mHistogramOccupancyElec->Scale(1 / 87.5); // Converting Occupancy from NbHits/NbOrbits to MHz + + // Compute the Occupancy for individual DE XY histograms + for (int de = 0; de < 1100; de++) { + for (int i = 0; i < 2; i++) { + auto h = mHistogramOccupancyXY[i].find(de); + if ((h != mHistogramOccupancyXY[i].end()) && (h->second != NULL)) { + auto hhits = mHistogramNhitsDE[i].find(de); + auto horbits = mHistogramNorbitsDE[i].find(de); + if ((hhits != mHistogramNhitsDE[i].end()) && (horbits != mHistogramNorbitsDE[i].end()) && (hhits->second != NULL) && (horbits->second != NULL)) { + h->second->Divide(hhits->second, horbits->second); + h->second->Scale(1 / 87.5); // Converting Occupancy from NbHits/NbOrbits to MHz + } + } + } + } + + { + // Using OccupancyElec to get the mean occupancy per DE + // By looking at each bin in NHits Elec histogram, getting the Elec info (fee, link, de) for each bin, computing the number of hits seen on a given DE and dividing by the number of bins + auto h = mHistogramOccupancyElec; + auto horbits = mHistogramNorbitsElec; + auto h1 = mMeanOccupancyPerDE; + if (h && h1 && horbits) { + for (int de = 0; de < 1100; de++) { + MeanOccupancyDE[de] = 0; + NbinsDE[de] = 0; + } + for (int binx = 1; binx < h->GetXaxis()->GetNbins() + 1; binx++) { + for (int biny = 1; biny < h->GetYaxis()->GetNbins() + 1; biny++) { + + int norbits = horbits->GetBinContent(binx, biny); + if (norbits <= 0) { + // no orbits detected for this channel, skip it + continue; + } + + // Getting Elec information based on the definition of x and y bins in ElecHistograms + uint32_t ds_addr = (binx - 1) % 40; + uint32_t linkid = ((binx - 1 - ds_addr) / 40) % 12; + uint32_t fee_id = (binx - 1 - ds_addr - 40 * linkid) / (12 * 40); + uint32_t de; + std::optional solar_id = mFeeLink2SolarMapper(FeeLinkId{ static_cast(fee_id), static_cast(linkid) }); + if (!solar_id.has_value()) { + continue; + } + std::optional dsDetId = + mElec2DetMapper(DsElecId{ solar_id.value(), static_cast(ds_addr / 5), static_cast(ds_addr % 5) }); + if (!dsDetId.has_value()) { + continue; + } + de = dsDetId->deId(); + + MeanOccupancyDE[de] += h->GetBinContent(binx, biny); + NbinsDE[de] += 1; + } + } + + for (int i = 0; i < 1100; i++) { + if (NbinsDE[i] > 0) { + MeanOccupancyDE[i] /= NbinsDE[i]; + } + h1->SetBinContent(i + 1, MeanOccupancyDE[i]); + } + } + } + + { + // Using NHitsElec and Norbits to get the mean occupancy per DE on last cycle + // Similarly, by looking at NHits and NOrbits Elec histogram, for each bin incrementing the corresponding DE total hits and total orbits, and from the values obtained at the end of a cycle compared to the beginning of the cycle, computing the occupancy during the cycle. + auto hhits = mHistogramNHitsElec; + auto horbits = mHistogramNorbitsElec; + auto h1 = mMeanOccupancyPerDECycle; + if (hhits && horbits && h1) { + for (int de = 0; de < 1100; de++) { + NewMeanNhitsDE[de] = 0; + NewMeanNorbitsDE[de] = 0; + } + for (int binx = 1; binx < hhits->GetXaxis()->GetNbins() + 1; binx++) { + for (int biny = 1; biny < hhits->GetYaxis()->GetNbins() + 1; biny++) { + // Same procedure as above in getting Elec info + uint32_t ds_addr = (binx - 1) % 40; + uint32_t linkid = ((binx - 1 - ds_addr) / 40) % 12; + uint32_t fee_id = (binx - 1 - ds_addr - 40 * linkid) / (12 * 40); + uint32_t de; + std::optional solar_id = mFeeLink2SolarMapper(FeeLinkId{ static_cast(fee_id), static_cast(linkid) }); + if (!solar_id.has_value()) { + continue; + } + std::optional dsDetId = + mElec2DetMapper(DsElecId{ solar_id.value(), static_cast(ds_addr / 5), static_cast(ds_addr % 5) }); + if (!dsDetId.has_value()) { + continue; + } + de = dsDetId->deId(); + + NewMeanNhitsDE[de] += hhits->GetBinContent(binx, biny); + NewMeanNorbitsDE[de] += horbits->GetBinContent(binx, biny); + NbinsDE[de] += 1; + } + } + for (int i = 0; i < 1100; i++) { + MeanOccupancyDECycle[i] = 0; + if (NbinsDE[i] > 0) { + NewMeanNhitsDE[i] /= NbinsDE[i]; + NewMeanNorbitsDE[i] /= NbinsDE[i]; + } + if ((NewMeanNorbitsDE[i] - LastMeanNorbitsDE[i]) > 0) { + MeanOccupancyDECycle[i] = (NewMeanNhitsDE[i] - LastMeanNhitsDE[i]) / (NewMeanNorbitsDE[i] - LastMeanNorbitsDE[i]) / 87.5; //Scaling to MHz + } + h1->SetBinContent(i + 1, MeanOccupancyDECycle[i]); + LastMeanNhitsDE[i] = NewMeanNhitsDE[i]; + LastMeanNorbitsDE[i] = NewMeanNorbitsDE[i]; + } + } + } +} + +void PhysicsTaskDigits::endOfActivity(Activity& /*activity*/) +{ + QcInfoLogger::GetInstance() << "endOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; + +#ifdef QC_MCH_SAVE_TEMP_ROOTFILE + TFile f("/tmp/qc.root", "RECREATE"); + + mHistogramNorbitsElec->Write(); + mHistogramNHitsElec->Write(); + mHistogramOccupancyElec->Write(); + + for (int de = 0; de < 1100; de++) { + { + auto h = mHistogramADCamplitudeDE.find(de); + if ((h != mHistogramADCamplitudeDE.end()) && (h->second != NULL)) { + h->second->Write(); + } + } + for (int i = 0; i < 2; i++) { + { + auto h = mHistogramNhitsDE[i].find(de); + if ((h != mHistogramNhitsDE[i].end()) && (h->second != NULL)) { + h->second->Write(); + } + } + { + auto h = mHistogramNorbitsDE[i].find(de); + if ((h != mHistogramNorbitsDE[i].end()) && (h->second != NULL)) { + h->second->Write(); + } + } + { + auto h = mHistogramOccupancyXY[i].find(de); + if ((h != mHistogramOccupancyXY[i].end()) && (h->second != NULL)) { + h->second->Write(); + } + } + } + } + + mMeanOccupancyPerDE->Write(); + mMeanOccupancyPerDECycle->Write(); + + mHistogramOrbits[0]->Write(); + mHistogramOccupancy[0]->Write(); + + f.Close(); +#endif +} + +void PhysicsTaskDigits::reset() +{ + // clean all the monitor objects here + + QcInfoLogger::GetInstance() << "Reseting the histogram" << AliceO2::InfoLogger::InfoLogger::endm; +} + +} // namespace muonchambers +} // namespace quality_control_modules +} // namespace o2 diff --git a/Modules/MUON/MCH/src/PhysicsTaskPreclusters.cxx b/Modules/MUON/MCH/src/PhysicsTaskPreclusters.cxx new file mode 100644 index 0000000000..dc9f8312fe --- /dev/null +++ b/Modules/MUON/MCH/src/PhysicsTaskPreclusters.cxx @@ -0,0 +1,502 @@ +/// +/// \file PhysicsTaskPreclusters.cxx +/// \author Barthelemy von Haller +/// \author Piotr Konopka +/// \author Andrea Ferrero +/// \author Sebastien Perrin +/// + +#include +#include +#include +#include +#include +#include + +#include "MCH/PhysicsTaskPreclusters.h" +#ifdef MCH_HAS_MAPPING_FACTORY +#include "MCHMappingFactory/CreateSegmentation.h" +#endif +#include "MCHMappingInterface/Segmentation.h" +#include "MCHMappingInterface/CathodeSegmentation.h" +#include "MCHMappingSegContour/CathodeSegmentationContours.h" +#include "MCHRawDecoder/PageDecoder.h" +#include "QualityControl/QcInfoLogger.h" + +using namespace std; +using namespace o2::mch::raw; +using namespace o2::quality_control::core; + +// #define QC_MCH_SAVE_TEMP_ROOTFILE 1 + +namespace o2 +{ +namespace quality_control_modules +{ +namespace muonchambers +{ +PhysicsTaskPreclusters::PhysicsTaskPreclusters() : TaskInterface() {} + +PhysicsTaskPreclusters::~PhysicsTaskPreclusters() {} + +void PhysicsTaskPreclusters::initialize(o2::framework::InitContext& /*ctx*/) +{ + QcInfoLogger::GetInstance() << "initialize PhysicsTaskPreclusters" << AliceO2::InfoLogger::InfoLogger::endm; + + for (int de = 0; de < 1100; de++) { + MeanPseudoeffDE[de] = MeanPseudoeffDECycle[de] = LastPreclBNBDE[de] = NewPreclBNBDE[de] = LastPreclNumDE[de] = NewPreclNumDE[de] = 0; + } + + // 1D histograms for mean pseudoeff per DE (integrated or per elapsed cycle) - Used in trending + mMeanPseudoeffPerDE = new TH1F("QcMuonChambers_MeanPseudoeff", "Mean Pseudoeff of each DE", 1100, -0.5, 1099.5); + getObjectsManager()->startPublishing(mMeanPseudoeffPerDE); + mMeanPseudoeffPerDECycle = new TH1F("QcMuonChambers_MeanPseudoeff_OnCycle", "Mean Pseudoeff of each DE during the cycle", 1100, -0.5, 1099.5); + getObjectsManager()->startPublishing(mMeanPseudoeffPerDECycle); + + for (auto de : o2::mch::raw::deIdsForAllMCH) { + + TH1F* h = new TH1F(TString::Format("QcMuonChambers_Cluster_Charge_DE%03d", de), + TString::Format("QcMuonChambers - cluster charge (DE%03d)", de), 1000, 0, 50000); + mHistogramClchgDE.insert(make_pair(de, h)); + h = new TH1F(TString::Format("QcMuonChambers_Cluster_Charge_OnCycle_DE%03d", de), + TString::Format("QcMuonChambers - cluster charge on cycle (DE%03d)", de), 1000, 0, 50000); + mHistogramClchgDEOnCycle.insert(make_pair(de, h)); + + float Xsize = 40 * 5; + float Xsize2 = Xsize / 2; + float Ysize = 50; + float Ysize2 = Ysize / 2; + float scale = 0.5; + + // Histograms using the XY Mapping + + { + TH2F* hXY = new TH2F(TString::Format("QcMuonChambers_Preclusters_Number_XY_%03d", de), + TString::Format("QcMuonChambers - Preclusters Number XY (DE%03d B)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPreclustersXY[0].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Preclusters_B_XY_%03d", de), + TString::Format("QcMuonChambers - Preclusters XY (DE%03d B)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPreclustersXY[1].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Preclusters_NB_XY_%03d", de), + TString::Format("QcMuonChambers - Preclusters XY (DE%03d NB)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPreclustersXY[2].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Preclusters_BNB_XY_%03d", de), + TString::Format("QcMuonChambers - Preclusters XY (DE%03d B+NB)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPreclustersXY[3].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Pseudoeff_B_XY_%03d", de), + TString::Format("QcMuonChambers - Pseudo-efficiency XY (DE%03d B)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPseudoeffXY[0].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Pseudoeff_NB_XY_%03d", de), + TString::Format("QcMuonChambers - Pseudo-efficiency XY (DE%03d NB)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPseudoeffXY[1].insert(make_pair(de, hXY)); + hXY = new TH2F(TString::Format("QcMuonChambers_Pseudoeff_BNB_XY_%03d", de), + TString::Format("QcMuonChambers - Pseudo-efficiency XY (DE%03d B+NB)", de), Xsize / scale, -Xsize2, Xsize2, Ysize / scale, -Ysize2, Ysize2); + mHistogramPseudoeffXY[2].insert(make_pair(de, hXY)); + } + } + + mHistogramPseudoeff[0] = new GlobalHistogram("QcMuonChambers_Pseudoeff_den", "Pseudo-efficiency cluster total count"); + mHistogramPseudoeff[0]->init(); + mHistogramPseudoeff[0]->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramPseudoeff[0]); + mHistogramPseudoeff[1] = new GlobalHistogram("QcMuonChambers_Pseudoeff", "Pseudo-efficiency - Clusters on B or NB"); + mHistogramPseudoeff[1]->init(); + mHistogramPseudoeff[1]->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramPseudoeff[1]); + mHistogramPseudoeff[2] = new GlobalHistogram("QcMuonChambers_Pseudoeff_BNB", "Pseudo-efficiency - Clusters on B and NB"); + mHistogramPseudoeff[2]->init(); + mHistogramPseudoeff[2]->SetOption("colz"); + getObjectsManager()->startPublishing(mHistogramPseudoeff[2]); +} + +void PhysicsTaskPreclusters::startOfActivity(Activity& /*activity*/) +{ + QcInfoLogger::GetInstance() << "startOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; +} + +void PhysicsTaskPreclusters::startOfCycle() +{ + QcInfoLogger::GetInstance() << "startOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; +} + +void PhysicsTaskPreclusters::monitorData(o2::framework::ProcessingContext& ctx) +{ + // get the input preclusters and associated digits + auto preClusters = ctx.inputs().get>("preclusters"); + auto digits = ctx.inputs().get>("preclusterdigits"); + + bool print = false; + for (auto& p : preClusters) { + if (!plotPrecluster(p, digits)) { + print = true; + } + } + + if (print) { + printPreclusters(preClusters, digits); + } +} + +//_________________________________________________________________________________________________ +// compute the center-of-gravity of a given pre-cluster +static void CoG(gsl::span precluster, double& Xcog, double& Ycog, bool isWide[2]) +{ + + double xmin = 1E9; + double ymin = 1E9; + double xmax = -1E9; + double ymax = -1E9; + double charge[] = { 0.0, 0.0 }; + int multiplicity[] = { 0, 0 }; + double padXPos[] = { 0, 0 }; + double padYPos[] = { 0, 0 }; + isWide[0] = isWide[1] = false; + // isWide tells if a given precluster is extended enough on a given cathode. On the bending side for exemple, a wide precluster would have at least 2 pads fired in the x direction (so when clustering it, we obtain a meaningful value for x). If a precluster is not wide and on a single cathode, when clustering, one of the coordinates will not be computed properly and set to the center of the pad by default. + + double x[] = { 0.0, 0.0 }; + double y[] = { 0.0, 0.0 }; + + double xsize[] = { 0.0, 0.0 }; + double ysize[] = { 0.0, 0.0 }; + + int detid = precluster[0].getDetID(); + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(detid); + + for (ssize_t i = 0; i < precluster.size(); ++i) { + const o2::mch::Digit& digit = precluster[i]; + int padid = digit.getPadID(); + + // position and size of current pad + double padPosition[2] = { segment.padPositionX(padid), segment.padPositionY(padid) }; + double padSize[2] = { segment.padSizeX(padid), segment.padSizeY(padid) }; + + // update of xmin/max et ymin/max + xmin = std::min(padPosition[0] - 0.5 * padSize[0], xmin); + xmax = std::max(padPosition[0] + 0.5 * padSize[0], xmax); + ymin = std::min(padPosition[1] - 0.5 * padSize[1], ymin); + ymax = std::max(padPosition[1] + 0.5 * padSize[1], ymax); + + // cathode index + int cathode = segment.isBendingPad(padid) ? 0 : 1; + + // update of the cluster position, size, charge and multiplicity + x[cathode] += padPosition[0] * digit.getADC(); + y[cathode] += padPosition[1] * digit.getADC(); + xsize[cathode] += padSize[0]; + ysize[cathode] += padSize[1]; + charge[cathode] += digit.getADC(); + + if (multiplicity[cathode] == 0) { + if (cathode == 0) { + padXPos[0] = padPosition[0]; + padYPos[0] = padPosition[1]; + } + if (cathode == 1) { + padXPos[1] = padPosition[0]; + padYPos[1] = padPosition[1]; + } + } else if (multiplicity[cathode] > 0) { + if ((cathode == 0) && (padXPos[0] != padPosition[0])) { + isWide[0] = true; + } + if ((cathode == 1) && (padYPos[1] != padPosition[1])) { + isWide[1] = true; + } + } + + multiplicity[cathode] += 1; + } + + // Computation of the CoG coordinates for the two cathodes + for (int cathode = 0; cathode < 2; ++cathode) { + if (charge[cathode] != 0) { + x[cathode] /= charge[cathode]; + y[cathode] /= charge[cathode]; + } + if (multiplicity[cathode] != 0) { + double sqrtCharge = sqrt(charge[cathode]); + xsize[cathode] /= (multiplicity[cathode] * sqrtCharge); + ysize[cathode] /= (multiplicity[cathode] * sqrtCharge); + } else { + xsize[cathode] = 1E9; + ysize[cathode] = 1E9; + } + } + + // each CoG coordinate is taken from the cathode with the best precision + Xcog = (xsize[0] < xsize[1]) ? x[0] : x[1]; + Ycog = (ysize[0] < ysize[1]) ? y[0] : y[1]; +} + +//_________________________________________________________________________________________________ +bool PhysicsTaskPreclusters::plotPrecluster(const o2::mch::PreCluster& preCluster, gsl::span digits) +{ + // filter out single-pad clusters + if (preCluster.nDigits < 2) { + return true; + } + + // get the digits of this precluster + auto preClusterDigits = digits.subspan(preCluster.firstDigit, preCluster.nDigits); + + bool cathode[2] = { false, false }; + float chargeSum[2] = { 0, 0 }; + float chargeMax[2] = { 0, 0 }; + + int detid = preClusterDigits[0].getDetID(); + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(detid); + + for (ssize_t i = 0; i < preClusterDigits.size(); ++i) { + const o2::mch::Digit& digit = preClusterDigits[i]; + int padid = digit.getPadID(); + + // cathode index + int cid = segment.isBendingPad(padid) ? 0 : 1; + cathode[cid] = true; + chargeSum[cid] += digit.getADC(); + + if (digit.getADC() > chargeMax[cid]) { + chargeMax[cid] = digit.getADC(); + } + } + + float chargeTot = chargeSum[0] + chargeSum[1]; + auto hCharge = mHistogramClchgDE.find(detid); + if ((hCharge != mHistogramClchgDE.end()) && (hCharge->second != NULL)) { + hCharge->second->Fill(chargeTot); + } + auto hChargeOnCycle = mHistogramClchgDEOnCycle.find(detid); + if ((hChargeOnCycle != mHistogramClchgDEOnCycle.end()) && (hChargeOnCycle->second != NULL)) { + hChargeOnCycle->second->Fill(chargeTot); + } + + // filter out clusters with small charge, which are likely to be noise + // and should not be used for estimating the pseudo-efficiency + if ((chargeMax[0] < 100) && (chargeMax[1] < 100)) { + return true; + } + + double Xcog, Ycog; + bool isWide[2]; + CoG(preClusterDigits, Xcog, Ycog, isWide); + + // Filling histograms to be used for Pseudo-efficiency computation + + // All meaningful preclusters (the breakdown is done in the histograms below) + if ((cathode[0] && isWide[0]) || (cathode[1] && isWide[1]) || (cathode[0] && cathode[1])) { + auto hXY0 = mHistogramPreclustersXY[0].find(detid); + if ((hXY0 != mHistogramPreclustersXY[0].end()) && (hXY0->second != NULL)) { + hXY0->second->Fill(Xcog, Ycog); + } + } + + // Wide clusters on bending side (because mono-cathode preclusters need to be wide to have a meaningful position in both x and y) + if (cathode[0] && isWide[0]) { + auto hXY1 = mHistogramPreclustersXY[1].find(detid); + if ((hXY1 != mHistogramPreclustersXY[1].end()) && (hXY1->second != NULL)) { + hXY1->second->Fill(Xcog, Ycog); + } + } + // Similarly on non-bending + if (cathode[1] && isWide[1]) { + auto hXY1 = mHistogramPreclustersXY[2].find(detid); + if ((hXY1 != mHistogramPreclustersXY[2].end()) && (hXY1->second != NULL)) { + hXY1->second->Fill(Xcog, Ycog); + } + } + // Clusters on both bending and non-bending (no need to require them to be wide because having both cathodes fired is sufficient to give x and y with enough precision) + if (cathode[0] && cathode[1]) { + auto hXY1 = mHistogramPreclustersXY[3].find(detid); + if ((hXY1 != mHistogramPreclustersXY[3].end()) && (hXY1->second != NULL)) { + hXY1->second->Fill(Xcog, Ycog); + } + } + + return (cathode[0] && cathode[1]); +} + +//_________________________________________________________________________________________________ +void PhysicsTaskPreclusters::printPreclusters(gsl::span preClusters, gsl::span digits) +{ + for (auto& preCluster : preClusters) { + // get the digits of this precluster + auto preClusterDigits = digits.subspan(preCluster.firstDigit, preCluster.nDigits); + + float chargeSum[2] = { 0, 0 }; + float chargeMax[2] = { 0, 0 }; + + int detid = preClusterDigits[0].getDetID(); + const o2::mch::mapping::Segmentation& segment = o2::mch::mapping::segmentation(detid); + + for (ssize_t i = 0; i < preClusterDigits.size(); ++i) { + const o2::mch::Digit& digit = preClusterDigits[i]; + int padid = digit.getPadID(); + + // cathode index + int cid = segment.isBendingPad(padid) ? 0 : 1; + chargeSum[cid] += digit.getADC(); + + if (digit.getADC() > chargeMax[cid]) { + chargeMax[cid] = digit.getADC(); + } + } + + double Xcog, Ycog; + bool isWide[2]; + CoG(preClusterDigits, Xcog, Ycog, isWide); + + QcInfoLogger::GetInstance() << "[pre-cluster] charge = " << chargeSum[0] << " " << chargeSum[1] << " CoG = " << Xcog << " " << AliceO2::InfoLogger::InfoLogger::endm; + for (auto& d : preClusterDigits) { + float X = segment.padPositionX(d.getPadID()); + float Y = segment.padPositionY(d.getPadID()); + bool bend = !segment.isBendingPad(d.getPadID()); + QcInfoLogger::GetInstance() << fmt::format(" DE {:4d} PAD {:5d} ADC {:6d} TIME ({} {} {:4d})", + d.getDetID(), d.getPadID(), d.getADC(), d.getTime().orbit, d.getTime().bunchCrossing, d.getTime().sampaTime) + << "\n" + << fmt::format(" CATHODE {} PAD_XY {:+2.2f} , {:+2.2f}", (int)bend, X, Y) << AliceO2::InfoLogger::InfoLogger::endm; + } + } +} + +void PhysicsTaskPreclusters::endOfCycle() +{ + QcInfoLogger::GetInstance() << "endOfCycle" << AliceO2::InfoLogger::InfoLogger::endm; + for (int de = 100; de <= 1030; de++) { + for (int i = 0; i < 3; i++) { + auto ih = mHistogramPreclustersXY[i + 1].find(de); + if (ih == mHistogramPreclustersXY[i + 1].end()) { + continue; + } + // Getting the histogram with the clusters positions exists (either on B, NB, or B and NB) + TH2F* hB = ih->second; + if (!hB) { + continue; + } + + // Getting the histogram with all the preclusters (denominator of pseudo-efficiency) + ih = mHistogramPreclustersXY[0].find(de); + if (ih == mHistogramPreclustersXY[0].end()) { + continue; + } + TH2F* hAll = ih->second; + if (!hAll) { + continue; + } + + // Checking the Histograms where Pseudo-efficiency should be stored and resetting them + ih = mHistogramPseudoeffXY[i].find(de); + if (ih == mHistogramPseudoeffXY[i].end()) { + continue; + } + TH2F* hEff = ih->second; + if (!hEff) { + continue; + } + + // Computing the Pseudo-efficiency by dividing the distrobution of clusters (either on B, NB, or B and NB) by the total distribution of all clusters. + hEff->Reset(); + hEff->Add(hB); + hEff->Divide(hAll); + } + } + + // Same procedure but in GlobalHistograms + mHistogramPseudoeff[0]->add(mHistogramPreclustersXY[0], mHistogramPreclustersXY[0]); + mHistogramPseudoeff[1]->add(mHistogramPreclustersXY[1], mHistogramPreclustersXY[2]); + mHistogramPseudoeff[1]->Divide(mHistogramPseudoeff[0]); + mHistogramPseudoeff[2]->add(mHistogramPreclustersXY[3], mHistogramPreclustersXY[3]); + mHistogramPseudoeff[2]->Divide(mHistogramPseudoeff[0]); + + // Using PseudoeffXY to get the mean pseudoeff per DE on last cycle + // By counting how many preclusters have been seen in total compared to how many have been seen on B and NB, on each DE + auto hMean = mMeanPseudoeffPerDE; + auto hMeanCycle = mMeanPseudoeffPerDECycle; + + for (int de = 0; de < 1100; de++) { + auto hnum = mHistogramPreclustersXY[0].find(de); + auto hBNB = mHistogramPreclustersXY[3].find(de); + if ((hBNB != mHistogramPreclustersXY[3].end()) && (hBNB->second != NULL) && (hnum != mHistogramPreclustersXY[0].end()) && (hnum->second != NULL)) { + NewPreclBNBDE[de] = 0; + NewPreclNumDE[de] = 0; + for (int binx = 1; binx < hBNB->second->GetXaxis()->GetNbins() + 1; binx++) { + for (int biny = 1; biny < hBNB->second->GetYaxis()->GetNbins() + 1; biny++) { + NewPreclBNBDE[de] += hBNB->second->GetBinContent(binx, biny); + } + } + for (int binx = 1; binx < hnum->second->GetXaxis()->GetNbins() + 1; binx++) { + for (int biny = 1; biny < hnum->second->GetYaxis()->GetNbins() + 1; biny++) { + NewPreclNumDE[de] += hnum->second->GetBinContent(binx, biny); + } + } + } + } + for (int i = 0; i < 1100; i++) { + MeanPseudoeffDE[i] = 0; + MeanPseudoeffDECycle[i] = 0; + if (NewPreclNumDE[i] > 0) { + MeanPseudoeffDE[i] = NewPreclBNBDE[i] / NewPreclNumDE[i]; + } + if ((NewPreclNumDE[i] - LastPreclNumDE[i]) > 0) { + MeanPseudoeffDECycle[i] = (NewPreclBNBDE[i] - LastPreclBNBDE[i]) / (NewPreclNumDE[i] - LastPreclNumDE[i]); + } + hMean->SetBinContent(i + 1, MeanPseudoeffDE[i]); + hMeanCycle->SetBinContent(i + 1, MeanPseudoeffDECycle[i]); + LastPreclBNBDE[i] = NewPreclBNBDE[i]; + LastPreclNumDE[i] = NewPreclNumDE[i]; + } +} + +void PhysicsTaskPreclusters::endOfActivity(Activity& /*activity*/) +{ + QcInfoLogger::GetInstance() << "endOfActivity" << AliceO2::InfoLogger::InfoLogger::endm; + +#ifdef QC_MCH_SAVE_TEMP_ROOTFILE + TFile f("/tmp/qc.root", "RECREATE"); + + { + auto hMean = mMeanPseudoeffPerDE; + auto hMeanCycle = mMeanPseudoeffPerDECycle; + hMean->Write(); + hMeanCycle->Write(); + } + + { + for (int i = 0; i < 4; i++) { + for (auto& h2 : mHistogramPreclustersXY[i]) { + if (h2.second != nullptr) { + h2.second->Write(); + } + } + } + for (auto& h : mHistogramClchgDE) { + if (h.second != nullptr) { + h.second->Write(); + } + } + for (auto& h : mHistogramClchgDEOnCycle) { + if (h.second != nullptr) { + h.second->Write(); + h.second->Reset(); + } + } + } + + mHistogramPseudoeff[0]->Write(); + mHistogramPseudoeff[1]->Write(); + mHistogramPseudoeff[2]->Write(); + + f.Close(); + +#endif +} + +void PhysicsTaskPreclusters::reset() +{ + // clean all the monitor objects here + + QcInfoLogger::GetInstance() << "Reseting the histogram" << AliceO2::InfoLogger::InfoLogger::endm; +} + +} // namespace muonchambers +} // namespace quality_control_modules +} // namespace o2 diff --git a/Modules/MUON/MCH/src/TH1MCHReductor.cxx b/Modules/MUON/MCH/src/TH1MCHReductor.cxx new file mode 100644 index 0000000000..6def5a0fd1 --- /dev/null +++ b/Modules/MUON/MCH/src/TH1MCHReductor.cxx @@ -0,0 +1,79 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TH1MCHReductor.cxx +/// \author Piotr Konopka, Sebastien Perrin +/// + +#include +#include "MCH/TH1MCHReductor.h" +#include +#include +#include +#include + +namespace o2::quality_control_modules::muonchambers +{ + +void* TH1MCHReductor::getBranchAddress() +{ + return &mStats; +} + +const char* TH1MCHReductor::getBranchLeafList() +{ + return "val500/D:val501:val502:val503:val504:val505:val506:val507:val508:val509:val510:val511:val512:val513:val514:val515:val516:val517:val600:val601:val602:val603:val604:val605:val606:val607:val608:val609:val610:val611:val612:val613:val614:val615:val616:val617:val700:val701:val702:val703:val704:val705:val706:val707:val708:val709:val710:val711:val712:val713:val714:val715:val716:val717:val718:val719:val720:val721:val722:val723:val724:val725:val800:val801:val802:val803:val804:val805:val806:val807:val808:val809:val810:val811:val812:val813:val814:val815:val816:val817:val818:val819:val820:val821:val822:val823:val824:val825:val900:val901:val902:val903:val904:val905:val906:val907:val908:val909:val910:val911:val912:val913:val914:val915:val916:val917:val918:val919:val920:val921:val922:val923:val924:val925:val1000:val1001:val1002:val1003:val1004:val1005:val1006:val1007:val1008:val1009:val1010:val1011:val1012:val1013:val1014:val1015:val1016:val1017:val1018:val1019:val1020:val1021:val1022:val1023:val1024:val1025:val5I:val5O:val6I:val6O:val7I:val7O:val8I:val8O:val9I:val9O:val10I:val10O:entries"; +} + +void TH1MCHReductor::update(TObject* obj) +{ + auto histo = dynamic_cast(obj); + if (!histo) + return; + + mStats.entries = histo->GetEntries(); + + // Get value from histo for each DE + int ivec[7] = { 0, 18, 36, 62, 88, 114, 140 }; + int deMin = 500; + for (int k = 0; k < 6; k++) { + for (int i = ivec[k]; i < ivec[k + 1]; i++) { + mStats.de_values.values[i] = histo->GetBinContent(deMin + (i - ivec[k]) + 1); + } + deMin += 100; + } + + // compute mean value within one half-chamber + auto computeMean = [&](gsl::span deIDs, int idx) { + double mean = 0; + for (int i : deIDs) { + mean += histo->GetBinContent(i + 1); + } + mean /= deIDs.size(); + mStats.halfch_values.values[idx] = mean; + }; + + int index = 0; + computeMean(detCH5I, index++); + computeMean(detCH5O, index++); + computeMean(detCH6I, index++); + computeMean(detCH6O, index++); + computeMean(detCH7I, index++); + computeMean(detCH7O, index++); + computeMean(detCH8I, index++); + computeMean(detCH8O, index++); + computeMean(detCH9I, index++); + computeMean(detCH9O, index++); + computeMean(detCH10I, index++); + computeMean(detCH10O, index++); +} + +} // namespace o2::quality_control_modules::muonchambers