Skip to content

Commit ad44565

Browse files
jokonigsawenzel
authored andcommitted
[EMCAL-567] Add class to handle EMCal temperature calibration
- Gain of EMCal cell is temperature dependent. - The temperature is stored in the ccdb about every 3min for 8 sensors per SM - New class downloads temperature values from ccdb and averages them per SM - Per cell, the energy dependence was determined in run2. These values are stored in the ccdb and also read in at initializeFromCCDB - As the temperature values are accumulated per run, the end of run timestamp is taken - 60s of safety margin
1 parent eb67b94 commit ad44565

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

Detectors/EMCAL/calibration/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ o2_add_library(EMCALCalibration
2020
src/PedestalCalibDevice.cxx
2121
src/PedestalProcessorDevice.cxx
2222
src/PedestalProcessorData.cxx
23+
src/EMCALTempCalibExtractor.cxx
2324
PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase
2425
O2::EMCALCalib
2526
O2::EMCALReconstruction
@@ -46,6 +47,7 @@ o2_target_root_dictionary(EMCALCalibration
4647
include/EMCALCalibration/EMCDCSProcessor.h
4748
include/EMCALCalibration/EMCALPedestalHelper.h
4849
include/EMCALCalibration/PedestalProcessorData.h
50+
include/EMCALCalibration/EMCALTempCalibExtractor.h
4951
LINKDEF src/EMCALCalibrationLinkDef.h)
5052

5153
o2_add_executable(emcal-channel-calib-workflow
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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+
/// \class EMCALTempCalibExtractor
13+
/// \brief Calculate gain correction factors based on the temperature and the cell-by-cell temperature dependent correction factors (slope and intercept)
14+
/// \author Joshua König
15+
/// \ingroup EMCALCalib
16+
/// \since June 30, 2025
17+
18+
#ifndef EMCALTEMPCALIBEXTRACTOR_H_
19+
#define EMCALTEMPCALIBEXTRACTOR_H_
20+
21+
#include <algorithm>
22+
#include <cmath>
23+
#include <iostream>
24+
#include "CCDB/BasicCCDBManager.h"
25+
#include "EMCALCalib/ElmbData.h"
26+
#include "EMCALCalib/TempCalibrationParams.h"
27+
#include "EMCALBase/Geometry.h"
28+
29+
namespace o2
30+
{
31+
namespace emcal
32+
{
33+
34+
class EMCALTempCalibExtractor
35+
{
36+
37+
public:
38+
/// \brief Constructor
39+
EMCALTempCalibExtractor()
40+
{
41+
LOG(info) << "initialized EMCALTempCalibExtractor";
42+
try {
43+
// Try to access geometry initialized ountside
44+
mGeometry = o2::emcal::Geometry::GetInstance();
45+
} catch (o2::emcal::GeometryNotInitializedException& e) {
46+
mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // fallback option
47+
}
48+
};
49+
/// \brief Destructor
50+
~EMCALTempCalibExtractor() = default;
51+
52+
/// \brief Initialize temperature data and slope for each cell from the ccdb
53+
/// \param path path to the slope data
54+
/// \param timestamp timestamp for the ccdb objects or runnumber (will detect automatically if its a runnumber and convert it)
55+
void InitializeFromCCDB(std::string path, uint64_t timestamp);
56+
57+
/// \brief get average temperature in a supermodule
58+
/// \param iSM SM number
59+
/// \param ElmbData object where temperature sensor values are stored
60+
/// \return average temperature in a supermodule
61+
float getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const;
62+
63+
/// \brief get gain calibration factor depending on the temperature and the slope of the cell
64+
/// \param cellID cell ID
65+
/// \return gain calibration factor
66+
float getGainCalibFactor(const unsigned short cellID) const;
67+
68+
/// \brief set temperature range in which sensor ddata is assumed to be good
69+
/// \param low lower temperature
70+
/// \param high upper temperature
71+
void setAcceptedEnergyRange(float low, float high);
72+
73+
/// \brief set if median (true) or mean (false) should be used for averaging of the temperature in a SM
74+
void setUseMedian(const bool tmp) { mUseMedian = tmp; }
75+
76+
/// \brief get sensor IDs for a specific supermodule
77+
/// \param iSM SM number
78+
/// \return vector of sensor IDs
79+
std::vector<unsigned short> getSensorsForSM(const unsigned short iSM) const;
80+
81+
private:
82+
static constexpr unsigned short mNCells = 17664; ///< Number of EMCal cells
83+
std::array<float, mNCells> mGainCalibFactors; ///< gain calibration factors that are calculated based on the temperature and the slopes for each cell
84+
o2::emcal::Geometry* mGeometry; ///< pointer to the EMCal geometry
85+
std::array<float, 2> mAcceptedTempRange = {15., 30.}; ///< Temperature range where sensors are believed to send good data. Temperatures outside this range will be rejected
86+
bool mUseMedian = true; /// switch to decide if temperature within a SM should be calculated as the mean or the median of the individual sensor data
87+
};
88+
89+
} // namespace emcal
90+
91+
} // namespace o2
92+
93+
#endif
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
#include "EMCALCalibration/EMCALTempCalibExtractor.h"
13+
#include "EMCALCalib/CalibDB.h"
14+
#include "CCDB/CcdbApi.h"
15+
#include "CCDB/BasicCCDBManager.h"
16+
#include <numeric>
17+
18+
namespace o2
19+
{
20+
namespace emcal
21+
{
22+
23+
void EMCALTempCalibExtractor::InitializeFromCCDB(std::string path, uint64_t timestamp)
24+
{
25+
26+
auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance();
27+
uint64_t maxRunNr = 1000000;
28+
if (timestamp < maxRunNr) {
29+
LOG(info) << "assuming input is run " << timestamp << " will convert it to timstamp";
30+
auto [sor, eor] = ccdbMgr.getRunDuration(timestamp);
31+
uint64_t sixtySec = 60000;
32+
timestamp = eor - sixtySec; // safety margin of 1min at EOR
33+
LOG(info) << "set timestamp to " << timestamp;
34+
}
35+
36+
o2::emcal::CalibDB calibdb("http://alice-ccdb.cern.ch");
37+
std::map<std::string, std::string> metadata;
38+
auto tempSensorData = calibdb.readTemperatureSensorData(timestamp, metadata);
39+
40+
// also obtain cell dependent correction factors
41+
TempCalibrationParams* params = ccdbMgr.getForTimeStamp<o2::emcal::TempCalibrationParams>(path, timestamp);
42+
43+
std::map<unsigned short, float> mapSMTemperature;
44+
for (unsigned short i = 0; i < mNCells; ++i) {
45+
const unsigned short iSM = mGeometry->GetSuperModuleNumber(i);
46+
if (mapSMTemperature.count(iSM) == 0) {
47+
mapSMTemperature[iSM] = getTemperatureForSM(iSM, tempSensorData);
48+
}
49+
float corrFac = params->getTempCalibParamA0(i) + params->getTempCalibParamSlope(i) * mapSMTemperature[iSM];
50+
mGainCalibFactors[i] = corrFac;
51+
}
52+
}
53+
54+
float EMCALTempCalibExtractor::getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const
55+
{
56+
if (iSM < 0 || iSM > 20) {
57+
LOG(error) << "SM " << iSM << "does not exist!"; // could be replaced with a proper exception
58+
return 0.;
59+
}
60+
std::vector<unsigned short> vecSensorID = getSensorsForSM(iSM);
61+
62+
// Obtain temperature for these sensors
63+
std::vector<float> vecTemperature;
64+
for (const auto& iSensor : vecSensorID) {
65+
float temp = ElmbData->getMean(iSensor);
66+
if (temp < mAcceptedTempRange[0] || temp > mAcceptedTempRange[1]) {
67+
continue;
68+
}
69+
vecTemperature.push_back(temp);
70+
}
71+
72+
const unsigned int nEntries = vecTemperature.size();
73+
if (nEntries == 0) {
74+
LOG(warning) << "No sensor data between " << mAcceptedTempRange[0] << " and " << mAcceptedTempRange[1] << "degree found... for SM " << iSM << " Setting to default 20 degree";
75+
return 20.; //
76+
}
77+
78+
// get median energy
79+
float tempSM = 0.;
80+
if (mUseMedian) {
81+
std::sort(vecTemperature.begin(), vecTemperature.end());
82+
if (nEntries % 2 == 0) {
83+
// even number of elements: average the two middle ones
84+
tempSM = (vecTemperature[nEntries / 2 - 1] + vecTemperature[nEntries / 2]) / 2.0;
85+
} else {
86+
// odd number of elements: return the middle one
87+
tempSM = vecTemperature[nEntries / 2];
88+
}
89+
} else { // use Mean temperature
90+
float sum = std::accumulate(vecTemperature.begin(), vecTemperature.end(), 0.0);
91+
tempSM = sum / vecTemperature.size();
92+
}
93+
return tempSM;
94+
}
95+
96+
float EMCALTempCalibExtractor::getGainCalibFactor(const unsigned short cellID) const
97+
{
98+
if (cellID >= mNCells) {
99+
LOG(error) << "cell ID" << cellID << " does not exist";
100+
return 1.;
101+
}
102+
return mGainCalibFactors[cellID];
103+
}
104+
105+
std::vector<unsigned short> EMCALTempCalibExtractor::getSensorsForSM(const unsigned short iSM) const
106+
{
107+
unsigned short nSensors = 8;
108+
if (iSM == 10 || iSM == 11 || iSM == 19 || iSM == 20) {
109+
nSensors = 4;
110+
}
111+
112+
std::vector<unsigned short> vecSensorID;
113+
for (unsigned short iELMBSensor = iSM * 8; iELMBSensor < iSM * 8 + nSensors; iELMBSensor++) {
114+
vecSensorID.push_back(iELMBSensor);
115+
}
116+
return vecSensorID;
117+
}
118+
119+
void EMCALTempCalibExtractor::setAcceptedEnergyRange(float low, float high)
120+
{
121+
mAcceptedTempRange[0] = low;
122+
mAcceptedTempRange[1] = high;
123+
}
124+
125+
} // namespace emcal
126+
127+
} // namespace o2

0 commit comments

Comments
 (0)