|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | + |
| 12 | +/// \file CommonModeCorrection.h |
| 13 | +/// \brief Calculate the common mode correction factor |
| 14 | +/// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de |
| 15 | + |
| 16 | +#ifndef AliceO2_TPC_CommonModeCorrection_H_ |
| 17 | +#define AliceO2_TPC_CommonModeCorrection_H_ |
| 18 | + |
| 19 | +#include <gsl/span> |
| 20 | +#include <string_view> |
| 21 | +#include <vector> |
| 22 | + |
| 23 | +#include "DataFormatsTPC/Digit.h" |
| 24 | +#include "TPCBase/FEEConfig.h" |
| 25 | + |
| 26 | +namespace o2::tpc |
| 27 | +{ |
| 28 | + |
| 29 | +/// Class to calculate the common mode correction |
| 30 | +/// |
| 31 | +/// Calculation of the common mode correction, based on the algorithm propsed by Marian Ivanov |
| 32 | +/// The calculation is done for one single CRU and time bin |
| 33 | +class CommonModeCorrection |
| 34 | +{ |
| 35 | + public: |
| 36 | + struct CMdata { |
| 37 | + std::vector<float> adcValues; |
| 38 | + std::vector<float> cmKValues; |
| 39 | + std::vector<float> pedestals; |
| 40 | + |
| 41 | + void resize(size_t newSize) |
| 42 | + { |
| 43 | + adcValues.resize(newSize); |
| 44 | + cmKValues.resize(newSize); |
| 45 | + pedestals.resize(newSize); |
| 46 | + } |
| 47 | + |
| 48 | + void clear() |
| 49 | + { |
| 50 | + adcValues.clear(); |
| 51 | + cmKValues.clear(); |
| 52 | + pedestals.clear(); |
| 53 | + } |
| 54 | + }; |
| 55 | + |
| 56 | + struct CMInfo { |
| 57 | + float cmValue{}; ///< common mode value from pseudo code |
| 58 | + float cmValueStd{}; ///< std dev of common mode values from pseudo code |
| 59 | + float cmValueCRU{}; ///< common mode value from firmware, if available |
| 60 | + float sumPos{}; ///< sum of positive signals > mSumPosThreshold |
| 61 | + float sumNeg{}; ///< sum of negative signals <= mSumPosThreshold, corrected for k-factor |
| 62 | + uint16_t nPadsUsed{}; ///< number of pads used for CM calculation |
| 63 | + uint16_t nNeg{}; ///< number of pads used for sumNeg |
| 64 | + uint16_t nOccupancy{}; ///< number of CM corrected pads larger than mOccupancyThreshold |
| 65 | + uint16_t nSaturation{}; ///< number of pads in saturation |
| 66 | + }; |
| 67 | + |
| 68 | + struct CMDebug { |
| 69 | + std::vector<uint8_t> nPadsOk{}; |
| 70 | + std::vector<uint16_t> adcDist{}; |
| 71 | + }; |
| 72 | + |
| 73 | + using CalPadMapType = std::unordered_map<std::string, CalPad>; |
| 74 | + |
| 75 | + /// Calculation of the common mode value |
| 76 | + /// |
| 77 | + /// \param value pad-by-pad charge values |
| 78 | + /// \param cmKValues corresponding pad-by-pad common mode k-factors |
| 79 | + /// \param pedestals corresponding pad-by-pad pedestals |
| 80 | + /// \param |
| 81 | + CMInfo getCommonMode(gsl::span<const float> values, gsl::span<const float> cmKValues, gsl::span<const float> pedestals, CMDebug* cmDebug = nullptr) const; |
| 82 | + CMInfo getCommonMode(const std::vector<float>& values, const std::vector<float>& cmKValues, const std::vector<float>& pedestals) const { return getCommonMode(gsl::span(values), gsl::span(cmKValues), gsl::span(pedestals)); } |
| 83 | + |
| 84 | + CMInfo getCommonMode(const CMdata& cmData) const { return getCommonMode(std::span(cmData.adcValues), std::span(cmData.cmKValues), std::span(cmData.pedestals)); } |
| 85 | + |
| 86 | + void setNPadsCompRandom(int n) { mNPadsCompRamdom = n; } |
| 87 | + int getNPadsCompRandom() const { return mNPadsCompRamdom; } |
| 88 | + |
| 89 | + void setNPadsCompMin(int n) { mNPadsCompMin = n; } |
| 90 | + int getNPadsCompMin() const { return mNPadsCompMin; } |
| 91 | + |
| 92 | + /// Minimum number of pads required in the CM calculation to be used for digit correction |
| 93 | + void setNPadsMinCM(int n) { mNPadsMinCM = n; } |
| 94 | + int getNPadsMinCM() const { return mNPadsMinCM; } |
| 95 | + |
| 96 | + void setQEmpty(float q) { mQEmpty = q; } |
| 97 | + float getQEmpty() const { return mQEmpty; } |
| 98 | + |
| 99 | + void setQComp(float q) { mQComp = q; } |
| 100 | + float getQComp() const { return mQComp; } |
| 101 | + |
| 102 | + /// The mQComp will be set to (cm - mQCompScaleThreshold) * mQCompScale, if cm > mQCompScaleThreshold |
| 103 | + void setQCompScaleThreshold(float q) { mQCompScaleThreshold = q; } |
| 104 | + float getQCompScaleThreshold() const { return mQCompScaleThreshold; } |
| 105 | + |
| 106 | + /// The mQComp will be set to (cm - mQCompScaleThreshold) * mQCompScale, if cm > mQCompScaleThreshold |
| 107 | + void setQCompScale(float q) { mQCompScale = q; } |
| 108 | + float getQCompScale() const { return mQCompScale; } |
| 109 | + |
| 110 | + /// Threshold above which a signal is considered for sumPos, if debug information is used |
| 111 | + void setSumPosThreshold(float threshold) { mSumPosThreshold = threshold; } |
| 112 | + float getSumPosThreshold() const { return mSumPosThreshold; } |
| 113 | + |
| 114 | + /// Threshold above which a signal is considered for the occupancy |
| 115 | + void setOccupancyThreshold(float threshold) { mOccupancyThreshold = threshold; } |
| 116 | + float getOccupancyThreshold() const { return mOccupancyThreshold; } |
| 117 | + |
| 118 | + /// Pad maps loaded from FEEConfig |
| 119 | + void setPadMaps(CalPadMapType& padMaps) { mPadMaps = padMaps; } |
| 120 | + |
| 121 | + /// load a CalPad from file and add it to the local mPadMaps |
| 122 | + /// \param fileName input file name |
| 123 | + /// \param nameInFile name of the CalPad object in the file |
| 124 | + /// \param namePadMap name under which to store the object in the mPadMaps, if empty use the same as nameInFile |
| 125 | + void loadCalPad(std::string_view fileName, std::string_view nameInFile, std::string_view namePadMap = ""); |
| 126 | + |
| 127 | + /// load CMkValues from file, assuming it is stored under the name "CMkValues |
| 128 | + void loadCMkValues(std::string_view fileName) { loadCalPad(fileName, "CMkValues"); } |
| 129 | + |
| 130 | + /// load Pedestals from file, assuming it is stored under the name "Pedestals |
| 131 | + void loadPedestals(std::string_view fileName) { loadCalPad(fileName, "Pedestals"); } |
| 132 | + |
| 133 | + /// Custom setting of CalPad, overwriting what was set in mPadMaps |
| 134 | + void setCalPad(const CalPad& calPad, std::string_view name) { mPadMaps[name.data()] = calPad; } |
| 135 | + |
| 136 | + /// cmk value |
| 137 | + float getCMkValue(int sector, int row, int pad) { return mPadMaps["CMkValues"].getValue(sector, row, pad); } |
| 138 | + |
| 139 | + /// pedestal value |
| 140 | + float getPedestalValue(int sector, int row, int pad) { return mPadMaps["Pedestals"].getValue(sector, row, pad); } |
| 141 | + |
| 142 | + /// load the Pad maps from CCDB |
| 143 | + void |
| 144 | + loadDefaultPadMaps(FEEConfig::Tags feeTag = FEEConfig::Tags::Physics30sigma); |
| 145 | + |
| 146 | + CMdata collectCMdata(const std::vector<Digit>& digits, int cru, int timeBin); |
| 147 | + |
| 148 | + int getCommonMode(std::vector<Digit>& digits, std::vector<std::vector<CMInfo>>& cmValues, bool negativeOnly = false, bool hasInjectedCMValue = false, std::vector<std::vector<CMDebug>>* cmDebug = nullptr, int minTimeBin = -1, int maxTimeBin = -1) const; |
| 149 | + |
| 150 | + /// corret digits for common mode |
| 151 | + /// \param cmValues will contain CM information for each CRU and time bin |
| 152 | + /// \param negativeOnly only correct negative common mode signals |
| 153 | + /// \return maximum |
| 154 | + int correctDigits(std::vector<Digit>& digits, std::vector<std::vector<CMInfo>>& cmValues, bool negativeOnly = false, bool hasInjectedCMValue = false, std::vector<std::vector<CMDebug>>* cmDebug = nullptr, int minTimeBin = -1, int maxTimeBin = -1) const; |
| 155 | + |
| 156 | + void correctDigits(std::string_view digiFileIn, Long64_t maxEntries = -1, std::string_view digitFileOut = "tpcdigit_cmcorr.root", std::string_view cmFileOut = "CommonModeValues.root", bool negativeOnly = false, int nThreads = 1, bool writeOnlyCM = false, bool writeDebug = false, bool hasInjectedCMValue = false, int minTimeBin = -1, int maxTimeBin = -1); |
| 157 | + |
| 158 | + void limitKFactorPrecision(bool limit = true) { mLimitKFactor = limit; } |
| 159 | + void limitPedestalPrecision(bool limit = true) { mLimitPedestal = limit; } |
| 160 | + |
| 161 | + /// set the number of threads used for CM calculation |
| 162 | + /// \param nThreads number of threads |
| 163 | + static void setNThreads(const int nThreads) { sNThreads = nThreads; } |
| 164 | + |
| 165 | + /// \return returns the number of threads used for decoding |
| 166 | + static int getNThreads() { return sNThreads; } |
| 167 | + |
| 168 | + /// add artificial common mode, only works when using the 'correctDigits' function |
| 169 | + void addCommonMode(float cm) { mArtificialCM = cm; } |
| 170 | + |
| 171 | + void setCorrectOutputForPedestal(bool corret = true) { mCorrectOutputForPedestal = corret; } |
| 172 | + bool getCorrectOutputForPedestal() const { return mCorrectOutputForPedestal; } |
| 173 | + |
| 174 | + /// Add zeros for pads without signal |
| 175 | + void setAddSubthreshold(bool addSubthreshold) { mSubthreshold = addSubthreshold; } |
| 176 | + bool getAddSubthreshold() const { return mSubthreshold; } |
| 177 | + |
| 178 | + static float decodeInjectedCMValue(float lower, float upper); |
| 179 | + |
| 180 | + private: |
| 181 | + inline static int sNThreads{1}; ///< Number of parallel threads for the CM calculation |
| 182 | + int mNPadsCompRamdom{10}; ///< Number of random pads to compare with to check if the present pad is empty |
| 183 | + int mNPadsCompMin{7}; ///< Minimum number of neighbouring pads with q close to present pad to define this as empty |
| 184 | + int mNPadsMinCM{0}; ///< Minimum number of pads required in the CM calculation to be used for digit correction |
| 185 | + float mQEmpty{2}; ///< Threshold to enter check for empty pad |
| 186 | + float mQComp{1}; ///< Threshold for comparison with random pads |
| 187 | + float mQCompScaleThreshold{0}; ///< Charge threshold from which on to increase mQComp |
| 188 | + float mQCompScale{0}; ///< Slope with which to increase mQComp if below mQCompScaleThreshold |
| 189 | + float mSumPosThreshold{2}; ///< calculate sumPos > mSumPosThreshold, sumNeg M<= mSumPosThreshold |
| 190 | + float mOccupancyThreshold{3}; ///< calculate number of pads > mQCompScaleThreshold after CM correction |
| 191 | + bool mLimitKFactor{false}; ///< Limit the k-factor precision to 2I6F |
| 192 | + bool mLimitPedestal{false}; ///< Limit the preestal precision to 10I2F |
| 193 | + int mSubthreshold{0}; ///< Add data for pads without signal. 1 = add zeros; 2 = add random noise |
| 194 | + float mArtificialCM{}; ///< artificial common mode signals |
| 195 | + bool mCorrectOutputForPedestal{false}; ///< correct the writte out ADC for the pedestal value |
| 196 | + |
| 197 | + CalPadMapType mPadMaps; ///< Pad-by-pad CRU configuration values (Pedestal, Noise, ITF + CM parameters) |
| 198 | + |
| 199 | + struct pos { |
| 200 | + int row; |
| 201 | + int pad; |
| 202 | + }; |
| 203 | + |
| 204 | + // positions of lower words per CRU in sector |
| 205 | + const std::array<pos, 10> mCMInjectIDLower{ |
| 206 | + // row0 pad0 row1 pad1 |
| 207 | + pos{0, 2}, |
| 208 | + pos{20, 1}, |
| 209 | + pos{32, 2}, |
| 210 | + pos{51, 1}, |
| 211 | + pos{63, 1}, |
| 212 | + pos{84, 1}, |
| 213 | + pos{97, 1}, |
| 214 | + pos{116, 2}, |
| 215 | + pos{127, 2}, |
| 216 | + pos{142, 0}, |
| 217 | + }; |
| 218 | + |
| 219 | + // positions of upper words per CRU in sector |
| 220 | + const std::array<pos, 10> mCMInjectIDUpper{ |
| 221 | + // row0 pad0 row1 pad1 |
| 222 | + pos{0, 3}, |
| 223 | + pos{20, 3}, |
| 224 | + pos{32, 3}, |
| 225 | + pos{51, 3}, |
| 226 | + pos{63, 2}, |
| 227 | + pos{84, 4}, |
| 228 | + pos{97, 2}, |
| 229 | + pos{115, 5}, |
| 230 | + pos{127, 3}, |
| 231 | + pos{142, 4}, |
| 232 | + }; |
| 233 | + |
| 234 | + /// Return the value stored in mPadMaps["calibName"] |
| 235 | + /// \param calibName name of calibraion in mPadMaps |
| 236 | + /// \param cru CRU number |
| 237 | + /// \param pad Pad number within the CRU |
| 238 | + float getCalPadValue(const std::string calibName, int icru, int pad) const; |
| 239 | + |
| 240 | + bool padMapExists(const std::string& calibName); |
| 241 | + |
| 242 | + ClassDefNV(CommonModeCorrection, 2); |
| 243 | +}; |
| 244 | + |
| 245 | +} // namespace o2::tpc |
| 246 | +#endif |
0 commit comments