Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Detectors/EMCAL/calibration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ o2_add_library(EMCALCalibration
src/PedestalCalibDevice.cxx
src/PedestalProcessorDevice.cxx
src/PedestalProcessorData.cxx
src/EMCALTempCalibExtractor.cxx
PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase
O2::EMCALCalib
O2::EMCALReconstruction
Expand All @@ -46,6 +47,7 @@ o2_target_root_dictionary(EMCALCalibration
include/EMCALCalibration/EMCDCSProcessor.h
include/EMCALCalibration/EMCALPedestalHelper.h
include/EMCALCalibration/PedestalProcessorData.h
include/EMCALCalibration/EMCALTempCalibExtractor.h
LINKDEF src/EMCALCalibrationLinkDef.h)

o2_add_executable(emcal-channel-calib-workflow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// 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.

/// \class EMCALTempCalibExtractor
/// \brief Calculate gain correction factors based on the temperature and the cell-by-cell temperature dependent correction factors (slope and intercept)
/// \author Joshua König
/// \ingroup EMCALCalib
/// \since June 30, 2025

#ifndef EMCALTEMPCALIBEXTRACTOR_H_
#define EMCALTEMPCALIBEXTRACTOR_H_

#include <algorithm>
#include <cmath>
#include <iostream>
#include "CCDB/BasicCCDBManager.h"
#include "EMCALCalib/ElmbData.h"
#include "EMCALCalib/TempCalibrationParams.h"
#include "EMCALBase/Geometry.h"

namespace o2
{
namespace emcal
{

class EMCALTempCalibExtractor
{

public:
/// \brief Constructor
EMCALTempCalibExtractor()
{
LOG(info) << "initialized EMCALTempCalibExtractor";
try {
// Try to access geometry initialized ountside
mGeometry = o2::emcal::Geometry::GetInstance();
} catch (o2::emcal::GeometryNotInitializedException& e) {
mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); // fallback option
}
};
/// \brief Destructor
~EMCALTempCalibExtractor() = default;

/// \brief Initialize temperature data and slope for each cell from the ccdb
/// \param path path to the slope data
/// \param timestamp timestamp for the ccdb objects or runnumber (will detect automatically if its a runnumber and convert it)
void InitializeFromCCDB(std::string path, uint64_t timestamp);

/// \brief get average temperature in a supermodule
/// \param iSM SM number
/// \param ElmbData object where temperature sensor values are stored
/// \return average temperature in a supermodule
float getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const;

/// \brief get gain calibration factor depending on the temperature and the slope of the cell
/// \param cellID cell ID
/// \return gain calibration factor
float getGainCalibFactor(const unsigned short cellID) const;

/// \brief set temperature range in which sensor ddata is assumed to be good
/// \param low lower temperature
/// \param high upper temperature
void setAcceptedEnergyRange(float low, float high);

/// \brief set if median (true) or mean (false) should be used for averaging of the temperature in a SM
void setUseMedian(const bool tmp) { mUseMedian = tmp; }

/// \brief get sensor IDs for a specific supermodule
/// \param iSM SM number
/// \return vector of sensor IDs
std::vector<unsigned short> getSensorsForSM(const unsigned short iSM) const;

private:
static constexpr unsigned short mNCells = 17664; ///< Number of EMCal cells
std::array<float, mNCells> mGainCalibFactors; ///< gain calibration factors that are calculated based on the temperature and the slopes for each cell
o2::emcal::Geometry* mGeometry; ///< pointer to the EMCal geometry
std::array<float, 2> mAcceptedTempRange = {15., 30.}; ///< Temperature range where sensors are believed to send good data. Temperatures outside this range will be rejected
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
};

} // namespace emcal

} // namespace o2

#endif
127 changes: 127 additions & 0 deletions Detectors/EMCAL/calibration/src/EMCALTempCalibExtractor.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// 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.

#include "EMCALCalibration/EMCALTempCalibExtractor.h"
#include "EMCALCalib/CalibDB.h"
#include "CCDB/CcdbApi.h"
#include "CCDB/BasicCCDBManager.h"
#include <numeric>

namespace o2
{
namespace emcal
{

void EMCALTempCalibExtractor::InitializeFromCCDB(std::string path, uint64_t timestamp)
{

auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance();
uint64_t maxRunNr = 1000000;
if (timestamp < maxRunNr) {
LOG(info) << "assuming input is run " << timestamp << " will convert it to timstamp";
auto [sor, eor] = ccdbMgr.getRunDuration(timestamp);
uint64_t sixtySec = 60000;
timestamp = eor - sixtySec; // safety margin of 1min at EOR
LOG(info) << "set timestamp to " << timestamp;
}

o2::emcal::CalibDB calibdb("http://alice-ccdb.cern.ch");
std::map<std::string, std::string> metadata;
auto tempSensorData = calibdb.readTemperatureSensorData(timestamp, metadata);

// also obtain cell dependent correction factors
TempCalibrationParams* params = ccdbMgr.getForTimeStamp<o2::emcal::TempCalibrationParams>(path, timestamp);

std::map<unsigned short, float> mapSMTemperature;
for (unsigned short i = 0; i < mNCells; ++i) {
const unsigned short iSM = mGeometry->GetSuperModuleNumber(i);
if (mapSMTemperature.count(iSM) == 0) {
mapSMTemperature[iSM] = getTemperatureForSM(iSM, tempSensorData);
}
float corrFac = params->getTempCalibParamA0(i) + params->getTempCalibParamSlope(i) * mapSMTemperature[iSM];
mGainCalibFactors[i] = corrFac;
}
}

float EMCALTempCalibExtractor::getTemperatureForSM(const unsigned short iSM, o2::emcal::ElmbData* ElmbData) const
{
if (iSM < 0 || iSM > 20) {
LOG(error) << "SM " << iSM << "does not exist!"; // could be replaced with a proper exception
return 0.;
}
std::vector<unsigned short> vecSensorID = getSensorsForSM(iSM);

// Obtain temperature for these sensors
std::vector<float> vecTemperature;
for (const auto& iSensor : vecSensorID) {
float temp = ElmbData->getMean(iSensor);
if (temp < mAcceptedTempRange[0] || temp > mAcceptedTempRange[1]) {
continue;
}
vecTemperature.push_back(temp);
}

const unsigned int nEntries = vecTemperature.size();
if (nEntries == 0) {
LOG(warning) << "No sensor data between " << mAcceptedTempRange[0] << " and " << mAcceptedTempRange[1] << "degree found... for SM " << iSM << " Setting to default 20 degree";
return 20.; //
}

// get median energy
float tempSM = 0.;
if (mUseMedian) {
std::sort(vecTemperature.begin(), vecTemperature.end());
if (nEntries % 2 == 0) {
// even number of elements: average the two middle ones
tempSM = (vecTemperature[nEntries / 2 - 1] + vecTemperature[nEntries / 2]) / 2.0;
} else {
// odd number of elements: return the middle one
tempSM = vecTemperature[nEntries / 2];
}
} else { // use Mean temperature
float sum = std::accumulate(vecTemperature.begin(), vecTemperature.end(), 0.0);
tempSM = sum / vecTemperature.size();
}
return tempSM;
}

float EMCALTempCalibExtractor::getGainCalibFactor(const unsigned short cellID) const
{
if (cellID >= mNCells) {
LOG(error) << "cell ID" << cellID << " does not exist";
return 1.;
}
return mGainCalibFactors[cellID];
}

std::vector<unsigned short> EMCALTempCalibExtractor::getSensorsForSM(const unsigned short iSM) const
{
unsigned short nSensors = 8;
if (iSM == 10 || iSM == 11 || iSM == 19 || iSM == 20) {
nSensors = 4;
}

std::vector<unsigned short> vecSensorID;
for (unsigned short iELMBSensor = iSM * 8; iELMBSensor < iSM * 8 + nSensors; iELMBSensor++) {
vecSensorID.push_back(iELMBSensor);
}
return vecSensorID;
}

void EMCALTempCalibExtractor::setAcceptedEnergyRange(float low, float high)
{
mAcceptedTempRange[0] = low;
mAcceptedTempRange[1] = high;
}

} // namespace emcal

} // namespace o2